diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/CodeGen/CGStmt.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/Parse/ParsePragma.cpp | 112 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmtAttr.cpp | 104 |
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); } } |

