summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support
diff options
context:
space:
mode:
authorThomas Preud'homme <thomasp@graphcore.ai>2019-07-13 13:24:30 +0000
committerThomas Preud'homme <thomasp@graphcore.ai>2019-07-13 13:24:30 +0000
commit2a7f5204602938ae89b0860e9412603d1951d945 (patch)
tree71376564c9ec72b8d0e10d77eddef856596e78ff /llvm/lib/Support
parent22cc1030f6a9afd14cc48ec0b935ebe8678c0c2e (diff)
downloadbcm5719-llvm-2a7f5204602938ae89b0860e9412603d1951d945.tar.gz
bcm5719-llvm-2a7f5204602938ae89b0860e9412603d1951d945.zip
FileCheck [7/12]: Arbitrary long numeric expressions
Summary: This patch is part of a patch series to add support for FileCheck numeric expressions. This specific patch extend numeric expression to support an arbitrary number of operands, either variable or literals. Copyright: - Linaro (changes up to diff 183612 of revision D55940) - GraphCore (changes in later versions of revision D55940 and in new revision created off D55940) Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield Tags: #llvm Differential Revision: https://reviews.llvm.org/D60387 llvm-svn: 366001
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r--llvm/lib/Support/FileCheck.cpp208
1 files changed, 124 insertions, 84 deletions
diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
index 5ec126f934e..9fb4d798849 100644
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -35,17 +35,33 @@ void FileCheckNumericVariable::clearValue() {
Value = None;
}
-Expected<uint64_t> FileCheckExpression::eval() const {
- assert(LeftOp && "Evaluating an empty expression");
- Optional<uint64_t> LeftOpValue = LeftOp->getValue();
- // Variable is undefined.
- if (!LeftOpValue)
- return make_error<FileCheckUndefVarError>(LeftOp->getName());
- return EvalBinop(*LeftOpValue, RightOp);
+Expected<uint64_t> FileCheckNumericVariableUse::eval() const {
+ Optional<uint64_t> Value = NumericVariable->getValue();
+ if (Value)
+ return *Value;
+ return make_error<FileCheckUndefVarError>(Name);
+}
+
+Expected<uint64_t> FileCheckASTBinop::eval() const {
+ Expected<uint64_t> LeftOp = LeftOperand->eval();
+ Expected<uint64_t> RightOp = RightOperand->eval();
+
+ // Bubble up any error (e.g. undefined variables) in the recursive
+ // evaluation.
+ if (!LeftOp || !RightOp) {
+ Error Err = Error::success();
+ if (!LeftOp)
+ Err = joinErrors(std::move(Err), LeftOp.takeError());
+ if (!RightOp)
+ Err = joinErrors(std::move(Err), RightOp.takeError());
+ return std::move(Err);
+ }
+
+ return EvalBinop(*LeftOp, *RightOp);
}
Expected<std::string> FileCheckNumericSubstitution::getResult() const {
- Expected<uint64_t> EvaluatedValue = Expression->eval();
+ Expected<uint64_t> EvaluatedValue = ExpressionAST->eval();
if (!EvaluatedValue)
return EvaluatedValue.takeError();
return utostr(*EvaluatedValue);
@@ -63,15 +79,14 @@ bool FileCheckPattern::isValidVarNameStart(char C) {
return C == '_' || isalpha(C);
}
-Expected<StringRef> FileCheckPattern::parseVariable(StringRef &Str,
- bool &IsPseudo,
- const SourceMgr &SM) {
+Expected<FileCheckPattern::VariableProperties>
+FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
if (Str.empty())
return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name");
bool ParsedOneChar = false;
unsigned I = 0;
- IsPseudo = Str[0] == '@';
+ bool IsPseudo = Str[0] == '@';
// Global vars start with '$'.
if (Str[0] == '$' || IsPseudo)
@@ -89,7 +104,7 @@ Expected<StringRef> FileCheckPattern::parseVariable(StringRef &Str,
StringRef Name = Str.take_front(I);
Str = Str.substr(I);
- return Name;
+ return VariableProperties {Name, IsPseudo};
}
// StringRef holding all characters considered as horizontal whitespaces by
@@ -111,13 +126,12 @@ Expected<FileCheckNumericVariable *>
FileCheckPattern::parseNumericVariableDefinition(
StringRef &Expr, FileCheckPatternContext *Context, size_t LineNumber,
const SourceMgr &SM) {
- bool IsPseudo;
- Expected<StringRef> ParseVarResult = parseVariable(Expr, IsPseudo, SM);
+ Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
if (!ParseVarResult)
return ParseVarResult.takeError();
- StringRef Name = *ParseVarResult;
+ StringRef Name = ParseVarResult->Name;
- if (IsPseudo)
+ if (ParseVarResult->IsPseudo)
return FileCheckErrorDiagnostic::get(
SM, Name, "definition of pseudo numeric variable unsupported");
@@ -143,15 +157,9 @@ FileCheckPattern::parseNumericVariableDefinition(
return DefinedNumericVariable;
}
-Expected<FileCheckNumericVariable *>
-FileCheckPattern::parseNumericVariableUse(StringRef &Expr,
+Expected<std::unique_ptr<FileCheckNumericVariableUse>>
+FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
const SourceMgr &SM) const {
- bool IsPseudo;
- Expected<StringRef> ParseVarResult = parseVariable(Expr, IsPseudo, SM);
- if (!ParseVarResult)
- return ParseVarResult.takeError();
- StringRef Name = *ParseVarResult;
-
if (IsPseudo && !Name.equals("@LINE"))
return FileCheckErrorDiagnostic::get(
SM, Name, "invalid pseudo numeric variable '" + Name + "'");
@@ -178,7 +186,32 @@ FileCheckPattern::parseNumericVariableUse(StringRef &Expr,
SM, Name,
"numeric variable '" + Name + "' defined on the same line as used");
- return NumericVariable;
+ return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);
+}
+
+Expected<std::unique_ptr<FileCheckExpressionAST>>
+FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
+ const SourceMgr &SM) const {
+ if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
+ // Try to parse as a numeric variable use.
+ Expected<FileCheckPattern::VariableProperties> ParseVarResult =
+ parseVariable(Expr, SM);
+ if (ParseVarResult)
+ return parseNumericVariableUse(ParseVarResult->Name,
+ ParseVarResult->IsPseudo, SM);
+ if (AO == AllowedOperand::LineVar)
+ return ParseVarResult.takeError();
+ // Ignore the error and retry parsing as a literal.
+ consumeError(ParseVarResult.takeError());
+ }
+
+ // Otherwise, parse it as a literal.
+ uint64_t LiteralValue;
+ if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))
+ return llvm::make_unique<FileCheckExpressionLiteral>(LiteralValue);
+
+ return FileCheckErrorDiagnostic::get(SM, Expr,
+ "invalid operand format '" + Expr + "'");
}
static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
@@ -189,20 +222,16 @@ static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
return LeftOp - RightOp;
}
-Expected<FileCheckExpression *>
-FileCheckPattern::parseBinop(StringRef &Expr, const SourceMgr &SM) const {
- Expected<FileCheckNumericVariable *> LeftParseResult =
- parseNumericVariableUse(Expr, SM);
- if (!LeftParseResult) {
- return LeftParseResult.takeError();
- }
- FileCheckNumericVariable *LeftOp = *LeftParseResult;
+Expected<std::unique_ptr<FileCheckExpressionAST>>
+FileCheckPattern::parseBinop(StringRef &Expr,
+ std::unique_ptr<FileCheckExpressionAST> LeftOp,
+ bool IsLegacyLineExpr, const SourceMgr &SM) const {
+ Expr = Expr.ltrim(SpaceChars);
+ if (Expr.empty())
+ return std::move(LeftOp);
// Check if this is a supported operation and select a function to perform
// it.
- Expr = Expr.ltrim(SpaceChars);
- if (Expr.empty())
- return Context->makeExpression(add, LeftOp, 0);
SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());
char Operator = popFront(Expr);
binop_eval_t EvalBinop;
@@ -223,22 +252,24 @@ FileCheckPattern::parseBinop(StringRef &Expr, const SourceMgr &SM) const {
if (Expr.empty())
return FileCheckErrorDiagnostic::get(SM, Expr,
"missing operand in expression");
- uint64_t RightOp;
- if (Expr.consumeInteger(10, RightOp))
- return FileCheckErrorDiagnostic::get(
- SM, Expr, "invalid offset in expression '" + Expr + "'");
- Expr = Expr.ltrim(SpaceChars);
- if (!Expr.empty())
- return FileCheckErrorDiagnostic::get(
- SM, Expr, "unexpected characters at end of expression '" + Expr + "'");
+ // The second operand in a legacy @LINE expression is always a literal.
+ AllowedOperand AO =
+ IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
+ Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =
+ parseNumericOperand(Expr, AO, SM);
+ if (!RightOpResult)
+ return RightOpResult;
- return Context->makeExpression(EvalBinop, LeftOp, RightOp);
+ Expr = Expr.ltrim(SpaceChars);
+ return llvm::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp),
+ std::move(*RightOpResult));
}
-Expected<FileCheckExpression *> FileCheckPattern::parseNumericSubstitutionBlock(
+Expected<std::unique_ptr<FileCheckExpressionAST>>
+FileCheckPattern::parseNumericSubstitutionBlock(
StringRef Expr,
Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
- const SourceMgr &SM) const {
+ bool IsLegacyLineExpr, const SourceMgr &SM) const {
// Parse the numeric variable definition.
DefinedNumericVariable = None;
size_t DefEnd = Expr.find(':');
@@ -259,12 +290,29 @@ Expected<FileCheckExpression *> FileCheckPattern::parseNumericSubstitutionBlock(
return ParseResult.takeError();
DefinedNumericVariable = *ParseResult;
- return Context->makeExpression(add, nullptr, 0);
+ return nullptr;
}
// Parse the expression itself.
Expr = Expr.ltrim(SpaceChars);
- return parseBinop(Expr, SM);
+ // The first operand in a legacy @LINE expression is always the @LINE pseudo
+ // variable.
+ AllowedOperand AO =
+ IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
+ Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
+ parseNumericOperand(Expr, AO, SM);
+ while (ParseResult && !Expr.empty()) {
+ ParseResult =
+ parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, SM);
+ // Legacy @LINE expressions only allow 2 operands.
+ if (ParseResult && IsLegacyLineExpr && !Expr.empty())
+ return FileCheckErrorDiagnostic::get(
+ SM, Expr,
+ "unexpected characters at end of expression '" + Expr + "'");
+ }
+ if (!ParseResult)
+ return ParseResult;
+ return std::move(*ParseResult);
}
bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
@@ -375,12 +423,15 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
PatternStr = UnparsedPatternStr.substr(End + 2);
bool IsDefinition = false;
+ // Whether the substitution block is a legacy use of @LINE with string
+ // substitution block syntax.
+ bool IsLegacyLineExpr = false;
StringRef DefName;
StringRef SubstStr;
StringRef MatchRegexp;
size_t SubstInsertIdx = RegExStr.size();
- // Parse string variable or legacy expression.
+ // Parse string variable or legacy @LINE expression.
if (!IsNumBlock) {
size_t VarEndIdx = MatchStr.find(":");
size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
@@ -391,15 +442,15 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
}
// Get the name (e.g. "foo") and verify it is well formed.
- bool IsPseudo;
StringRef OrigMatchStr = MatchStr;
- Expected<StringRef> ParseVarResult =
- parseVariable(MatchStr, IsPseudo, SM);
+ Expected<FileCheckPattern::VariableProperties> ParseVarResult =
+ parseVariable(MatchStr, SM);
if (!ParseVarResult) {
logAllUnhandledErrors(ParseVarResult.takeError(), errs());
return true;
}
- StringRef Name = *ParseVarResult;
+ StringRef Name = ParseVarResult->Name;
+ bool IsPseudo = ParseVarResult->IsPseudo;
IsDefinition = (VarEndIdx != StringRef::npos);
if (IsDefinition) {
@@ -424,23 +475,24 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
} else {
if (IsPseudo) {
MatchStr = OrigMatchStr;
- IsNumBlock = true;
+ IsLegacyLineExpr = IsNumBlock = true;
} else
SubstStr = Name;
}
}
// Parse numeric substitution block.
- FileCheckExpression *Expression;
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST;
Optional<FileCheckNumericVariable *> DefinedNumericVariable;
if (IsNumBlock) {
- Expected<FileCheckExpression *> ParseResult =
- parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, SM);
+ Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
+ parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
+ IsLegacyLineExpr, SM);
if (!ParseResult) {
logAllUnhandledErrors(ParseResult.takeError(), errs());
return true;
}
- Expression = *ParseResult;
+ ExpressionAST = std::move(*ParseResult);
if (DefinedNumericVariable) {
IsDefinition = true;
DefName = (*DefinedNumericVariable)->getName();
@@ -468,8 +520,8 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
// previous CHECK patterns, and substitution of expressions.
FileCheckSubstitution *Substitution =
IsNumBlock
- ? Context->makeNumericSubstitution(SubstStr, Expression,
- SubstInsertIdx)
+ ? Context->makeNumericSubstitution(
+ SubstStr, std::move(ExpressionAST), SubstInsertIdx)
: Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
Substitutions.push_back(Substitution);
}
@@ -660,7 +712,7 @@ void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
Expected<std::string> MatchedValue = Substitution->getResult();
// Substitution failed or is not known at match time, print the undefined
- // variable it uses.
+ // variables it uses.
if (!MatchedValue) {
bool UndefSeen = false;
handleAllErrors(MatchedValue.takeError(),
@@ -669,13 +721,11 @@ void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
[](const FileCheckErrorDiagnostic &E) {},
[&](const FileCheckUndefVarError &E) {
if (!UndefSeen) {
- OS << "uses undefined variable ";
+ OS << "uses undefined variable(s):";
UndefSeen = true;
}
+ OS << " ";
E.log(OS);
- },
- [](const ErrorInfoBase &E) {
- llvm_unreachable("Unexpected error");
});
} else {
// Substitution succeeded. Print substituted value.
@@ -768,15 +818,6 @@ FileCheckPatternContext::getPatternVarValue(StringRef VarName) {
return VarIter->second;
}
-FileCheckExpression *
-FileCheckPatternContext::makeExpression(binop_eval_t EvalBinop,
- FileCheckNumericVariable *OperandLeft,
- uint64_t OperandRight) {
- Expressions.push_back(llvm::make_unique<FileCheckExpression>(
- EvalBinop, OperandLeft, OperandRight));
- return Expressions.back().get();
-}
-
template <class... Types>
FileCheckNumericVariable *
FileCheckPatternContext::makeNumericVariable(Types... args) {
@@ -794,10 +835,10 @@ FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
}
FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(
- StringRef ExpressionStr, FileCheckExpression *Expression,
- size_t InsertIdx) {
+ StringRef ExpressionStr,
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) {
Substitutions.push_back(llvm::make_unique<FileCheckNumericSubstitution>(
- this, ExpressionStr, Expression, InsertIdx));
+ this, ExpressionStr, std::move(ExpressionAST), InsertIdx));
return Substitutions.back().get();
}
@@ -1777,9 +1818,8 @@ Error FileCheckPatternContext::defineCmdlineVariables(
std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
StringRef CmdlineName = CmdlineNameVal.first;
StringRef OrigCmdlineName = CmdlineName;
- bool IsPseudo;
- Expected<StringRef> ParseVarResult =
- FileCheckPattern::parseVariable(CmdlineName, IsPseudo, SM);
+ Expected<FileCheckPattern::VariableProperties> ParseVarResult =
+ FileCheckPattern::parseVariable(CmdlineName, SM);
if (!ParseVarResult) {
Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());
continue;
@@ -1787,7 +1827,7 @@ Error FileCheckPatternContext::defineCmdlineVariables(
// Check that CmdlineName does not denote a pseudo variable is only
// composed of the parsed numeric variable. This catches cases like
// "FOO+2" in a "FOO+2=10" definition.
- if (IsPseudo || !CmdlineName.empty()) {
+ if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {
Errs = joinErrors(std::move(Errs),
FileCheckErrorDiagnostic::get(
SM, OrigCmdlineName,
@@ -1795,7 +1835,7 @@ Error FileCheckPatternContext::defineCmdlineVariables(
OrigCmdlineName + "'"));
continue;
}
- StringRef Name = *ParseVarResult;
+ StringRef Name = ParseVarResult->Name;
// Detect collisions between string and numeric variables when the former
// is created later than the latter.
OpenPOWER on IntegriCloud