forked from OSchip/llvm-project
Allow constant expressions in pragma loop hints.
Previously loop hints such as #pragma loop vectorize_width(#) required a constant. This patch allows a constant expression to be used as well. Such as a non-type template parameter or an expression (2 * c + 1). Reviewed by Richard Smith llvm-svn: 219589
This commit is contained in:
parent
7000ca3f55
commit
c724a83e20
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "clang/AST/AttrIterator.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/AttrKinds.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
|
|
@ -1845,7 +1845,7 @@ def LoopHint : Attr {
|
|||
EnumArgument<"State", "LoopHintState",
|
||||
["default", "enable", "disable"],
|
||||
["Default", "Enable", "Disable"]>,
|
||||
DefaultIntArgument<"Value", 1>];
|
||||
ExprArgument<"Value">];
|
||||
|
||||
let AdditionalMembers = [{
|
||||
static const char *getOptionName(int Option) {
|
||||
|
@ -1885,7 +1885,7 @@ def LoopHint : Attr {
|
|||
OS << "(";
|
||||
if (option == VectorizeWidth || option == InterleaveCount ||
|
||||
option == UnrollCount)
|
||||
OS << value;
|
||||
value->printPretty(OS, nullptr, Policy);
|
||||
else if (state == Default)
|
||||
return "";
|
||||
else if (state == Enable)
|
||||
|
|
|
@ -949,16 +949,15 @@ def err_omp_immediate_directive : Error<
|
|||
def err_omp_expected_identifier_for_critical : Error<
|
||||
"expected identifier specifying the name of the 'omp critical' directive">;
|
||||
|
||||
// Pragma support.
|
||||
def err_pragma_invalid_keyword : Error<
|
||||
"%select{invalid|missing}0 argument; expected '%select{enable|full}1' or 'disable'">;
|
||||
|
||||
// Pragma loop support.
|
||||
def err_pragma_loop_missing_argument : Error<
|
||||
"missing argument; expected %select{an integer value|"
|
||||
"'%select{enable|full}1' or 'disable'}0">;
|
||||
def err_pragma_loop_invalid_option : Error<
|
||||
"%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
|
||||
"vectorize_width, interleave, interleave_count, unroll, or unroll_count">;
|
||||
def err_pragma_loop_numeric_value : Error<
|
||||
"invalid argument; expected a positive integer value">;
|
||||
def err_pragma_invalid_keyword : Error<
|
||||
"invalid argument; expected '%select{enable|full}0' or 'disable'">;
|
||||
|
||||
// Pragma unroll support.
|
||||
def warn_pragma_unroll_cuda_value_in_parens : Warning<
|
||||
|
|
|
@ -551,8 +551,10 @@ def err_pragma_pop_visibility_mismatch : Error<
|
|||
"#pragma visibility pop with no matching #pragma visibility push">;
|
||||
def note_surrounding_namespace_starts_here : Note<
|
||||
"surrounding namespace with visibility attribute starts here">;
|
||||
def err_pragma_loop_invalid_value : Error<
|
||||
"invalid argument; expected a positive integer value">;
|
||||
def err_pragma_loop_invalid_argument_type : Error<
|
||||
"invalid argument of type %0; expected an integer type">;
|
||||
def err_pragma_loop_invalid_argument_value : Error<
|
||||
"%select{invalid value '%0'; must be positive|value '%0' is too large}1">;
|
||||
def err_pragma_loop_compatibility : Error<
|
||||
"%select{incompatible|duplicate}0 directives '%1' and '%2'">;
|
||||
def err_pragma_loop_precedes_nonloop : Error<
|
||||
|
|
|
@ -3486,6 +3486,9 @@ public:
|
|||
PredefinedExpr::IdentType IT);
|
||||
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
|
||||
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
|
||||
|
||||
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
|
||||
|
||||
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
|
||||
ExprResult ActOnCharacterConstant(const Token &Tok,
|
||||
Scope *UDLScope = nullptr);
|
||||
|
|
|
@ -601,8 +601,6 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
|
|||
|
||||
LoopHintAttr::OptionType Option = LH->getOption();
|
||||
LoopHintAttr::LoopHintState State = LH->getState();
|
||||
int ValueInt = LH->getValue();
|
||||
|
||||
const char *MetadataName;
|
||||
switch (Option) {
|
||||
case LoopHintAttr::Vectorize:
|
||||
|
@ -622,6 +620,15 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
|
|||
MetadataName = "llvm.loop.unroll.count";
|
||||
break;
|
||||
}
|
||||
|
||||
Expr *ValueExpr = LH->getValue();
|
||||
int ValueInt = 1;
|
||||
if (ValueExpr) {
|
||||
llvm::APSInt ValueAPS =
|
||||
ValueExpr->EvaluateKnownConstInt(CGM.getContext());
|
||||
ValueInt = static_cast<int>(ValueAPS.getSExtValue());
|
||||
}
|
||||
|
||||
llvm::Value *Value;
|
||||
llvm::MDString *Name;
|
||||
switch (Option) {
|
||||
|
|
|
@ -724,16 +724,28 @@ bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
|
|||
struct PragmaLoopHintInfo {
|
||||
Token PragmaName;
|
||||
Token Option;
|
||||
Token Value;
|
||||
bool HasValue;
|
||||
PragmaLoopHintInfo() : HasValue(false) {}
|
||||
Token *Toks;
|
||||
size_t TokSize;
|
||||
PragmaLoopHintInfo() : Toks(nullptr), TokSize(0) {}
|
||||
};
|
||||
|
||||
static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
|
||||
std::string PragmaString;
|
||||
if (PragmaName.getIdentifierInfo()->getName() == "loop") {
|
||||
PragmaString = "clang loop ";
|
||||
PragmaString += Option.getIdentifierInfo()->getName();
|
||||
} else {
|
||||
assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
|
||||
"Unexpected pragma name");
|
||||
PragmaString = "unroll";
|
||||
}
|
||||
return PragmaString;
|
||||
}
|
||||
|
||||
bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
|
||||
assert(Tok.is(tok::annot_pragma_loop_hint));
|
||||
PragmaLoopHintInfo *Info =
|
||||
static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
|
||||
ConsumeToken(); // The annotation token.
|
||||
|
||||
IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
|
||||
Hint.PragmaNameLoc = IdentifierLoc::create(
|
||||
|
@ -747,50 +759,88 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
|
|||
Hint.OptionLoc = IdentifierLoc::create(
|
||||
Actions.Context, Info->Option.getLocation(), OptionInfo);
|
||||
|
||||
Token *Toks = Info->Toks;
|
||||
size_t TokSize = Info->TokSize;
|
||||
|
||||
// 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)) {
|
||||
if (TokSize == 0 && (PragmaUnroll || PragmaNoUnroll)) {
|
||||
ConsumeToken(); // The annotation token.
|
||||
Hint.Range = Info->PragmaName.getLocation();
|
||||
return true;
|
||||
}
|
||||
|
||||
// If no option is specified the argument is assumed to be numeric.
|
||||
// The constant expression is always followed by an eof token, which increases
|
||||
// the TokSize by 1.
|
||||
assert(TokSize > 0 &&
|
||||
"PragmaLoopHintInfo::Toks must contain at least one token.");
|
||||
|
||||
// If no option is specified the argument is assumed to be a constant expr.
|
||||
bool StateOption = false;
|
||||
if (OptionInfo)
|
||||
if (OptionInfo) { // Pragma unroll does not specify an option.
|
||||
StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
|
||||
.Case("vectorize", true)
|
||||
.Case("interleave", true)
|
||||
.Case("unroll", true)
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
// Verify loop hint has an argument.
|
||||
if (Toks[0].is(tok::eof)) {
|
||||
ConsumeToken(); // The annotation token.
|
||||
Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument)
|
||||
<< /*StateArgument=*/StateOption << /*FullKeyword=*/PragmaUnroll;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the argument.
|
||||
if (StateOption) {
|
||||
ConsumeToken(); // The annotation token.
|
||||
bool OptionUnroll = OptionInfo->isStr("unroll");
|
||||
SourceLocation StateLoc = Info->Value.getLocation();
|
||||
IdentifierInfo *StateInfo = Info->Value.getIdentifierInfo();
|
||||
SourceLocation StateLoc = Toks[0].getLocation();
|
||||
IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
|
||||
if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full")
|
||||
: !StateInfo->isStr("enable")) &&
|
||||
!StateInfo->isStr("disable"))) {
|
||||
Diag(StateLoc, diag::err_pragma_invalid_keyword)
|
||||
<< /*MissingArgument=*/false << /*FullKeyword=*/OptionUnroll;
|
||||
Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword)
|
||||
<< /*FullKeyword=*/OptionUnroll;
|
||||
return false;
|
||||
}
|
||||
if (TokSize > 2)
|
||||
Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
|
||||
<< PragmaLoopHintString(Info->PragmaName, Info->Option);
|
||||
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 {
|
||||
Diag(Info->Value.getLocation(), diag::err_pragma_loop_numeric_value);
|
||||
return false;
|
||||
// Enter constant expression including eof terminator into token stream.
|
||||
PP.EnterTokenStream(Toks, TokSize, /*DisableMacroExpansion=*/false,
|
||||
/*OwnsTokens=*/false);
|
||||
ConsumeToken(); // The annotation token.
|
||||
|
||||
ExprResult R = ParseConstantExpression();
|
||||
|
||||
// Tokens following an error in an ill-formed constant expression will
|
||||
// remain in the token stream and must be removed.
|
||||
if (Tok.isNot(tok::eof)) {
|
||||
Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
|
||||
<< PragmaLoopHintString(Info->PragmaName, Info->Option);
|
||||
while (Tok.isNot(tok::eof))
|
||||
ConsumeAnyToken();
|
||||
}
|
||||
|
||||
ConsumeToken(); // Consume the constant expression eof terminator.
|
||||
|
||||
if (R.isInvalid() ||
|
||||
Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation()))
|
||||
return false;
|
||||
|
||||
// Argument is a constant expression with an integer type.
|
||||
Hint.ValueExpr = R.get();
|
||||
}
|
||||
|
||||
Hint.Range =
|
||||
SourceRange(Info->PragmaName.getLocation(), Info->Value.getLocation());
|
||||
Hint.Range = SourceRange(Info->PragmaName.getLocation(),
|
||||
Info->Toks[TokSize - 1].getLocation());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1796,31 +1846,21 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
|
|||
static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
|
||||
Token Option, bool ValueInParens,
|
||||
PragmaLoopHintInfo &Info) {
|
||||
if (ValueInParens) {
|
||||
if (Tok.is(tok::r_paren)) {
|
||||
// Nothing between the parentheses.
|
||||
std::string PragmaString;
|
||||
if (PragmaName.getIdentifierInfo()->getName() == "loop") {
|
||||
PragmaString = "clang loop ";
|
||||
PragmaString += Option.getIdentifierInfo()->getName();
|
||||
} else {
|
||||
assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
|
||||
"Unexpected pragma name");
|
||||
PragmaString = "unroll";
|
||||
}
|
||||
// Don't try to emit what the pragma is expecting with the diagnostic
|
||||
// because the logic is non-trivial and we give expected values in sema
|
||||
// diagnostics if an invalid argument is given. Here, just note that the
|
||||
// pragma is missing an argument.
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
|
||||
<< PragmaString << /*Expected=*/false;
|
||||
return true;
|
||||
SmallVector<Token, 1> ValueList;
|
||||
int OpenParens = ValueInParens ? 1 : 0;
|
||||
// Read constant expression.
|
||||
while (Tok.isNot(tok::eod)) {
|
||||
if (Tok.is(tok::l_paren))
|
||||
OpenParens++;
|
||||
else if (Tok.is(tok::r_paren)) {
|
||||
OpenParens--;
|
||||
if (OpenParens == 0 && ValueInParens)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Value should be stored and parsed as a constant expression.
|
||||
Token Value = Tok;
|
||||
PP.Lex(Tok);
|
||||
ValueList.push_back(Tok);
|
||||
PP.Lex(Tok);
|
||||
}
|
||||
|
||||
if (ValueInParens) {
|
||||
// Read ')'
|
||||
|
@ -1831,10 +1871,20 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
|
|||
PP.Lex(Tok);
|
||||
}
|
||||
|
||||
Token EOFTok;
|
||||
EOFTok.startToken();
|
||||
EOFTok.setKind(tok::eof);
|
||||
EOFTok.setLocation(Tok.getLocation());
|
||||
ValueList.push_back(EOFTok); // Terminates expression for parsing.
|
||||
|
||||
Token *TokenArray =
|
||||
new (PP.getPreprocessorAllocator()) Token[ValueList.size()];
|
||||
std::copy(ValueList.begin(), ValueList.end(), TokenArray);
|
||||
Info.Toks = TokenArray;
|
||||
Info.TokSize = ValueList.size();
|
||||
|
||||
Info.PragmaName = PragmaName;
|
||||
Info.Option = Option;
|
||||
Info.Value = Value;
|
||||
Info.HasValue = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1975,7 +2025,6 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
|
|||
if (Tok.is(tok::eod)) {
|
||||
// nounroll or unroll pragma without an argument.
|
||||
Info->PragmaName = PragmaName;
|
||||
Info->HasValue = false;
|
||||
Info->Option.startToken();
|
||||
} else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") {
|
||||
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
|
||||
|
@ -1997,7 +2046,7 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
|
|||
// In CUDA, the argument to '#pragma unroll' should not be contained in
|
||||
// parentheses.
|
||||
if (PP.getLangOpts().CUDA && ValueInParens)
|
||||
PP.Diag(Info->Value.getLocation(),
|
||||
PP.Diag(Info->Toks[0].getLocation(),
|
||||
diag::warn_pragma_unroll_cuda_value_in_parens);
|
||||
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
|
|
|
@ -3021,6 +3021,34 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
|
|||
return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc);
|
||||
}
|
||||
|
||||
bool Sema::CheckLoopHintExpr(Expr *E, SourceLocation Loc) {
|
||||
assert(E && "Invalid expression");
|
||||
|
||||
if (E->isValueDependent())
|
||||
return false;
|
||||
|
||||
QualType QT = E->getType();
|
||||
if (!QT->isIntegerType() || QT->isBooleanType() || QT->isCharType()) {
|
||||
Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_type) << QT;
|
||||
return true;
|
||||
}
|
||||
|
||||
llvm::APSInt ValueAPS;
|
||||
ExprResult R = VerifyIntegerConstantExpression(E, &ValueAPS);
|
||||
|
||||
if (R.isInvalid())
|
||||
return true;
|
||||
|
||||
bool ValueIsPositive = ValueAPS.isStrictlyPositive();
|
||||
if (!ValueIsPositive || ValueAPS.getActiveBits() > 31) {
|
||||
Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_value)
|
||||
<< ValueAPS.toString(10) << ValueIsPositive;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
|
||||
// Fast path for a single digit (which is quite common). A single digit
|
||||
// cannot have a trigraph, escaped newline, radix prefix, or suffix.
|
||||
|
|
|
@ -88,21 +88,15 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
|
|||
Spelling = LoopHintAttr::Pragma_clang_loop;
|
||||
}
|
||||
|
||||
int ValueInt = 1;
|
||||
LoopHintAttr::LoopHintState State = LoopHintAttr::Default;
|
||||
if (PragmaNoUnroll) {
|
||||
State = LoopHintAttr::Disable;
|
||||
} else if (Option == LoopHintAttr::VectorizeWidth ||
|
||||
Option == LoopHintAttr::InterleaveCount ||
|
||||
Option == LoopHintAttr::UnrollCount) {
|
||||
// FIXME: We should support template parameters for the loop hint value.
|
||||
// See bug report #19610.
|
||||
llvm::APSInt ValueAPS;
|
||||
if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) ||
|
||||
(ValueInt = ValueAPS.getSExtValue()) < 1) {
|
||||
S.Diag(A.getLoc(), diag::err_pragma_loop_invalid_value);
|
||||
assert(ValueExpr && "Attribute must have a valid value expression.");
|
||||
if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
|
||||
return nullptr;
|
||||
}
|
||||
} else if (Option == LoopHintAttr::Vectorize ||
|
||||
Option == LoopHintAttr::Interleave ||
|
||||
Option == LoopHintAttr::Unroll) {
|
||||
|
@ -117,7 +111,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
|
|||
}
|
||||
|
||||
return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
|
||||
ValueInt, A.getRange());
|
||||
ValueExpr, A.getRange());
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -767,6 +767,8 @@ namespace {
|
|||
QualType ObjectType = QualType(),
|
||||
NamedDecl *FirstQualifierInScope = nullptr);
|
||||
|
||||
const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
|
||||
|
||||
ExprResult TransformPredefinedExpr(PredefinedExpr *E);
|
||||
ExprResult TransformDeclRefExpr(DeclRefExpr *E);
|
||||
ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
|
||||
|
@ -1127,6 +1129,24 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
|
|||
return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
|
||||
}
|
||||
|
||||
const LoopHintAttr *
|
||||
TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
|
||||
Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get();
|
||||
|
||||
if (TransformedExpr == LH->getValue())
|
||||
return LH;
|
||||
|
||||
// Generate error if there is a problem with the value.
|
||||
if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation()))
|
||||
return LH;
|
||||
|
||||
// Create new LoopHintValueAttr with integral expression in place of the
|
||||
// non-type template parameter.
|
||||
return LoopHintAttr::CreateImplicit(
|
||||
getSema().Context, LH->getSemanticSpelling(), LH->getOption(),
|
||||
LH->getState(), TransformedExpr, LH->getRange());
|
||||
}
|
||||
|
||||
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
|
||||
NonTypeTemplateParmDecl *parm,
|
||||
SourceLocation loc,
|
||||
|
|
|
@ -327,6 +327,27 @@ public:
|
|||
/// \returns the transformed OpenMP clause.
|
||||
OMPClause *TransformOMPClause(OMPClause *S);
|
||||
|
||||
/// \brief Transform the given attribute.
|
||||
///
|
||||
/// By default, this routine transforms a statement by delegating to the
|
||||
/// appropriate TransformXXXAttr function to transform a specific kind
|
||||
/// of attribute. Subclasses may override this function to transform
|
||||
/// attributed statements using some other mechanism.
|
||||
///
|
||||
/// \returns the transformed attribute
|
||||
const Attr *TransformAttr(const Attr *S);
|
||||
|
||||
/// \brief Transform the specified attribute.
|
||||
///
|
||||
/// Subclasses should override the transformation of attributes with a pragma
|
||||
/// spelling to transform expressions stored within the attribute.
|
||||
///
|
||||
/// \returns the transformed attribute.
|
||||
#define ATTR(X)
|
||||
#define PRAGMA_SPELLING_ATTR(X) \
|
||||
const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; }
|
||||
#include "clang/Basic/AttrList.inc"
|
||||
|
||||
/// \brief Transform the given expression.
|
||||
///
|
||||
/// By default, this routine transforms an expression by delegating to the
|
||||
|
@ -5543,19 +5564,43 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) {
|
|||
SubStmt.get());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
|
||||
template <typename Derived>
|
||||
const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) {
|
||||
if (!R)
|
||||
return R;
|
||||
|
||||
switch (R->getKind()) {
|
||||
// Transform attributes with a pragma spelling by calling TransformXXXAttr.
|
||||
#define ATTR(X)
|
||||
#define PRAGMA_SPELLING_ATTR(X) \
|
||||
case attr::X: \
|
||||
return getDerived().Transform##X##Attr(cast<X##Attr>(R));
|
||||
#include "clang/Basic/AttrList.inc"
|
||||
default:
|
||||
return R;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
|
||||
bool AttrsChanged = false;
|
||||
SmallVector<const Attr *, 1> Attrs;
|
||||
|
||||
// Visit attributes and keep track if any are transformed.
|
||||
for (const auto *I : S->getAttrs()) {
|
||||
const Attr *R = getDerived().TransformAttr(I);
|
||||
AttrsChanged |= (I != R);
|
||||
Attrs.push_back(R);
|
||||
}
|
||||
|
||||
StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
|
||||
if (SubStmt.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
// TODO: transform attributes
|
||||
if (SubStmt.get() == S->getSubStmt() /* && attrs are the same */)
|
||||
if (SubStmt.get() == S->getSubStmt() && !AttrsChanged)
|
||||
return S;
|
||||
|
||||
return getDerived().RebuildAttributedStmt(S->getAttrLoc(),
|
||||
S->getAttrs(),
|
||||
return getDerived().RebuildAttributedStmt(S->getAttrLoc(), Attrs,
|
||||
SubStmt.get());
|
||||
}
|
||||
|
||||
|
|
|
@ -28,11 +28,13 @@ void do_test(int *List, int Length) {
|
|||
} while (i < Length);
|
||||
}
|
||||
|
||||
enum struct Tuner : short { Interleave = 4, Unroll = 8 };
|
||||
|
||||
// Verify for loop is recognized after sequence of pragma clang loop directives.
|
||||
void for_test(int *List, int Length) {
|
||||
#pragma clang loop interleave(enable)
|
||||
#pragma clang loop interleave_count(4)
|
||||
#pragma clang loop unroll_count(8)
|
||||
#pragma clang loop interleave_count(static_cast<int>(Tuner::Interleave))
|
||||
#pragma clang loop unroll_count(static_cast<int>(Tuner::Unroll))
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_3:.*]]
|
||||
List[i] = i * 2;
|
||||
|
@ -74,28 +76,74 @@ void for_define_test(int *List, int Length, int Value) {
|
|||
}
|
||||
}
|
||||
|
||||
// Verify constant expressions are handled correctly.
|
||||
void for_contant_expression_test(int *List, int Length) {
|
||||
#pragma clang loop vectorize_width(1 + 4)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_7:.*]]
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
#pragma clang loop vectorize_width(3 + VECWIDTH)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_8:.*]]
|
||||
List[i] += i;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify metadata is generated when template is used.
|
||||
template <typename A>
|
||||
void for_template_test(A *List, int Length, A Value) {
|
||||
|
||||
#pragma clang loop vectorize_width(8) interleave_count(8) unroll_count(8)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_7:.*]]
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_9:.*]]
|
||||
List[i] = i * Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify define is resolved correctly when template is used.
|
||||
template <typename A>
|
||||
template <typename A, typename T>
|
||||
void for_template_define_test(A *List, int Length, A Value) {
|
||||
#pragma clang loop vectorize_width(VECWIDTH) interleave_count(INTCOUNT)
|
||||
#pragma clang loop unroll_count(UNROLLCOUNT)
|
||||
const T VWidth = VECWIDTH;
|
||||
const T ICount = INTCOUNT;
|
||||
const T UCount = UNROLLCOUNT;
|
||||
#pragma clang loop vectorize_width(VWidth) interleave_count(ICount)
|
||||
#pragma clang loop unroll_count(UCount)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_8:.*]]
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_10:.*]]
|
||||
List[i] = i * Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify templates and constant expressions are handled correctly.
|
||||
template <typename A, int V, int I, int U>
|
||||
void for_template_constant_expression_test(A *List, int Length) {
|
||||
#pragma clang loop vectorize_width(V) interleave_count(I) unroll_count(U)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_11:.*]]
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
#pragma clang loop vectorize_width(V * 2 + VECWIDTH) interleave_count(I * 2 + INTCOUNT) unroll_count(U * 2 + UNROLLCOUNT)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_12:.*]]
|
||||
List[i] += i;
|
||||
}
|
||||
|
||||
const int Scale = 4;
|
||||
#pragma clang loop vectorize_width(Scale * V) interleave_count(Scale * I) unroll_count(Scale * U)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_13:.*]]
|
||||
List[i] += i;
|
||||
}
|
||||
|
||||
#pragma clang loop vectorize_width((Scale * V) + 2)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_14:.*]]
|
||||
List[i] += i;
|
||||
}
|
||||
}
|
||||
|
||||
#undef VECWIDTH
|
||||
#undef INTCOUNT
|
||||
#undef UNROLLCOUNT
|
||||
|
@ -105,7 +153,8 @@ void template_test(double *List, int Length) {
|
|||
double Value = 10;
|
||||
|
||||
for_template_test<double>(List, Length, Value);
|
||||
for_template_define_test<double>(List, Length, Value);
|
||||
for_template_define_test<double, int>(List, Length, Value);
|
||||
for_template_constant_expression_test<double, 2, 4, 8>(List, Length);
|
||||
}
|
||||
|
||||
// CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata ![[UNROLL_FULL:.*]], metadata ![[WIDTH_4:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[INTENABLE_1:.*]]}
|
||||
|
@ -124,6 +173,19 @@ void template_test(double *List, int Length) {
|
|||
// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[UNROLL_DISABLE:.*]], metadata ![[WIDTH_1:.*]]}
|
||||
// CHECK: ![[WIDTH_1]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 1}
|
||||
// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
|
||||
// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata ![[WIDTH_8:.*]]}
|
||||
// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[WIDTH_5:.*]]}
|
||||
// CHECK: ![[WIDTH_5]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 5}
|
||||
// CHECK: ![[LOOP_8]] = metadata !{metadata ![[LOOP_8]], metadata ![[WIDTH_5:.*]]}
|
||||
// CHECK: ![[LOOP_9]] = metadata !{metadata ![[LOOP_9]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata ![[WIDTH_8:.*]]}
|
||||
// CHECK: ![[INTERLEAVE_8]] = metadata !{metadata !"llvm.loop.interleave.count", i32 8}
|
||||
// CHECK: ![[LOOP_8]] = metadata !{metadata ![[LOOP_8]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
|
||||
// CHECK: ![[LOOP_10]] = metadata !{metadata ![[LOOP_10]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
|
||||
// CHECK: ![[LOOP_11]] = metadata !{metadata ![[LOOP_11]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_4:.*]], metadata ![[WIDTH_2:.*]]}
|
||||
// CHECK: ![[LOOP_12]] = metadata !{metadata ![[LOOP_12]], metadata ![[UNROLL_24:.*]], metadata ![[INTERLEAVE_10:.*]], metadata ![[WIDTH_6:.*]]}
|
||||
// CHECK: ![[UNROLL_24]] = metadata !{metadata !"llvm.loop.unroll.count", i32 24}
|
||||
// CHECK: ![[INTERLEAVE_10]] = metadata !{metadata !"llvm.loop.interleave.count", i32 10}
|
||||
// CHECK: ![[WIDTH_6]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 6}
|
||||
// CHECK: ![[LOOP_13]] = metadata !{metadata ![[LOOP_13]], metadata ![[UNROLL_32:.*]], metadata ![[INTERLEAVE_16:.*]], metadata ![[WIDTH_8:.*]]}
|
||||
// CHECK: ![[UNROLL_32]] = metadata !{metadata !"llvm.loop.unroll.count", i32 32}
|
||||
// CHECK: ![[INTERLEAVE_16]] = metadata !{metadata !"llvm.loop.interleave.count", i32 16}
|
||||
// CHECK: ![[LOOP_14]] = metadata !{metadata ![[LOOP_14]], metadata ![[WIDTH_10:.*]]}
|
||||
// CHECK: ![[WIDTH_10]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 10}
|
||||
|
|
|
@ -38,3 +38,18 @@ void test(int *List, int Length) {
|
|||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
template <int V, int I>
|
||||
void test_nontype_template_param(int *List, int Length) {
|
||||
#pragma clang loop vectorize_width(V) interleave_count(I)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: #pragma clang loop interleave_count(I)
|
||||
// CHECK: #pragma clang loop vectorize_width(V)
|
||||
|
||||
void test_templates(int *List, int Length) {
|
||||
test_nontype_template_param<2, 4>(List, Length);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
// CHECK: #pragma unroll
|
||||
// CHECK: #pragma unroll (32)
|
||||
// CHECK: #pragma nounroll
|
||||
// CHECK: #pragma clang loop interleave_count(I)
|
||||
// CHECK: #pragma clang loop vectorize_width(V)
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
@ -81,6 +83,15 @@ public:
|
|||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
template <int V, int I>
|
||||
inline void run7(int *List, int Length) {
|
||||
#pragma clang loop vectorize_width(V)
|
||||
#pragma clang loop interleave_count(I)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
};
|
||||
#else
|
||||
|
||||
|
@ -95,6 +106,7 @@ void test() {
|
|||
pt.run4(List, 100);
|
||||
pt.run5(List, 100);
|
||||
pt.run6(List, 100);
|
||||
pt.run7<2, 4>(List, 100);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,79 @@
|
|||
// Note that this puts the expected lines before the directives to work around
|
||||
// limitations in the -verify mode.
|
||||
|
||||
template <int V, int I>
|
||||
void test_nontype_template_param(int *List, int Length) {
|
||||
#pragma clang loop vectorize_width(V) interleave_count(I)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
#pragma clang loop vectorize_width(V + 4) interleave_count(I + 4)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
template <int V>
|
||||
void test_nontype_template_vectorize(int *List, int Length) {
|
||||
/* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop vectorize_width(V)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop vectorize_width(V / 2)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] += i;
|
||||
}
|
||||
}
|
||||
|
||||
template <int I>
|
||||
void test_nontype_template_interleave(int *List, int Length) {
|
||||
/* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop interleave_count(I)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(2 % I)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
template <char V>
|
||||
void test_nontype_template_char(int *List, int Length) {
|
||||
/* expected-error {{invalid argument of type 'char'; expected an integer type}} */ #pragma clang loop vectorize_width(V)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool V>
|
||||
void test_nontype_template_bool(int *List, int Length) {
|
||||
/* expected-error {{invalid argument of type 'bool'; expected an integer type}} */ #pragma clang loop vectorize_width(V)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
template <int V, int I>
|
||||
void test_nontype_template_badarg(int *List, int Length) {
|
||||
/* expected-error {{use of undeclared identifier 'Vec'}} */ #pragma clang loop vectorize_width(Vec) interleave_count(I)
|
||||
/* expected-error {{use of undeclared identifier 'Int'}} */ #pragma clang loop vectorize_width(V) interleave_count(Int)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void test_type_template_vectorize(int *List, int Length) {
|
||||
const T Value = -1;
|
||||
/* expected-error {{invalid value '-1'; must be positive}} */ #pragma clang loop vectorize_width(Value)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
void test(int *List, int Length) {
|
||||
int i = 0;
|
||||
|
||||
|
@ -43,6 +116,8 @@ void test(int *List, int Length) {
|
|||
VList[j] = List[j];
|
||||
}
|
||||
|
||||
test_nontype_template_param<4, 8>(List, Length);
|
||||
|
||||
/* expected-error {{expected '('}} */ #pragma clang loop vectorize
|
||||
/* expected-error {{expected '('}} */ #pragma clang loop interleave
|
||||
/* expected-error {{expected '('}} */ #pragma clang loop unroll
|
||||
|
@ -55,40 +130,56 @@ void test(int *List, int Length) {
|
|||
/* expected-error {{expected ')'}} */ #pragma clang loop interleave_count(4
|
||||
/* expected-error {{expected ')'}} */ #pragma clang loop unroll_count(4
|
||||
|
||||
/* expected-error {{missing argument to '#pragma clang loop vectorize'}} */ #pragma clang loop vectorize()
|
||||
/* expected-error {{missing argument to '#pragma clang loop interleave_count'}} */ #pragma clang loop interleave_count()
|
||||
/* expected-error {{missing argument to '#pragma clang loop unroll'}} */ #pragma clang loop unroll()
|
||||
/* expected-error {{missing argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize()
|
||||
/* expected-error {{missing argument; expected an integer value}} */ #pragma clang loop interleave_count()
|
||||
/* expected-error {{missing argument; expected 'enable' or 'disable'}} */ #pragma clang loop unroll()
|
||||
|
||||
/* expected-error {{missing option}} */ #pragma clang loop
|
||||
/* expected-error {{missing option; expected vectorize, vectorize_width, interleave, interleave_count, unroll, or unroll_count}} */ #pragma clang loop
|
||||
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword
|
||||
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword(enable)
|
||||
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop vectorize(enable) badkeyword(4)
|
||||
/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize(enable) ,
|
||||
|
||||
while (i-4 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(0)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(0)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(0)
|
||||
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop vectorize_width(0)
|
||||
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(0)
|
||||
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop unroll_count(0)
|
||||
|
||||
/* expected-error {{expression is not an integral constant expression}} expected-note {{division by zero}} */ #pragma clang loop vectorize_width(10 / 0)
|
||||
/* expected-error {{invalid value '0'; must be positive}} */ #pragma clang loop interleave_count(10 / 5 - 2)
|
||||
while (i-5 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(3000000000)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(3000000000)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(3000000000)
|
||||
test_nontype_template_vectorize<4>(List, Length);
|
||||
/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_vectorize<-1>(List, Length);
|
||||
test_nontype_template_interleave<8>(List, Length);
|
||||
/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_interleave<-1>(List, Length);
|
||||
|
||||
/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_char<'A'>(List, Length); // Loop hint arg cannot be a char.
|
||||
/* expected-note {{in instantiation of function template specialization}} */ test_nontype_template_bool<true>(List, Length); // Or a bool.
|
||||
/* expected-note {{in instantiation of function template specialization}} */ test_type_template_vectorize<int>(List, Length); // Or a template type.
|
||||
|
||||
/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop vectorize_width(3000000000)
|
||||
/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop interleave_count(3000000000)
|
||||
/* expected-error {{value '3000000000' is too large}} */ #pragma clang loop unroll_count(3000000000)
|
||||
while (i-6 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(1 +) 1
|
||||
/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize_width(1 +) 1
|
||||
/* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize_width(1) +1
|
||||
const int VV = 4;
|
||||
/* expected-error {{expected expression}} */ #pragma clang loop vectorize_width(VV +/ 2)
|
||||
/* expected-error {{use of undeclared identifier 'undefined'}} */ #pragma clang loop vectorize_width(VV+undefined)
|
||||
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(1+(^*/2 * ()
|
||||
/* expected-warning {{extra tokens at end of '#pragma clang loop' - ignored}} */ #pragma clang loop vectorize_width(1+(-0[0]))))))
|
||||
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(badvalue)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(badvalue)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(badvalue)
|
||||
/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop vectorize_width(badvalue)
|
||||
/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop interleave_count(badvalue)
|
||||
/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop unroll_count(badvalue)
|
||||
while (i-6 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
@ -102,12 +193,12 @@ void test(int *List, int Length) {
|
|||
|
||||
// PR20069 - Loop pragma arguments that are not identifiers or numeric
|
||||
// constants crash FE.
|
||||
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize(()
|
||||
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize(()
|
||||
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop interleave(*)
|
||||
/* expected-error {{invalid argument; expected 'full' or 'disable'}} */ #pragma clang loop unroll(=)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(^)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(/)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(==)
|
||||
/* expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}} */ #pragma clang loop vectorize_width(^)
|
||||
/* expected-error {{expected expression}} expected-error {{expected expression}} */ #pragma clang loop interleave_count(/)
|
||||
/* expected-error {{expected expression}} expected-error {{expected expression}} */ #pragma clang loop unroll_count(==)
|
||||
while (i-8 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ void test(int *List, int Length) {
|
|||
}
|
||||
|
||||
/* expected-error {{expected ')'}} */ #pragma unroll(4
|
||||
/* expected-error {{missing argument to '#pragma unroll'}} */ #pragma unroll()
|
||||
/* expected-error {{missing argument; expected an integer value}} */ #pragma unroll()
|
||||
/* expected-warning {{extra tokens at end of '#pragma unroll'}} */ #pragma unroll 1 2
|
||||
while (i-6 < Length) {
|
||||
List[i] = i;
|
||||
|
@ -38,12 +38,12 @@ void test(int *List, int Length) {
|
|||
List[i] = i;
|
||||
}
|
||||
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(()
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll -
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(0)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 0
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(3000000000)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 3000000000
|
||||
/* expected-error {{expected ')'}} */ #pragma unroll(()
|
||||
/* expected-error {{expected expression}} */ #pragma unroll -
|
||||
/* expected-error {{invalid value '0'; must be positive}} */ #pragma unroll(0)
|
||||
/* expected-error {{invalid value '0'; must be positive}} */ #pragma unroll 0
|
||||
/* expected-error {{value '3000000000' is too large}} */ #pragma unroll(3000000000)
|
||||
/* expected-error {{value '3000000000' is too large}} */ #pragma unroll 3000000000
|
||||
while (i-8 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
|
|
@ -1669,8 +1669,16 @@ static void EmitAttrList(raw_ostream &OS, StringRef Class,
|
|||
}
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
// Determines if an attribute has a Pragma spelling.
|
||||
static bool AttrHasPragmaSpelling(const Record *R) {
|
||||
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
|
||||
return std::find_if(Spellings.begin(), Spellings.end(),
|
||||
[](const FlattenedSpelling &S) {
|
||||
return S.variety() == "Pragma";
|
||||
}) != Spellings.end();
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
// Emits the enumeration list for attributes.
|
||||
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
|
||||
emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
|
||||
|
@ -1696,14 +1704,25 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
|
|||
" INHERITABLE_PARAM_ATTR(NAME)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "#ifndef PRAGMA_SPELLING_ATTR\n";
|
||||
OS << "#define PRAGMA_SPELLING_ATTR(NAME)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "#ifndef LAST_PRAGMA_SPELLING_ATTR\n";
|
||||
OS << "#define LAST_PRAGMA_SPELLING_ATTR(NAME) PRAGMA_SPELLING_ATTR(NAME)\n";
|
||||
OS << "#endif\n\n";
|
||||
|
||||
Record *InhClass = Records.getClass("InheritableAttr");
|
||||
Record *InhParamClass = Records.getClass("InheritableParamAttr");
|
||||
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
|
||||
NonInhAttrs, InhAttrs, InhParamAttrs;
|
||||
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"),
|
||||
NonInhAttrs, InhAttrs, InhParamAttrs, PragmaAttrs;
|
||||
for (auto *Attr : Attrs) {
|
||||
if (!Attr->getValueAsBit("ASTNode"))
|
||||
continue;
|
||||
|
||||
|
||||
if (AttrHasPragmaSpelling(Attr))
|
||||
PragmaAttrs.push_back(Attr);
|
||||
|
||||
if (Attr->isSubClassOf(InhParamClass))
|
||||
InhParamAttrs.push_back(Attr);
|
||||
else if (Attr->isSubClassOf(InhClass))
|
||||
|
@ -1712,6 +1731,7 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
|
|||
NonInhAttrs.push_back(Attr);
|
||||
}
|
||||
|
||||
EmitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs);
|
||||
EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);
|
||||
EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);
|
||||
EmitAttrList(OS, "ATTR", NonInhAttrs);
|
||||
|
@ -1720,6 +1740,8 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
|
|||
OS << "#undef INHERITABLE_ATTR\n";
|
||||
OS << "#undef LAST_INHERITABLE_ATTR\n";
|
||||
OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n";
|
||||
OS << "#undef LAST_PRAGMA_ATTR\n";
|
||||
OS << "#undef PRAGMA_SPELLING_ATTR\n";
|
||||
OS << "#undef ATTR\n";
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue