Skip to content

Commit

Permalink
FileCheck: Improve FileCheck variable terminology
Browse files Browse the repository at this point in the history
Summary:
Terminology introduced by [[#]] blocks is confusing and does not
integrate well with existing terminology.

First, variables referred by [[]] blocks are called "pattern variables"
while the text a CHECK directive needs to match is called a "CHECK
pattern". This is inconsistent with variables in [[#]] blocks since
[[#]] blocks are also found in CHECK pattern yet those variables are
called "numeric variable".

Second, the replacing of both [[]] and [[#]] blocks by the value of the
variable or expression they contain is represented by a
FileCheckPatternSubstitution class. The naming refers to being a
substitution in a CHECK pattern but could be wrongly understood as being
a substitution of a pattern variable.

Third and lastly, comments use "numeric expression" to refer both to the
[[#]] blocks as well as to the numeric expressions these blocks contain
which get evaluated at match time.

This patch solves these confusions by
- calling variables in [[]] and [[#]] blocks as string and numeric
  variables respectively;
- referring to [[]] and [[#]] as substitution *blocks*, with the former
  being a string substitution block and the latter a numeric
  substitution block;
- calling [[]] and [[#]] blocks to be replaced by the value of a
  variable or expression they contain a substitution (as opposed to
  definition when these blocks are used to defined a variable), with the
  former being a string substitution and the latter a numeric
  substitution;
- renaming the FileCheckPatternSubstitution as a FileCheckSubstitution
  class with FileCheckStringSubstitution and
  FileCheckNumericSubstitution subclasses;
- restricting the use of "numeric expression" to refer to the expression
  that is evaluated in a numeric substitution.

While numeric substitution blocks only support numeric substitutions of
numeric expressions at the moment there are plans to augment numeric
substitution blocks to support numeric definitions as well as both a
numeric definition and numeric substitution in the same numeric
substitution block.

Reviewers: jhenderson, jdenny, probinson, arichardson

Subscribers: hiraditya, arichardson, probinson, llvm-commits

Tags: #llvm

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

llvm-svn: 361445
  • Loading branch information
Thomas Preud'homme committed May 23, 2019
1 parent 33dbab8 commit 1a944d2
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 189 deletions.
63 changes: 35 additions & 28 deletions llvm/docs/CommandGuide/FileCheck.rst
Expand Up @@ -499,8 +499,8 @@ simply uniquely match a single line in the file being verified.

``CHECK-LABEL:`` directives cannot contain variable definitions or uses.

FileCheck Pattern Matching Syntax
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FileCheck Regex Matching Syntax
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

All FileCheck directives take a pattern to match.
For most uses of FileCheck, fixed string matching is perfectly sufficient. For
Expand All @@ -525,14 +525,15 @@ braces like you would in C. In the rare case that you want to match double
braces explicitly from the input, you can use something ugly like
``{{[{][{]}}`` as your pattern.

FileCheck Pattern Expressions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FileCheck String Substitution Blocks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It is often useful to match a pattern and then verify that it occurs again
later in the file. For codegen tests, this can be useful to allow any register,
but verify that that register is used consistently later. To do this,
:program:`FileCheck` supports pattern expressions that allow pattern variables
to be defined and substituted into patterns. Here is a simple example:
later in the file. For codegen tests, this can be useful to allow any
register, but verify that that register is used consistently later. To do
this, :program:`FileCheck` supports string substitution blocks that allow
string variables to be defined and substituted into patterns. Here is a simple
example:

.. code-block:: llvm
Expand All @@ -541,15 +542,16 @@ to be defined and substituted into patterns. Here is a simple example:
; CHECK: andw {{.*}}[[REGISTER]]
The first check line matches a regex ``%[a-z]+`` and captures it into the
variable ``REGISTER``. The second line verifies that whatever is in
``REGISTER`` occurs later in the file after an "``andw``". :program:`FileCheck`
variable references are always contained in ``[[ ]]`` pairs, and their names can
be formed with the regex ``[a-zA-Z_][a-zA-Z0-9_]*``. If a colon follows the name,
then it is a definition of the variable; otherwise, it is a use.
string variable ``REGISTER``. The second line verifies that whatever is in
``REGISTER`` occurs later in the file after an "``andw``". :program:`FileCheck`
string substitution blocks are always contained in ``[[ ]]`` pairs, and string
variable names can be formed with the regex ``[a-zA-Z_][a-zA-Z0-9_]*``. If a
colon follows the name, then it is a definition of the variable; otherwise, it
is a substitution.

:program:`FileCheck` variables can be defined multiple times, and uses always
get the latest value. Variables can also be used later on the same line they
were defined on. For example:
:program:`FileCheck` variables can be defined multiple times, and substitutions
always get the latest value. Variables can also be substituted later on the
same line they were defined on. For example:

.. code-block:: llvm
Expand All @@ -565,16 +567,17 @@ CHECK-LABEL block. Global variables are not affected by CHECK-LABEL.
This makes it easier to ensure that individual tests are not affected
by variables set in preceding tests.

FileCheck Numeric Variables and Expressions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FileCheck Numeric Substitution Blocks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:program:`FileCheck` also allows checking for numeric values that satisfy a
numeric expression constraint based on numeric variables. This allows
``CHECK:`` directives to verify a numeric relation between two numbers, such as
the need for consecutive registers to be used.
:program:`FileCheck` also supports numeric substitution blocks that allow
checking for numeric values that satisfy a numeric expression constraint based
on numeric variables. This allows ``CHECK:`` directives to verify a numeric
relation between two numbers, such as the need for consecutive registers to be
used.

The syntax to check a numeric expression constraint is
``[[#<NUMVAR><op><offset>]]`` where:
The syntax of a numeric substitution block is ``[[#<NUMVAR><op><offset>]]``
where:

* ``<NUMVAR>`` is the name of a numeric variable defined on the command line.

Expand All @@ -585,6 +588,10 @@ The syntax to check a numeric expression constraint is
the numeric operation <op>. It must be present if ``<op>`` is present,
absent otherwise.

Spaces are accepted before, after and between any of these elements.

Unlike string substitution blocks, numeric substitution blocks only introduce
numeric substitutions which substitute a numeric expression for its value.
For example:

.. code-block:: llvm
Expand All @@ -606,7 +613,7 @@ but would not match the line:
due to ``7`` being unequal to ``5 + 1``.

The ``--enable-var-scope`` option has the same effect on numeric variables as
on pattern variables.
on string variables.

FileCheck Pseudo Numeric Variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -632,9 +639,9 @@ relative line number references, for example:
// CHECK-NEXT: {{^ ;}}
int a

To support legacy uses of ``@LINE`` as a special pattern variable,
:program:`FileCheck` also accepts the following uses of ``@LINE`` with pattern
variable syntax: ``[[@LINE]]``, ``[[@LINE+<offset>]]`` and
To support legacy uses of ``@LINE`` as a special string variable,
:program:`FileCheck` also accepts the following uses of ``@LINE`` with string
substitution block syntax: ``[[@LINE]]``, ``[[@LINE+<offset>]]`` and
``[[@LINE-<offset>]]`` without any spaces inside the brackets and where
``offset`` is an integer.

Expand Down
99 changes: 51 additions & 48 deletions llvm/include/llvm/Support/FileCheck.h
Expand Up @@ -37,7 +37,7 @@ struct FileCheckRequest {
};

//===----------------------------------------------------------------------===//
// Numeric expression handling code.
// Numeric substitution handling code.
//===----------------------------------------------------------------------===//

/// Class representing a numeric variable with a given value in a numeric
Expand Down Expand Up @@ -105,55 +105,58 @@ class FileCheckNumExpr {

class FileCheckPatternContext;

/// Class representing a substitution to perform in the string to match.
class FileCheckPatternSubstitution {
private:
/// Pointer to a class instance holding the table with the values of live
/// pattern variables at the start of any given CHECK line. Used for
/// substituting pattern variables (numeric variables have their value in the
/// FileCheckNumExpr class instance pointed to by NumExpr).
/// Class representing a substitution to perform in the RegExStr string.
class FileCheckSubstitution {
protected:
/// Pointer to a class instance holding, among other things, the table with
/// the values of live string variables at the start of any given CHECK line.
/// Used for substituting string variables with the text they were defined
/// as. Numeric expressions are linked to the numeric variables they use at
/// parse time and directly access the value of the numeric variable to
/// evaluate their value.
FileCheckPatternContext *Context;

/// Whether this represents a numeric expression substitution.
bool IsNumExpr;
bool IsNumSubst;

/// The string that needs to be substituted for something else. For a
/// pattern variable this is its name, otherwise this is the whole numeric
/// string variable this is its name, otherwise this is the whole numeric
/// expression.
StringRef FromStr;

/// If this is a numeric expression substitution, this is the pointer to the
/// class representing that numeric expression.
/// class representing the numeric expression whose value is to be
/// substituted.
FileCheckNumExpr *NumExpr = nullptr;

// Index in RegExStr of where to do the substitution.
size_t InsertIdx;

public:
/// Constructor for a pattern variable substitution.
FileCheckPatternSubstitution(FileCheckPatternContext *Context,
StringRef VarName, size_t InsertIdx)
: Context(Context), IsNumExpr(false), FromStr(VarName),
FileCheckSubstitution(FileCheckPatternContext *Context,
StringRef VarName, size_t InsertIdx)
: Context(Context), IsNumSubst(false), FromStr(VarName),
InsertIdx(InsertIdx) {}

/// Constructor for a numeric expression substitution.
FileCheckPatternSubstitution(FileCheckPatternContext *Context, StringRef Expr,
FileCheckNumExpr *NumExpr, size_t InsertIdx)
: Context(Context), IsNumExpr(true), FromStr(Expr), NumExpr(NumExpr),
FileCheckSubstitution(FileCheckPatternContext *Context, StringRef Expr,
FileCheckNumExpr *NumExpr, size_t InsertIdx)
: Context(Context), IsNumSubst(true), FromStr(Expr), NumExpr(NumExpr),
InsertIdx(InsertIdx) {}

/// \returns whether this is a numeric expression substitution.
bool isNumExpr() const { return IsNumExpr; }
bool isNumSubst() const { return IsNumSubst; }

/// \returns the string to be substituted.
/// \returns the string to be substituted for something else.
StringRef getFromString() const { return FromStr; }

/// \returns the index where the substitution is to be performed.
/// \returns the index where the substitution is to be performed in RegExStr.
size_t getIndex() const { return InsertIdx; }

/// \returns the result of the substitution represented by this class
/// instance or None if substitution failed. Numeric expressions are
/// substituted by their values. Pattern variables are simply replaced by the
/// substituted by their values. String variables are simply replaced by the
/// text their definition matched.
llvm::Optional<std::string> getResult() const;

Expand Down Expand Up @@ -216,14 +219,14 @@ class FileCheckPatternContext {
friend class FileCheckPattern;

private:
/// When matching a given pattern, this holds the value of all the FileCheck
/// pattern variables defined in previous patterns. In a pattern, only the
/// last definition for a given variable is recorded in this table.
/// When matching a given pattern, this holds the value of all the string
/// variables defined in previous patterns. In a pattern, only the last
/// definition for a given variable is recorded in this table.
/// Back-references are used for uses after any the other definition.
StringMap<StringRef> GlobalVariableTable;

/// Map of all pattern variables defined so far. Used at parse time to detect
/// a name conflict between a numeric variable and a pattern variable when
/// Map of all string variables defined so far. Used at parse time to detect
/// a name conflict between a numeric variable and a string variable when
/// the former is defined on a later line than the latter.
StringMap<bool> DefinedVariableTable;

Expand All @@ -243,19 +246,21 @@ class FileCheckPatternContext {
std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;

public:
/// \returns the value of pattern variable \p VarName or None if no such
/// \returns the value of string variable \p VarName or None if no such
/// variable has been defined.
llvm::Optional<StringRef> getPatternVarValue(StringRef VarName);

/// Defines pattern and numeric variables from definitions given on the
/// Defines string and numeric variables from definitions given on the
/// command line, passed as a vector of [#]VAR=VAL strings in
/// \p CmdlineDefines. Reports any error to \p SM and \returns whether an
/// error occured.
bool defineCmdlineVariables(std::vector<std::string> &CmdlineDefines,
SourceMgr &SM);

/// Undefines local variables (variables whose name does not start with a '$'
/// sign), i.e. removes them from GlobalVariableTable.
/// sign), i.e. removes them from GlobalVariableTable and from
/// GlobalNumericVariableTable and also clears the value of numeric
/// variables.
void clearLocalVars();

private:
Expand All @@ -281,17 +286,15 @@ class FileCheckPattern {
/// a fixed string to match.
std::string RegExStr;

/// Entries in this vector represent uses of a pattern variable or a numeric
/// expression in the pattern that need to be substituted in the regexp
/// pattern at match time, e.g. "foo[[bar]]baz[[#N+1]]". In this case, the
/// Entries in this vector represent a substitution of a string variable or a
/// numeric expression in the RegExStr regex at match time. For example, in
/// the case of a CHECK directive with the pattern "foo[[bar]]baz[[#N+1]]",
/// RegExStr will contain "foobaz" and we'll get two entries in this vector
/// that tells us to insert the value of pattern variable "bar" at offset 3
/// and the value of numeric expression "N+1" at offset 6. Uses are
/// represented by a FileCheckPatternSubstitution class to abstract whether
/// it is a pattern variable or a numeric expression.
std::vector<FileCheckPatternSubstitution> Substitutions;
/// that tells us to insert the value of string variable "bar" at offset 3
/// and the value of numeric expression "N+1" at offset 6.
std::vector<FileCheckSubstitution> Substitutions;

/// Maps names of pattern variables defined in a pattern to the parenthesized
/// Maps names of string variables defined in a pattern to the parenthesized
/// capture numbers of their last definition.
///
/// E.g. for the pattern "foo[[bar:.*]]baz[[bar]]quux[[bar:.*]]",
Expand All @@ -304,9 +307,9 @@ class FileCheckPattern {

/// Pointer to a class instance holding the global state shared by all
/// patterns:
/// - separate tables with the values of live pattern and numeric variables
/// - separate tables with the values of live string and numeric variables
/// respectively at the start of any given CHECK line;
/// - table holding whether a pattern variable has been defined at any given
/// - table holding whether a string variable has been defined at any given
/// point during the parsing phase.
FileCheckPatternContext *Context;

Expand Down Expand Up @@ -335,14 +338,14 @@ class FileCheckPattern {
/// character that is part of the variable name. Otherwise, only
/// \returns true.
static bool parseVariable(StringRef Str, bool &IsPseudo, unsigned &TrailIdx);
/// Parses a numeric expression involving (pseudo if \p IsPseudo is true)
/// Parses a numeric substitution involving (pseudo if \p IsPseudo is true)
/// variable \p Name with the string corresponding to the operation being
/// performed in \p Trailer. \returns the class representing the numeric
/// expression or nullptr if parsing fails in which case errors are reported
/// on \p SM.
FileCheckNumExpr *parseNumericExpression(StringRef Name, bool IsPseudo,
StringRef Trailer,
const SourceMgr &SM) const;
/// expression being substituted or nullptr if parsing fails, in which case
/// errors are reported on \p SM.
FileCheckNumExpr *parseNumericSubstitution(StringRef Name, bool IsPseudo,
StringRef Trailer,
const SourceMgr &SM) const;
/// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
/// instance accordingly.
///
Expand All @@ -361,11 +364,11 @@ class FileCheckPattern {
/// string.
///
/// The GlobalVariableTable StringMap in the FileCheckPatternContext class
/// instance provides the current values of FileCheck pattern variables and
/// instance provides the current values of FileCheck string variables and
/// is updated if this match defines new values.
size_t match(StringRef Buffer, size_t &MatchLen) const;
/// Prints the value of successful substitutions or the name of the undefined
/// pattern or numeric variable preventing such a successful substitution.
/// string or numeric variable preventing a successful substitution.
void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
SMRange MatchRange = None) const;
void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
Expand Down

0 comments on commit 1a944d2

Please sign in to comment.