diff --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst --- a/llvm/docs/CommandGuide/FileCheck.rst +++ b/llvm/docs/CommandGuide/FileCheck.rst @@ -598,7 +598,8 @@ would match ``mov r5, 0xF0F0`` and set ``REG`` to the value ``5`` and ``IMM`` to the value ``61680``. -The syntax of a numeric substitution is ``[[#%:]]`` where: +The syntax of a numeric substitution is +``[[#%: ]]`` where: * ``%`` is the same matching format specifier as for defining numeric variables but acting as a printf-style format to indicate how a numeric @@ -608,6 +609,12 @@ if no numeric variable is used. In case of conflict between matching formats of several numeric variables the format specifier is mandatory. +* ```` is the matching 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 + ```` is not provided. No matching constraint must be specified + when the ```` is empty. + * ```` is an expression. An expression is in turn recursively defined as: 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 @@ -329,9 +329,10 @@ StringRef SpaceChars = " \t"; // Parsing helper function that strips the string in SkipStr from S. Returns -// true if string SkipStr was not in S. Returns false otherwise. -static bool stripFront(StringRef &S, const StringRef &SkipStr) { - return !S.consume_front(SkipStr); +// true if string SkipStr was not in S and Optional was false. Returns false +// otherwise. +static bool stripFront(StringRef &S, const StringRef &SkipStr, bool Optional) { + return !S.consume_front(SkipStr) && !Optional; } // Parsing helper function that strips the first character in S and returns it. @@ -493,7 +494,7 @@ size_t FormatSpecEnd = Expr.find(','); if (FormatSpecEnd != StringRef::npos) { Expr = Expr.ltrim(SpaceChars); - if (stripFront(Expr, "%")) + if (stripFront(Expr, "%", /*Optional=*/false)) return FileCheckErrorDiagnostic::get( SM, Expr, "invalid matching format specification in expression"); @@ -519,7 +520,7 @@ } Expr = Expr.ltrim(SpaceChars); - if (stripFront(Expr, ",")) + if (stripFront(Expr, ",", /*Optional=*/false)) return FileCheckErrorDiagnostic::get( SM, Expr, "invalid matching format specification in expression"); } @@ -531,10 +532,19 @@ Expr = Expr.substr(DefEnd + 1); } + // Parse matching constraint. + Expr = Expr.ltrim(SpaceChars); + StringRef ConstraintExpr = Expr; + if (stripFront(Expr, "==", /*Optional=*/true)) + return FileCheckErrorDiagnostic::get(SM, Expr, "invalid matching constraint"); + // Parse the expression itself. Expr = Expr.ltrim(SpaceChars); StringRef UseExpr = Expr; - if (!Expr.empty()) { + if (Expr.empty()) { + if (Expr.size() != ConstraintExpr.size()) + return FileCheckErrorDiagnostic::get(SM, Expr, "Empty numeric expression should not have a matching constraint"); + } else { // First operand in legacy @LINE expression is the @LINE pseudo variable. AllowedOperand AO = LegacyLineExpr ? LineVar : Any; Expected> ParseResult = 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 @@ -183,6 +183,17 @@ CHECK-LABEL: USE IMPL FMT IMPL MATCH UNSIGNED IMM CHECK-NEXT: [[#VAR1+0x8000000000000000]] +; Numeric expressions in default matching format and explicit matching rule using +; variables defined on other lines +USE DEF FMT EXPL MATCH +11 +11 +11 +; CHECK-LABEL: USE DEF FMT EXPL MATCH +; CHECK-NEXT: [[#==VAR1]] +; CHECK-NEXT: [[# ==VAR1]] +; CHECK-NEXT: [[# == VAR1]] + ; Numeric expressions with conversion matching format and implicit matching rule ; using variables defined on other lines USE CONV FMT IMPL MATCH @@ -329,7 +340,6 @@ FMT-CONFLICT-MSG-NEXT: {{F}}MT-CONFLICT-NEXT: {{\[\[#VAR1 \+ VAR2\]\]}} FMT-CONFLICT-MSG-NEXT: {{^ \^$}} - ; Numeric expression with overflow RUN: not FileCheck -check-prefix OVERFLOW -input-file %s %s 2>&1 \ RUN: | FileCheck -check-prefix OVERFLOW-MSG %s @@ -342,7 +352,6 @@ OVERFLOW-MSG-NEXT: {{O}}VERFLOW-NEXT: BIGVAR: {{\[\[#BIGVAR:0x8000000000000000\+0x8000000000000000\]\]}} OVERFLOW-MSG-NEXT: {{^ \^$}} - ; Numeric expression with underflow RUN: not FileCheck -check-prefix UNDERFLOW -input-file %s %s 2>&1 \ RUN: | FileCheck -check-prefix UNDERFLOW-MSG %s @@ -354,3 +363,27 @@ UNDERFLOW-MSG: numeric-expression.txt:[[#@LINE-1]]:29: error: Unable to substitute variable or numeric expression UNDERFLOW-MSG-NEXT: {{U}}NDERFLOW-NEXT: TINYVAR: {{\[\[#%d,TINYVAR:-0x8000000000000000-0x8000000000000000\]\]}} UNDERFLOW-MSG-NEXT: {{^ \^$}} + +; Empty numeric expression with matching constraint +RUN: not FileCheck -check-prefix EMPTY-NUMEXPR-CONSTRAINT -input-file %s %s 2>&1 \ +RUN: | FileCheck -check-prefix EMPTY-NUMEXPR-CONSTRAINT-MSG %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 matching constraint +EMPTY-NUMEXPR-CONSTRAINT-MSG-NEXT: {{E}}MPTY-NUMEXPR-CONSTRAINT-NEXT: {{\[\[# ==\]\]}} +EMPTY-NUMEXPR-CONSTRAINT-MSG-NEXT: {{^ \^$}} + +; Empty numeric expression with matching constraint +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 matching constraint +EMPTY-NUMDEF-CONSTRAINT-MSG-NEXT: {{E}}MPTY-NUMDEF-CONSTRAINT-NEXT: {{\[\[#VARDEF: ==\]\]}} +EMPTY-NUMDEF-CONSTRAINT-MSG-NEXT: {{^ \^$}}