summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp7
-rw-r--r--clang/lib/Parse/ParsePragma.cpp112
-rw-r--r--clang/lib/Parse/ParseStmt.cpp7
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp104
4 files changed, 124 insertions, 106 deletions
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index d75b97ddf6a..df30892e869 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -588,6 +588,7 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
continue;
LoopHintAttr::OptionType Option = LH->getOption();
+ LoopHintAttr::LoopHintState State = LH->getState();
int ValueInt = LH->getValue();
const char *MetadataName;
@@ -602,8 +603,8 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
break;
case LoopHintAttr::Unroll:
// With the unroll loop hint, a non-zero value indicates full unrolling.
- MetadataName =
- ValueInt == 0 ? "llvm.loop.unroll.disable" : "llvm.loop.unroll.full";
+ MetadataName = State == LoopHintAttr::Disable ? "llvm.loop.unroll.disable"
+ : "llvm.loop.unroll.full";
break;
case LoopHintAttr::UnrollCount:
MetadataName = "llvm.loop.unroll.count";
@@ -614,7 +615,7 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
switch (Option) {
case LoopHintAttr::Vectorize:
case LoopHintAttr::Interleave:
- if (ValueInt == 1) {
+ if (State != LoopHintAttr::Disable) {
// FIXME: In the future I will modifiy the behavior of the metadata
// so we can enable/disable vectorization and interleaving separately.
Name = llvm::MDString::get(Context, "llvm.loop.vectorize.enable");
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 20b87d92b78..106c02b362f 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -720,40 +720,68 @@ struct PragmaLoopHintInfo {
Token Option;
Token Value;
bool HasValue;
+ PragmaLoopHintInfo() : HasValue(false) {}
};
-LoopHint Parser::HandlePragmaLoopHint() {
+bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
assert(Tok.is(tok::annot_pragma_loop_hint));
PragmaLoopHintInfo *Info =
static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
+ ConsumeToken(); // The annotation token.
- LoopHint Hint;
- Hint.PragmaNameLoc =
- IdentifierLoc::create(Actions.Context, Info->PragmaName.getLocation(),
- Info->PragmaName.getIdentifierInfo());
- Hint.OptionLoc =
- IdentifierLoc::create(Actions.Context, Info->Option.getLocation(),
- Info->Option.getIdentifierInfo());
- if (Info->HasValue) {
- Hint.Range =
- SourceRange(Info->Option.getLocation(), Info->Value.getLocation());
- Hint.ValueLoc =
- IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),
- Info->Value.getIdentifierInfo());
-
+ IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
+ Hint.PragmaNameLoc = IdentifierLoc::create(
+ Actions.Context, Info->PragmaName.getLocation(), PragmaNameInfo);
+
+ IdentifierInfo *OptionInfo = Info->Option.getIdentifierInfo();
+ Hint.OptionLoc = IdentifierLoc::create(
+ Actions.Context, Info->Option.getLocation(), OptionInfo);
+
+ // Return a valid hint if pragma unroll or nounroll were specified
+ // without an argument.
+ bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
+ bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
+ if (!Info->HasValue && (PragmaUnroll || PragmaNoUnroll)) {
+ Hint.Range = Info->PragmaName.getLocation();
+ return true;
+ }
+
+ // If no option is specified the argument is assumed to be numeric.
+ bool StateOption = false;
+ if (OptionInfo)
+ StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
+ .Case("vectorize", true)
+ .Case("interleave", true)
+ .Case("unroll", true)
+ .Default(false);
+
+ // Validate the argument.
+ if (StateOption) {
+ bool OptionUnroll = OptionInfo->isStr("unroll");
+ SourceLocation StateLoc = Info->Value.getLocation();
+ IdentifierInfo *StateInfo = Info->Value.getIdentifierInfo();
+ if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full")
+ : !StateInfo->isStr("enable")) &&
+ !StateInfo->isStr("disable"))) {
+ Diag(StateLoc, diag::err_pragma_invalid_keyword)
+ << /*MissingArgument=*/false << /*FullKeyword=*/OptionUnroll;
+ return false;
+ }
+ Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo);
+ } else {
// FIXME: We should allow non-type template parameters for the loop hint
// value. See bug report #19610
if (Info->Value.is(tok::numeric_constant))
Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
- else
- Hint.ValueExpr = nullptr;
- } else {
- Hint.Range = SourceRange(Info->PragmaName.getLocation());
- Hint.ValueLoc = nullptr;
- Hint.ValueExpr = nullptr;
+ else {
+ Diag(Info->Value.getLocation(), diag::err_pragma_loop_numeric_value);
+ return false;
+ }
}
- return Hint;
+ Hint.Range =
+ SourceRange(Info->PragmaName.getLocation(), Info->Value.getLocation());
+ return true;
}
// #pragma GCC visibility comes in two variants:
@@ -1755,12 +1783,10 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
}
/// \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,
+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;
@@ -1784,13 +1810,15 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
// FIXME: Value should be stored and parsed as a constant expression.
Token Value = Tok;
+ PP.Lex(Tok);
if (ValueInParens) {
- PP.Lex(Tok);
+ // Read ')'
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
return true;
}
+ PP.Lex(Tok);
}
Info.PragmaName = PragmaName;
@@ -1872,17 +1900,19 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
<< /*MissingOption=*/false << OptionInfo;
return;
}
-
- auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
PP.Lex(Tok);
- bool ValueInParens;
- if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info))
- return;
- if (!ValueInParens) {
- PP.Diag(Info->Value.getLocation(), diag::err_expected) << tok::l_paren;
+ // Read '('
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
return;
}
+ PP.Lex(Tok);
+
+ auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
+ if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true,
+ *Info))
+ return;
// Generate the loop hint token.
Token LoopHintTok;
@@ -1891,9 +1921,6 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
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)) {
@@ -1938,7 +1965,6 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
if (Tok.is(tok::eod)) {
// nounroll or unroll pragma without an argument.
Info->PragmaName = PragmaName;
- Info->Option = PragmaName;
Info->HasValue = false;
} else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
@@ -1947,9 +1973,12 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
} else {
// Unroll pragma with an argument: "#pragma unroll N" or
// "#pragma unroll(N)".
- bool ValueInParens;
- if (ParseLoopHintValue(PP, Tok, PragmaName, PragmaName, ValueInParens,
- *Info))
+ // Read '(' if it exists.
+ bool ValueInParens = Tok.is(tok::l_paren);
+ if (ValueInParens)
+ PP.Lex(Tok);
+
+ if (ParseLoopHintValue(PP, Tok, PragmaName, Token(), ValueInParens, *Info))
return;
// In CUDA, the argument to '#pragma unroll' should not be contained in
@@ -1958,7 +1987,6 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
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";
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 38723b1293d..a431270d2b1 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1817,10 +1817,11 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
// Get loop hints and consume annotated token.
while (Tok.is(tok::annot_pragma_loop_hint)) {
- LoopHint Hint = HandlePragmaLoopHint();
- ConsumeToken();
+ LoopHint Hint;
+ if (!HandlePragmaLoopHint(Hint))
+ continue;
- ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.ValueLoc,
+ ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.StateLoc,
ArgsUnion(Hint.ValueExpr)};
TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,
Hint.PragmaNameLoc->Loc, ArgHints, 4,
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 595aa3656eb..4cb0fde11d0 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -47,13 +47,11 @@ 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;
+ IdentifierLoc *StateLoc = A.getArgAsIdent(2);
Expr *ValueExpr = A.getArgAsExpr(3);
- assert(OptionInfo && "Attribute must have valid option info.");
-
+ bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
+ bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
if (St->getStmtClass() != Stmt::DoStmtClass &&
St->getStmtClass() != Stmt::ForStmtClass &&
St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
@@ -69,13 +67,16 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
LoopHintAttr::OptionType Option;
LoopHintAttr::Spelling Spelling;
- if (PragmaNameLoc->Ident->getName() == "unroll") {
- Option = ValueLoc ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
+ if (PragmaUnroll) {
+ Option = ValueExpr ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
Spelling = LoopHintAttr::Pragma_unroll;
- } else if (PragmaNameLoc->Ident->getName() == "nounroll") {
+ } else if (PragmaNoUnroll) {
Option = LoopHintAttr::Unroll;
Spelling = LoopHintAttr::Pragma_nounroll;
} else {
+ assert(OptionLoc && OptionLoc->Ident &&
+ "Attribute must have valid option info.");
+ IdentifierInfo *OptionInfo = OptionLoc->Ident;
Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
.Case("vectorize", LoopHintAttr::Vectorize)
.Case("vectorize_width", LoopHintAttr::VectorizeWidth)
@@ -87,35 +88,10 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
Spelling = LoopHintAttr::Pragma_clang_loop;
}
- int ValueInt = -1;
- if (Option == LoopHintAttr::Unroll &&
- Spelling == LoopHintAttr::Pragma_unroll) {
- if (ValueInfo)
- ValueInt = (ValueInfo->isStr("disable") ? 0 : 1);
- } else if (Option == LoopHintAttr::Unroll &&
- Spelling == LoopHintAttr::Pragma_nounroll) {
- ValueInt = 0;
- } else if (Option == LoopHintAttr::Vectorize ||
- Option == LoopHintAttr::Interleave ||
- Option == LoopHintAttr::Unroll) {
- // Unrolling uses the keyword "full" rather than "enable" to indicate full
- // unrolling.
- const char *TrueKeyword =
- Option == LoopHintAttr::Unroll ? "full" : "enable";
- if (!ValueInfo) {
- S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword)
- << TrueKeyword;
- return nullptr;
- }
- if (ValueInfo->isStr("disable"))
- ValueInt = 0;
- else if (ValueInfo->getName() == TrueKeyword)
- ValueInt = 1;
- else {
- S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword)
- << TrueKeyword;
- return nullptr;
- }
+ int ValueInt = 1;
+ LoopHintAttr::LoopHintState State = LoopHintAttr::Default;
+ if (PragmaNoUnroll) {
+ State = LoopHintAttr::Disable;
} else if (Option == LoopHintAttr::VectorizeWidth ||
Option == LoopHintAttr::InterleaveCount ||
Option == LoopHintAttr::UnrollCount) {
@@ -124,28 +100,39 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
llvm::APSInt ValueAPS;
if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) ||
(ValueInt = ValueAPS.getSExtValue()) < 1) {
- S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value);
+ S.Diag(A.getLoc(), diag::err_pragma_loop_invalid_value);
return nullptr;
}
- } else
- llvm_unreachable("Unknown loop hint option");
+ } else if (Option == LoopHintAttr::Vectorize ||
+ Option == LoopHintAttr::Interleave ||
+ Option == LoopHintAttr::Unroll) {
+ // Default state is assumed if StateLoc is not specified, such as with
+ // '#pragma unroll'.
+ if (StateLoc && StateLoc->Ident) {
+ if (StateLoc->Ident->isStr("disable"))
+ State = LoopHintAttr::Disable;
+ else
+ State = LoopHintAttr::Enable;
+ }
+ }
- return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, ValueInt,
- A.getRange());
+ return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
+ ValueInt, A.getRange());
}
-static void CheckForIncompatibleAttributes(
- Sema &S, const SmallVectorImpl<const Attr *> &Attrs) {
- // There are 3 categories of loop hints attributes: vectorize, interleave, and
- // unroll. Each comes in two variants: a boolean form and a numeric form. The
- // boolean hints selectively enables/disables the transformation for the loop
- // (for unroll, a nonzero value indicates full unrolling rather than enabling
- // the transformation). The numeric hint 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.
+static void
+CheckForIncompatibleAttributes(Sema &S,
+ const SmallVectorImpl<const Attr *> &Attrs) {
+ // There are 3 categories of loop hints attributes: vectorize, interleave,
+ // and unroll. Each comes 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 *EnableAttr;
+ const LoopHintAttr *StateAttr;
const LoopHintAttr *NumericAttr;
} HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
@@ -179,8 +166,8 @@ static void CheckForIncompatibleAttributes(
if (Option == LoopHintAttr::Vectorize ||
Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
// Enable|disable hint. For example, vectorize(enable).
- PrevAttr = CategoryState.EnableAttr;
- CategoryState.EnableAttr = LH;
+ PrevAttr = CategoryState.StateAttr;
+ CategoryState.StateAttr = LH;
} else {
// Numeric hint. For example, vectorize_width(8).
PrevAttr = CategoryState.NumericAttr;
@@ -195,14 +182,15 @@ static void CheckForIncompatibleAttributes(
<< /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
<< LH->getDiagnosticName(Policy);
- if (CategoryState.EnableAttr && CategoryState.NumericAttr &&
- (Category == Unroll || !CategoryState.EnableAttr->getValue())) {
+ if (CategoryState.StateAttr && CategoryState.NumericAttr &&
+ (Category == Unroll ||
+ 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
// compatible with "enable" form of the unroll pragma, unroll(full).
S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
<< /*Duplicate=*/false
- << CategoryState.EnableAttr->getDiagnosticName(Policy)
+ << CategoryState.StateAttr->getDiagnosticName(Policy)
<< CategoryState.NumericAttr->getDiagnosticName(Policy);
}
}
OpenPOWER on IntegriCloud