Skip to content

Commit

Permalink
FileCheck [6/12]: Introduce numeric variable definition
Browse files Browse the repository at this point in the history
Summary:
This patch is part of a patch series to add support for FileCheck
numeric expressions. This specific patch introduces support for defining
numeric variable in a CHECK directive.

This commit introduces support for defining numeric variable from a
litteral value in the input text. Numeric expressions can then use the
variable provided it is on a later line.

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/D60386

llvm-svn: 362705
  • Loading branch information
Thomas Preud'homme committed Jun 6, 2019
1 parent bf5bca5 commit 71d3f22
Show file tree
Hide file tree
Showing 8 changed files with 706 additions and 337 deletions.
49 changes: 32 additions & 17 deletions llvm/docs/CommandGuide/FileCheck.rst
Original file line number Diff line number Diff line change
Expand Up @@ -571,15 +571,26 @@ FileCheck Numeric Substitution Blocks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

: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.
defining numeric variables and checking for numeric values that satisfy a
numeric expression constraint based on those variables via a numeric
substitution. This allows ``CHECK:`` directives to verify a numeric relation
between two numbers, such as the need for consecutive registers to be used.

The syntax of a numeric substitution block is ``[[#<NUMVAR><op><offset>]]``
where:
The syntax to define a numeric variable is ``[[#<NUMVAR>:]]`` where
``<NUMVAR>`` is the name of the numeric variable to define to the matching
value.

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

.. code-block:: llvm
; CHECK: mov r[[#REG:]], 42
would match ``mov r5, 42`` and set ``REG`` to the value ``5``.

The syntax of a numeric substitution is ``[[#<NUMVAR><op><offset>]]`` where:

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

* ``<op>`` is an optional numeric operation to perform on the value of
``<NUMVAR>``. Currently supported numeric operations are ``+`` and ``-``.
Expand All @@ -590,31 +601,35 @@ where:

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
; CHECK: add r[[#REG]], r[[#REG]], r[[#REG+1]]
; CHECK: load r[[#REG:]], [r0]
; CHECK: load r[[#REG+1]], [r1]
The above example would match the line:
The above example would match the text:

.. code-block:: gas
add r5, r5, r6
load r5, [r0]
load r6, [r1]
but would not match the line:
but would not match the text:

.. code-block:: gas
add r5, r5, r7
load r5, [r0]
load r7, [r1]
due to ``7`` being unequal to ``5 + 1``.

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

Important note: In its current implementation, a numeric expression cannot use
a numeric variable defined on the same line.

FileCheck Pseudo Numeric Variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -624,9 +639,9 @@ fragility of the match file structure, as "``CHECK:``" lines contain absolute
line numbers in the same file, which have to be updated whenever line numbers
change due to text addition or deletion.

To support this case, FileCheck understands the ``@LINE`` pseudo numeric
variable which evaluates to the line number of the CHECK pattern where it is
found.
To support this case, FileCheck numeric expressions understand the ``@LINE``
pseudo numeric variable which evaluates to the line number of the CHECK pattern
where it is found.

This way match patterns can be put near the relevant test lines and include
relative line number references, for example:
Expand Down
134 changes: 97 additions & 37 deletions llvm/include/llvm/Support/FileCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ struct FileCheckRequest {
//===----------------------------------------------------------------------===//

/// Class representing a numeric variable with a given value in a numeric
/// expression.
/// expression. Each definition of a variable gets its own instance of this
/// class. Variable uses share the same instance as their respective
/// definition.
class FileCheckNumericVariable {
private:
/// Name of the numeric variable.
Expand All @@ -50,11 +52,19 @@ class FileCheckNumericVariable {
/// Value of numeric variable, if defined, or None otherwise.
Optional<uint64_t> Value;

/// Line number where this variable is defined. Used to determine whether a
/// variable is defined on the same line as a given use.
size_t DefLineNumber;

public:
/// Constructor for a variable \p Name defined at line \p DefLineNumber.
FileCheckNumericVariable(size_t DefLineNumber, StringRef Name)
: Name(Name), DefLineNumber(DefLineNumber) {}

/// Constructor for numeric variable \p Name with a known \p Value at parse
/// time (e.g. the @LINE numeric variable).
FileCheckNumericVariable(StringRef Name, uint64_t Value)
: Name(Name), Value(Value) {}
: Name(Name), Value(Value), DefLineNumber(0) {}

/// \returns name of that numeric variable.
StringRef getName() const { return Name; }
Expand All @@ -69,6 +79,9 @@ class FileCheckNumericVariable {
/// Clears value of this numeric variable. \returns whether the variable was
/// already undefined.
bool clearValue();

/// \returns the line number where this variable is defined.
size_t getDefLineNumber() { return DefLineNumber; }
};

/// Type of functions evaluating a given binary operation.
Expand Down Expand Up @@ -248,8 +261,11 @@ class FileCheckPatternContext {

/// When matching a given pattern, this holds the pointers to the classes
/// representing the last definitions of numeric variables defined in
/// previous patterns. Earlier definition of the variables, if any, have
/// their own class instance not referenced by this table.
/// previous patterns. Earlier definitions of the variables, if any, have
/// their own class instance not referenced by this table. When matching a
/// pattern all definitions for that pattern are recorded in the
/// NumericVariableDefs table in the FileCheckPattern instance of that
/// pattern.
StringMap<FileCheckNumericVariable *> GlobalNumericVariableTable;

/// Vector holding pointers to all parsed numeric expressions. Used to
Expand Down Expand Up @@ -292,7 +308,8 @@ class FileCheckPatternContext {

/// Makes a new numeric variable and registers it for destruction when the
/// context is destroyed.
FileCheckNumericVariable *makeNumericVariable(StringRef Name, uint64_t Value);
template <class... Types>
FileCheckNumericVariable *makeNumericVariable(Types... args);

/// Makes a new string substitution and registers it for destruction when the
/// context is destroyed.
Expand Down Expand Up @@ -325,17 +342,39 @@ class FileCheckPattern {
/// and the value of numeric expression "N+1" at offset 6.
std::vector<FileCheckSubstitution *> Substitutions;

/// Maps names of string variables defined in a pattern to the parenthesized
/// capture numbers of their last definition.
/// Maps names of string variables defined in a pattern to the number of
/// their parenthesis group in RegExStr capturing their last definition.
///
/// E.g. for the pattern "foo[[bar:.*]]baz[[bar]]quux[[bar:.*]]",
/// VariableDefs will map "bar" to 2 corresponding to the second definition
/// of "bar".
/// E.g. for the pattern "foo[[bar:.*]]baz([[bar]][[QUUX]][[bar:.*]])",
/// RegExStr will be "foo(.*)baz(\1<quux value>(.*))" where <quux value> is
/// the value captured for QUUX on the earlier line where it was defined, and
/// VariableDefs will map "bar" to the third parenthesis group which captures
/// the second definition of "bar".
///
/// Note: uses std::map rather than StringMap to be able to get the key when
/// iterating over values.
std::map<StringRef, unsigned> VariableDefs;

/// Structure representing the definition of a numeric variable in a pattern.
/// It holds the pointer to the class representing the numeric variable whose
/// value is being defined and the number of the parenthesis group in
/// RegExStr to capture that value.
struct FileCheckNumExprMatch {
/// Pointer to class representing the numeric variable whose value is being
/// defined.
FileCheckNumericVariable *DefinedNumericVariable;

/// Number of the parenthesis group in RegExStr that captures the value of
/// this numeric variable definition.
unsigned CaptureParenGroup;
};

/// Holds the number of the parenthesis group in RegExStr and pointer to the
/// corresponding FileCheckNumericVariable class instance of all numeric
/// variable definitions. Used to set the matched value of all those
/// variables.
StringMap<FileCheckNumExprMatch> NumericVariableDefs;

/// Pointer to a class instance holding the global state shared by all
/// patterns:
/// - separate tables with the values of live string and numeric variables
Expand All @@ -346,13 +385,14 @@ class FileCheckPattern {

Check::FileCheckType CheckTy;

/// Contains the number of line this pattern is in.
unsigned LineNumber;
/// Line number for this CHECK pattern. Used to determine whether a variable
/// definition is made on an earlier line to the one with this CHECK.
size_t LineNumber;

public:
explicit FileCheckPattern(Check::FileCheckType Ty,
FileCheckPatternContext *Context)
: Context(Context), CheckTy(Ty) {}
FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context,
size_t Line)
: Context(Context), CheckTy(Ty), LineNumber(Line) {}

/// \returns the location in source code.
SMLoc getLoc() const { return PatternLoc; }
Expand All @@ -363,31 +403,37 @@ class FileCheckPattern {

/// \returns whether \p C is a valid first character for a variable name.
static bool isValidVarNameStart(char C);
/// Verifies that the string at the start of \p Str is a well formed
/// variable. \returns false if it is and sets \p IsPseudo to indicate if it
/// is a pseudo variable and \p TrailIdx to the position of the last
/// character that is part of the variable name. Otherwise, only
/// \returns true.
static bool parseVariable(StringRef Str, bool &IsPseudo, unsigned &TrailIdx);
/// 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 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 string at the start of \p Str for a variable name and \returns
/// whether the variable name is ill-formed. If parsing succeeded, sets
/// \p IsPseudo to indicate if it is a pseudo variable, sets \p Name to the
/// parsed variable name and strips \p Str from the variable name.
static bool parseVariable(StringRef &Str, StringRef &Name, bool &IsPseudo);
/// Parses \p Expr for the definition of a numeric variable, returning an
/// error if \p Context already holds a string variable with the same name.
/// \returns whether parsing fails, in which case errors are reported on
/// \p SM. Otherwise, sets \p Name to the name of the parsed numeric
/// variable.
static bool parseNumericVariableDefinition(StringRef &Expr, StringRef &Name,
FileCheckPatternContext *Context,
const SourceMgr &SM);
/// Parses \p Expr for a numeric substitution block. \returns the class
/// representing the AST of the numeric expression whose value must be
/// substituted, or nullptr if parsing fails, in which case errors are
/// reported on \p SM. Sets \p DefinedNumericVariable to point to the class
/// representing the numeric variable defined in this numeric substitution
/// block, or nullptr if this block does not define any variable.
FileCheckNumExpr *parseNumericSubstitutionBlock(
StringRef Expr, FileCheckNumericVariable *&DefinedNumericVariable,
const SourceMgr &SM) const;
/// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
/// instance accordingly.
///
/// \p Prefix provides which prefix is being matched, \p Req describes the
/// global options that influence the parsing such as whitespace
/// canonicalization, \p SM provides the SourceMgr used for error reports,
/// and \p LineNumber is the line number in the input file from which the
/// pattern string was read. \returns true in case of an error, false
/// otherwise.
bool ParsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
unsigned LineNumber, const FileCheckRequest &Req);
/// canonicalization, \p SM provides the SourceMgr used for error reports.
/// \returns true in case of an error, false otherwise.
bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
const FileCheckRequest &Req);
/// Matches the pattern string against the input buffer \p Buffer
///
/// \returns the position that is matched or npos if there is no match. If
Expand All @@ -396,8 +442,11 @@ class FileCheckPattern {
///
/// The GlobalVariableTable StringMap in the FileCheckPatternContext class
/// 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;
/// is updated if this match defines new values. Likewise, the
/// GlobalNumericVariableTable StringMap in the same class provides the
/// current values of FileCheck numeric variables and is updated if this
/// match defines new numeric values.
size_t match(StringRef Buffer, size_t &MatchLen, const SourceMgr &SM) const;
/// Prints the value of successful substitutions or the name of the undefined
/// string or numeric variable preventing a successful substitution.
void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
Expand Down Expand Up @@ -427,6 +476,17 @@ class FileCheckPattern {
/// \returns the offset of the closing sequence within Str, or npos if it
/// was not found.
size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);

/// Parses \p Expr for the use of a numeric variable. \returns the pointer to
/// the class instance representing that variable if successful, or nullptr
/// otherwise, in which case errors are reported on \p SM.
FileCheckNumericVariable *parseNumericVariableUse(StringRef &Expr,
const SourceMgr &SM) const;
/// Parses \p Expr for a binary operation.
/// \returns the class representing the binary operation of the numeric
/// expression, or nullptr if parsing fails, in which case errors are
/// reported on \p SM.
FileCheckNumExpr *parseBinop(StringRef &Expr, const SourceMgr &SM) const;
};

//===----------------------------------------------------------------------===//
Expand Down
Loading

0 comments on commit 71d3f22

Please sign in to comment.