[llvm] 47934c7 - FileCheck [11/12]: Add matching constraint specification

Thomas Preud'homme via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 07:56:39 PDT 2020


Author: Thomas Preud'homme
Date: 2020-06-10T15:56:10+01:00
New Revision: 47934c7cf9f6c18e21a34f9324680652214f771e

URL: https://github.com/llvm/llvm-project/commit/47934c7cf9f6c18e21a34f9324680652214f771e
DIFF: https://github.com/llvm/llvm-project/commit/47934c7cf9f6c18e21a34f9324680652214f771e.diff

LOG: FileCheck [11/12]: Add matching constraint specification

This patch is part of a patch series to add support for FileCheck
numeric expressions. This specific patch adds support for specifying the
matching constraint for a numeric expression, ie. how the value being
matched should relate to the numeric expression.

This commit only adds the equality constraint where the numeric value
matched must be equal to the numeric expression. It is the default
matching constraint used when not specified. It is added to provision
other matching constraint (e.g. inequality relations).

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)

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D60391

Added: 
    

Modified: 
    llvm/docs/CommandGuide/FileCheck.rst
    llvm/lib/Support/FileCheck.cpp
    llvm/lib/Support/FileCheckImpl.h
    llvm/test/FileCheck/line-count.txt
    llvm/test/FileCheck/numeric-expression.txt
    llvm/unittests/Support/FileCheckTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst
index 8199258a2d1d..0f72b41b20c2 100644
--- a/llvm/docs/CommandGuide/FileCheck.rst
+++ b/llvm/docs/CommandGuide/FileCheck.rst
@@ -670,7 +670,8 @@ For example:
 would match ``mov r5, 0xF0F0`` and set ``REG`` to the value ``5`` and ``IMM``
 to the value ``0xF0F0``.
 
