diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp --- a/llvm/lib/Support/FileCheck.cpp +++ b/llvm/lib/Support/FileCheck.cpp @@ -273,6 +273,13 @@ Expected> Pattern::parseNumericOperand( StringRef &Expr, AllowedOperand AO, Optional LineNumber, FileCheckPatternContext *Context, const SourceMgr &SM) { + if (Expr.startswith("!")) { + if (AO != AllowedOperand::Any) + return ErrorDiagnostic::get( + SM, Expr, "function call not permitted here"); + return parseCallExpr(Expr, LineNumber, Context, SM); + } + if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) { // Try to parse as a numeric variable use. Expected ParseVarResult = @@ -308,6 +315,18 @@ return LeftOp - RightOp; } +static uint64_t umax(uint64_t LeftOp, uint64_t RightOp) { + return std::max(LeftOp, RightOp); +} + +static uint64_t umin(uint64_t LeftOp, uint64_t RightOp) { + return std::min(LeftOp, RightOp); +} + +static uint64_t umul(uint64_t LeftOp, uint64_t RightOp) { + return LeftOp * RightOp; +} + Expected> Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr, std::unique_ptr LeftOp, @@ -352,6 +371,77 @@ std::move(*RightOpResult)); } +Expected> +Pattern::parseCallExpr(StringRef &Expr, Optional LineNumber, + FileCheckPatternContext *Context, const SourceMgr &SM) { + Expr = Expr.ltrim(SpaceChars); // TODO: do I need this + assert(Expr.startswith("!")); + Expr.consume_front("!"); + + SMLoc OpLoc = SMLoc::getFromPointer(Expr.data()); + + size_t FuncNameEnd = Expr.find('('); + if (FuncNameEnd == StringRef::npos) + return ErrorDiagnostic::get( + SM, OpLoc, "missing '(' at start of call expression"); + + StringRef FuncName = Expr.take_front(FuncNameEnd); + auto OptFunc = StringSwitch>(FuncName) + .Case("umax", umax) + .Case("umin", umin) + .Case("umul", umul) + .Default(None); + + // @( is used to enforce operator precedence. + if (!OptFunc && (FuncName != "")) + return ErrorDiagnostic::get( + SM, OpLoc, Twine("unsupported function '") + FuncName + "'"); + + // String funcion name along with leading '('; + Expr = Expr.drop_front(FuncNameEnd + 1); + Expr = Expr.ltrim(SpaceChars); + + // TODO: what about end of string + SmallVector, 4> Args; + while (!Expr.startswith(")")) { + Expected> Arg = + parseNumericOperand(Expr, AllowedOperand::Any, LineNumber, Context, SM); + + if (!Arg) + return ErrorDiagnostic::get(SM, OpLoc, "bad call syntax - no arg"); + + Args.push_back(std::move(*Arg)); + Expr = Expr.ltrim(SpaceChars); + + if (!Expr.startswith(")") && !Expr.startswith(",")) + return ErrorDiagnostic::get(SM, OpLoc, Twine("bad call syntax - no seperator '") + Expr + "'"); + + if (Expr.consume_front(",")) + Expr = Expr.ltrim(SpaceChars); + } + + if (!Expr.consume_front(")")) + return ErrorDiagnostic::get( + SM, OpLoc, "missing ')' at end of call expression"); + + // @( is used to enforce operator precedence. + if (FuncName == "") { + if (Args.size() != 1) + return ErrorDiagnostic::get( + SM, OpLoc, Twine("invalid function signature '") + FuncName + "'"); + + return std::move(Args[0]); + } + + // TODO: support more signatuture types. + if (Args.size() != 2) + return ErrorDiagnostic::get( + SM, OpLoc, Twine("invalid function signature '") + FuncName + "'"); + + return std::make_unique(Expr, *OptFunc, std::move(Args[0]), + std::move(Args[1])); +} + Expected> Pattern::parseNumericSubstitutionBlock( StringRef Expr, Optional &DefinedNumericVariable, bool IsLegacyLineExpr, Optional LineNumber, diff --git a/llvm/lib/Support/FileCheckImpl.h b/llvm/lib/Support/FileCheckImpl.h --- a/llvm/lib/Support/FileCheckImpl.h +++ b/llvm/lib/Support/FileCheckImpl.h @@ -684,6 +684,11 @@ std::unique_ptr LeftOp, bool IsLegacyLineExpr, Optional LineNumber, FileCheckPatternContext *Context, const SourceMgr &SM); + + /// Complete me! + static Expected> + parseCallExpr(StringRef &Expr, Optional LineNumber, + FileCheckPatternContext *Context, const SourceMgr &SM); }; //===----------------------------------------------------------------------===// diff --git a/llvm/test/FileCheck/numeric-expression.txt b/llvm/test/FileCheck/numeric-expression.txt --- a/llvm/test/FileCheck/numeric-expression.txt +++ b/llvm/test/FileCheck/numeric-expression.txt @@ -67,6 +67,9 @@ 11 12 10 +10 +77 +99 c d b @@ -87,6 +90,11 @@ CHECK-NEXT: [[#%u,VAR1]] CHECK-NEXT: [[#%u,VAR1+1]] CHECK-NEXT: [[#%u,VAR1-1]] +CHECK-NEXT: [[#%u,!umin(VAR1,10)]] +CHECK-NEXT: [[#%u,!umul(VAR1,7)]] +CHECK-NEXT: [[#%u,!umax(VAR1,99)]] +UNDECIDED-NEXT: [[#%u,1 + VAR1 * 3]] +UNDECIDED-NEXT: [[#%u,1 + @(VAR1 * 3)]] CHECK-NEXT: [[#%x,VAR2]] CHECK-NEXT: [[#%x,VAR2+1]] CHECK-NEXT: [[#%x,VAR2-1]]