-The syntax of a numeric substitution is ``[[#%<fmtspec>,<expr>]]`` where:
+The syntax of a numeric substitution is
+``[[#%<fmtspec>: <constraint> <expr>]]`` where:
 
 * ``%<fmtspec>`` is the same matching format specifier as for defining numeric
   variables but acting as a printf-style format to indicate how a numeric
@@ -680,6 +681,12 @@ The syntax of a numeric substitution is ``[[#%<fmtspec>,<expr>]]`` where:
   is used.  In case of conflict between matching formats of several numeric
   variables the format specifier is mandatory.
 
+* ``<constraint>`` is the constraint describing how the value to match must
+  relate to the value of the numeric expression. The only currently accepted
+  constraint is ``==`` for an exact match and is the default if
+  ``<constraint>`` is not provided. No matching constraint must be specified
+  when the ``<expr>`` is empty.
+
 * ``<expr>`` is an expression. An expression is in turn recursively defined
   as:
 
@@ -747,11 +754,12 @@ does not matter:
 to check that a value is synthesized rather than moved around.
 
 A numeric variable can also be defined to the result of a numeric expression,
-in which case the numeric expression is checked and if verified the variable is
-assigned to the value. The unified syntax for both defining numeric variables
-and checking a numeric expression is thus ``[[#%<fmtspec>,<NUMVAR>: <expr>]]``
-with each element as described previously. One can use this syntax to make a
-testcase more self-describing by using variables instead of values:
+in which case the numeric expression constraint is checked and if verified the
+variable is assigned to the value. The unified syntax for both defining numeric
+variables and checking a numeric expression is thus
+``[[#%<fmtspec>,<NUMVAR>: <constraint> <expr>]]`` with each element as
+described previously. One can use this syntax to make a testcase more
+self-describing by using variables instead of values:
 
 .. code-block:: gas
 

diff  --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
index 4a797ead337e..fe4d641f3062 100644
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -448,8 +448,9 @@ Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse(
 }
 
 Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
-    StringRef &Expr, AllowedOperand AO, Optional<size_t> LineNumber,
-    FileCheckPatternContext *Context, const SourceMgr &SM) {
+    StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint,
+    Optional<size_t> LineNumber, FileCheckPatternContext *Context,
+    const SourceMgr &SM) {
   if (Expr.startswith("(")) {
     if (AO != AllowedOperand::Any)
       return ErrorDiagnostic::get(
@@ -497,8 +498,11 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
     return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()),
                                                SignedLiteralValue);
 
-  return ErrorDiagnostic::get(SM, Expr,
-                              "invalid operand format '" + Expr + "'");
+  return ErrorDiagnostic::get(
+      SM, Expr,
+      Twine("invalid ") +
+          (MaybeInvalidConstraint ? "matching constraint or " : "") +
+          "operand format");
 }
 
 Expected<std::unique_ptr<ExpressionAST>>
@@ -514,8 +518,9 @@ Pattern::parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber,
     return ErrorDiagnostic::get(SM, Expr, "missing operand in expression");
 
   // Note: parseNumericOperand handles nested opening parentheses.
-  Expected<std::unique_ptr<ExpressionAST>> SubExprResult =
-      parseNumericOperand(Expr, AllowedOperand::Any, LineNumber, Context, SM);
+  Expected<std::unique_ptr<ExpressionAST>> SubExprResult = parseNumericOperand(
+      Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber,
+      Context, SM);
   Expr = Expr.ltrim(SpaceChars);
   while (SubExprResult && !Expr.empty() && !Expr.startswith(")")) {
     StringRef OrigExpr = Expr;
@@ -568,7 +573,8 @@ Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr,
   AllowedOperand AO =
       IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any;
   Expected<std::unique_ptr<ExpressionAST>> RightOpResult =
-      parseNumericOperand(RemainingExpr, AO, LineNumber, Context, SM);
+      parseNumericOperand(RemainingExpr, AO, /*MaybeInvalidConstraint=*/false,
+                          LineNumber, Context, SM);
   if (!RightOpResult)
     return RightOpResult;
 
@@ -606,8 +612,9 @@ Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName,
 
     // Parse the argument, which is an arbitary expression.
     StringRef OuterBinOpExpr = Expr;
-    Expected<std::unique_ptr<ExpressionAST>> Arg =
-        parseNumericOperand(Expr, AllowedOperand::Any, LineNumber, Context, SM);
+    Expected<std::unique_ptr<ExpressionAST>> Arg = parseNumericOperand(
+        Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber,
+        Context, SM);
     while (Arg && !Expr.empty()) {
       Expr = Expr.ltrim(SpaceChars);
       // Have we reached an argument terminator?
@@ -702,17 +709,27 @@ Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock(
     Expr = Expr.substr(DefEnd + 1);
   }
 
+  // Parse matching constraint.
+  Expr = Expr.ltrim(SpaceChars);
+  bool HasParsedValidConstraint = false;
+  if (Expr.consume_front("=="))
+    HasParsedValidConstraint = true;
+
   // Parse the expression itself.
   Expr = Expr.ltrim(SpaceChars);
-  if (!Expr.empty()) {
+  if (Expr.empty()) {
+    if (HasParsedValidConstraint)
+      return ErrorDiagnostic::get(
+          SM, Expr, "empty numeric expression should not have a constraint");
+  } else {
     Expr = Expr.rtrim(SpaceChars);
     StringRef OuterBinOpExpr = Expr;
     // 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<ExpressionAST>> ParseResult =
-        parseNumericOperand(Expr, AO, LineNumber, Context, SM);
+    Expected<std::unique_ptr<ExpressionAST>> ParseResult = parseNumericOperand(
+        Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM);
     while (ParseResult && !Expr.empty()) {
       ParseResult = parseBinop(OuterBinOpExpr, Expr, std::move(*ParseResult),
                                IsLegacyLineExpr, LineNumber, Context, SM);

diff  --git a/llvm/lib/Support/FileCheckImpl.h b/llvm/lib/Support/FileCheckImpl.h
index d3bc32be58a4..c909316f4171 100644
--- a/llvm/lib/Support/FileCheckImpl.h
+++ b/llvm/lib/Support/FileCheckImpl.h
@@ -728,13 +728,14 @@ class Pattern {
   /// Parses \p Expr for use of a numeric operand at line \p LineNumber, or
   /// before input is parsed if \p LineNumber is None. Accepts literal values,
   /// numeric variables and function calls, depending on the value of \p AO.
-  /// Parameter \p Context points to the class instance holding the live string
-  /// and numeric variables. \returns the class representing that operand in the
-  /// AST of the expression or an error holding a diagnostic against \p SM
-  /// otherwise. If \p Expr starts with a "(" this function will attempt to
-  /// parse a parenthesized expression.
+  /// \p MaybeInvalidConstraint indicates whether the text being parsed could
+  /// be an invalid constraint. \p Context points to the class instance holding
+  /// the live string and numeric variables. \returns the class representing
+  /// that operand in the AST of the expression or an error holding a
+  /// diagnostic against \p SM otherwise. If \p Expr starts with a "(" this
+  /// function will attempt to parse a parenthesized expression.
   static Expected<std::unique_ptr<ExpressionAST>>
-  parseNumericOperand(StringRef &Expr, AllowedOperand AO,
+  parseNumericOperand(StringRef &Expr, AllowedOperand AO, bool ConstraintParsed,
                       Optional<size_t> LineNumber,
                       FileCheckPatternContext *Context, const SourceMgr &SM);
   /// Parses and updates \p RemainingExpr for a binary operation at line

diff  --git a/llvm/test/FileCheck/line-count.txt b/llvm/test/FileCheck/line-count.txt
index 0f98a2a43419..01959aa7c4d0 100644
--- a/llvm/test/FileCheck/line-count.txt
+++ b/llvm/test/FileCheck/line-count.txt
@@ -50,31 +50,33 @@
 50 ERR9: line-count.txt:[[#@LINE-1]]:17: error: unsupported operation '*'
 51
 52 BAD10: [[@LINE-x]]
-53 ERR10: line-count.txt:[[#@LINE-1]]:19: error: invalid operand format 'x'
-54
-55 BAD11: [[@LINE-1x]]
-56 ERR11: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of expression 'x'
-57
+53 ERR10: line-count.txt:[[#@LINE-1]]:19: error: invalid operand format
+54 ERR10-NEXT: 52 {{B}}AD10: {{\[\[@LINE-x\]\]}}
+55 ERR10-NEXT:        {{^}}              ^{{$}}
+56
+57 BAD11: [[@LINE-1x]]
+58 ERR11: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of expression 'x'
+59
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -check-prefix BAD12 -input-file %s %s 2>&1 \
 ; RUN:   | FileCheck -check-prefix ERR12 %s
-61
-62 BAD12: [[#@LINE-1]] NOT HERE
-63 ERR12: note: with "@LINE-1" equal to "61"
-64
+63
+64 BAD12: [[#@LINE-1]] NOT HERE
+65 ERR12: note: with "@LINE-1" equal to "63"
+66
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck --check-prefix BAD13 --input-file %s %s 2>&1 \
 ; RUN:   | FileCheck --check-prefix ERR13 %s
-68
-69 BAD13: [[@LINE-0xA]]
-70 ERR13: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of expression 'xA'
-71
-72 CHECK: [[#@LINE]] CHECK
-73 CHECK: [[# @LINE]] CHECK
-74 CHECK: [[# @LINE ]] CHECK
-75
-76 CHECK: [[#@LINE-1]]
-77 CHECK: [[# @LINE-1]] CHECK
-78 CHECK: [[# @LINE -1]] CHECK
-79 CHECK: [[# @LINE - 1]] CHECK
-80 CHECK: [[# @LINE - 1 ]] CHECK
+70
+71 BAD13: [[@LINE-0xA]]
+72 ERR13: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of expression 'xA'
+73
+74 CHECK: [[#@LINE]] CHECK
+75 CHECK: [[# @LINE]] CHECK
+76 CHECK: [[# @LINE ]] CHECK
+77
+78 CHECK: [[#@LINE-1]]
+79 CHECK: [[# @LINE-1]] CHECK
+80 CHECK: [[# @LINE -1]] CHECK
+81 CHECK: [[# @LINE - 1]] CHECK
+82 CHECK: [[# @LINE - 1 ]] CHECK

diff  --git a/llvm/test/FileCheck/numeric-expression.txt b/llvm/test/FileCheck/numeric-expression.txt
index aca8b9d303c9..7859e208d8d9 100644
--- a/llvm/test/FileCheck/numeric-expression.txt
+++ b/llvm/test/FileCheck/numeric-expression.txt
@@ -154,6 +154,54 @@ USE IMPL FMT IMPL MATCH UNSIGNED IMM
 CHECK-LABEL: USE IMPL FMT IMPL MATCH UNSIGNED IMM
 CHECK-NEXT: [[#UNSI+0x8000000000000000]]
 
+; Numeric expressions in default matching format and explicit matching rule using
+; variables defined on other lines.
+USE DEF FMT EXPL MATCH  // CHECK-LABEL: USE DEF FMT EXPL MATCH
+11  // CHECK-NEXT: {{^}}[[#==UNSI]]
+11  // CHECK-NEXT: {{^}}[[# == UNSI]]
+12  // CHECK-NEXT: {{^}}[[#UNSI2: == UNSI + 1]]
+12  // CHECK-NEXT: {{^}}[[#==UNSI2]]
+
+; Numeric expressions in default matching format and explicit matching rule using
+; variable defined on other lines with match failure.
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck --check-prefix NUMEXPR-CONSTRAINT-NOMATCH --input-file %s %s 2>&1 \
+RUN:   | FileCheck --check-prefix NUMEXPR-CONSTRAINT-NOMATCH-MSG --strict-whitespace %s
+
+USE DEF FMT EXPL NO MATCH
+12
+NUMEXPR-CONSTRAINT-NOMATCH-LABEL: USE DEF FMT EXPL NO MATCH
+NUMEXPR-CONSTRAINT-NOMATCH-NEXT: [[#==UNSI]]
+NUMEXPR-CONSTRAINT-NOMATCH-MSG: numeric-expression.txt:[[#@LINE-1]]:34: error: {{N}}UMEXPR-CONSTRAINT-NOMATCH-NEXT: expected string not found in input
+NUMEXPR-CONSTRAINT-NOMATCH-MSG-NEXT: {{N}}UMEXPR-CONSTRAINT-NOMATCH-NEXT: {{\[\[#==UNSI\]\]}}
+NUMEXPR-CONSTRAINT-NOMATCH-MSG-NEXT:   {{^}}                                 ^{{$}}
+
+; Empty numeric expression with matching constraint.
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck --check-prefix EMPTY-NUMEXPR-CONSTRAINT --input-file %s %s 2>&1 \
+RUN:   | FileCheck --check-prefix EMPTY-NUMEXPR-CONSTRAINT-MSG --strict-whitespace %s
+
+EMPTY NUMEXPR USE WITH CONSTRAINT
+18
+EMPTY-NUMEXPR-CONSTRAINT-LABEL: EMPTY NUMEXPR USE WITH CONSTRAINT
+EMPTY-NUMEXPR-CONSTRAINT-NEXT: [[# ==]]
+EMPTY-NUMEXPR-CONSTRAINT-MSG: numeric-expression.txt:[[#@LINE-1]]:38: error: empty numeric expression should not have a constraint
+EMPTY-NUMEXPR-CONSTRAINT-MSG-NEXT: {{E}}MPTY-NUMEXPR-CONSTRAINT-NEXT: {{\[\[# ==\]\]}}
+EMPTY-NUMEXPR-CONSTRAINT-MSG-NEXT:     {{^}}                                     ^{{$}}
+
+; Definition from empty numeric expression with matching constraint.
+RUN: %ProtectFileCheckOutput \
+RUN: not FileCheck --check-prefix EMPTY-NUMDEF-CONSTRAINT --input-file %s %s 2>&1 \
+RUN:   | FileCheck --check-prefix EMPTY-NUMDEF-CONSTRAINT-MSG %s
+
+EMPTY NUMEXPR DEF WITH CONSTRAINT
+18
+EMPTY-NUMDEF-CONSTRAINT-LABEL: EMPTY NUMEXPR CONSTRAINT
+EMPTY-NUMDEF-CONSTRAINT-NEXT: [[#VARDEF: ==]]
+EMPTY-NUMDEF-CONSTRAINT-MSG: numeric-expression.txt:[[#@LINE-1]]:44: error: empty numeric expression should not have a constraint
+EMPTY-NUMDEF-CONSTRAINT-MSG-NEXT: {{E}}MPTY-NUMDEF-CONSTRAINT-NEXT: {{\[\[#VARDEF: ==\]\]}}
+EMPTY-NUMDEF-CONSTRAINT-MSG-NEXT:     {{^}}                                           ^{{$}}
+
 ; Numeric expressions with matching format overriding the implicit format of
 ; variables defined on other lines.
 USE CONV FMT IMPL MATCH  // CHECK-LABEL: USE CONV FMT IMPL MATCH

diff  --git a/llvm/unittests/Support/FileCheckTest.cpp b/llvm/unittests/Support/FileCheckTest.cpp
index 6cdb5f1b94b8..376313043ff3 100644
--- a/llvm/unittests/Support/FileCheckTest.cpp
+++ b/llvm/unittests/Support/FileCheckTest.cpp
@@ -902,7 +902,7 @@ TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
   Tester.initNextPattern();
 
   // Invalid variable name.
-  expectDiagnosticError("invalid operand format '%VAR'",
+  expectDiagnosticError("invalid matching constraint or operand format",
                         Tester.parseSubst("%VAR").takeError());
 
   expectDiagnosticError("invalid pseudo numeric variable '@FOO'",
@@ -937,6 +937,10 @@ TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
   // Valid empty expression.
   EXPECT_THAT_EXPECTED(Tester.parseSubst(""), Succeeded());
 
+  // Invalid equality matching constraint with empty expression.
+  expectDiagnosticError("empty numeric expression should not have a constraint",
+                        Tester.parseSubst("==").takeError());
+
   // Valid single operand expression.
   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO"), Succeeded());
   EXPECT_THAT_EXPECTED(Tester.parseSubst("18"), Succeeded());
@@ -947,6 +951,13 @@ TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
   EXPECT_THAT_EXPECTED(Tester.parseSubst(std::to_string(MinInt64)),
                        Succeeded());
 
+  // Valid optional matching constraint.
+  EXPECT_THAT_EXPECTED(Tester.parseSubst("==FOO"), Succeeded());
+
+  // Invalid matching constraint.
+  expectDiagnosticError("invalid matching constraint or operand format",
+                        Tester.parseSubst("+=FOO").takeError());
+
   // Invalid format.
   expectDiagnosticError("invalid matching format specification in expression",
                         Tester.parseSubst("X,FOO:").takeError());
@@ -968,12 +979,12 @@ TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
 
   // Errors in RHS operand are bubbled up by parseBinop() to
   // parseNumericSubstitutionBlock().
-  expectDiagnosticError("invalid operand format '%VAR'",
+  expectDiagnosticError("invalid operand format",
                         Tester.parseSubst("@LINE+%VAR").takeError());
 
   // Invalid legacy @LINE expression with non literal rhs.
   expectDiagnosticError(
-      "invalid operand format '@LINE'",
+      "invalid operand format",
       Tester.parseSubst("@LINE+ at LINE", /*IsLegacyNumExpr=*/true).takeError());
 
   // Invalid legacy @LINE expression made of a single literal.
@@ -1046,7 +1057,7 @@ TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
 
   // Test more closing than opening parentheses. The diagnostic messages are
   // not ideal, but for now simply check that we reject invalid input.
-  expectDiagnosticError("invalid operand format ')'",
+  expectDiagnosticError("invalid matching constraint or operand format",
                         Tester.parseSubst(")").takeError());
   expectDiagnosticError("unsupported operation ')'",
                         Tester.parseSubst("1)").takeError());


        


More information about the llvm-commits mailing list