Denzel-Brian Budii 9b63bdd154
[mlir] Improve mlir-query tool by implementing getBackwardSlice and getForwardSlice matchers (#115670)
Improve mlir-query tool by implementing `getBackwardSlice` and
`getForwardSlice` matchers. As an addition `SetQuery` also needed to be
added to enable custom configuration for each query. e.g: `inclusive`,
`omitUsesFromAbove`, `omitBlockArguments`.

Note: backwardSlice and forwardSlice algoritms are the same as the ones
in `mlir/lib/Analysis/SliceAnalysis.cpp`
Example of current matcher. The query was made to the file:
`mlir/test/mlir-query/complex-test.mlir`

```mlir
./mlir-query /home/dbudii/personal/llvm-project/mlir/test/mlir-query/complex-test.mlir -c "match getDefinitions(hasOpName(\"arith.add
f\"),2)"

Match #1:

/home/dbudii/personal/llvm-project/mlir/test/mlir-query/complex-test.mlir:5:8:
  %0 = linalg.generic {indexing_maps = [#map, #map], iterator_types = ["parallel", "parallel"]} ins(%arg0 : tensor<5x5xf32>) outs(%arg1 : tensor<5x5xf32>) {
       ^
/home/dbudii/personal/llvm-project/mlir/test/mlir-query/complex-test.mlir:7:10: note: "root" binds here
    %2 = arith.addf %in, %in : f32
         ^
Match #2:

/home/dbudii/personal/llvm-project/mlir/test/mlir-query/complex-test.mlir:10:16:
  %collapsed = tensor.collapse_shape %0 [[0, 1]] : tensor<5x5xf32> into tensor<25xf32>
               ^
/home/dbudii/personal/llvm-project/mlir/test/mlir-query/complex-test.mlir:13:11:
    %c2 = arith.constant 2 : index
          ^
/home/dbudii/personal/llvm-project/mlir/test/mlir-query/complex-test.mlir:14:18:
    %extracted = tensor.extract %collapsed[%c2] : tensor<25xf32>
                 ^
/home/dbudii/personal/llvm-project/mlir/test/mlir-query/complex-test.mlir:15:10: note: "root" binds here
    %2 = arith.addf %extracted, %extracted : f32
         ^
2 matches.
```
2025-05-13 13:18:14 +02:00

194 lines
7.0 KiB
C++

//===--- Parser.h - Matcher expression parser -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Simple matcher expression parser.
//
// This file contains the Parser class, which is responsible for parsing
// expressions in a specific format: matcherName(Arg0, Arg1, ..., ArgN). The
// parser can also interpret simple types, like strings.
//
// The actual processing of the matchers is handled by a Sema object that is
// provided to the parser.
//
// The grammar for the supported expressions is as follows:
// <Expression> := <Literal> | <MatcherExpression>
// <Literal> := <StringLiteral> | <NumericLiteral> | <BooleanLiteral>
// <StringLiteral> := "quoted string"
// <BooleanLiteral> := "true" | "false"
// <NumericLiteral> := [0-9]+
// <MatcherExpression> := <MatcherName>(<ArgumentList>)
// <MatcherName> := [a-zA-Z]+
// <ArgumentList> := <Expression> | <Expression>,<ArgumentList>
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_TOOLS_MLIRQUERY_MATCHER_PARSER_H
#define MLIR_TOOLS_MLIRQUERY_MATCHER_PARSER_H
#include "Diagnostics.h"
#include "RegistryManager.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include <memory>
#include <vector>
namespace mlir::query::matcher::internal {
// Matcher expression parser.
class Parser {
public:
// Different possible tokens.
enum class TokenKind {
Eof,
NewLine,
OpenParen,
CloseParen,
Comma,
Period,
Literal,
Ident,
InvalidChar,
CodeCompletion,
Error
};
// Interface to connect the parser with the registry and more. The parser uses
// the Sema instance passed into parseMatcherExpression() to handle all
// matcher tokens.
class Sema {
public:
virtual ~Sema();
// Process a matcher expression. The caller takes ownership of the Matcher
// object returned.
virtual VariantMatcher actOnMatcherExpression(
MatcherCtor ctor, SourceRange nameRange, llvm::StringRef functionName,
llvm::ArrayRef<ParserValue> args, Diagnostics *error) = 0;
// Look up a matcher by name in the matcher name found by the parser.
virtual std::optional<MatcherCtor>
lookupMatcherCtor(llvm::StringRef matcherName) = 0;
// Compute the list of completion types for Context.
virtual std::vector<ArgKind> getAcceptedCompletionTypes(
llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context);
// Compute the list of completions that match any of acceptedTypes.
virtual std::vector<MatcherCompletion>
getMatcherCompletions(llvm::ArrayRef<ArgKind> acceptedTypes);
};
// An implementation of the Sema interface that uses the matcher registry to
// process tokens.
class RegistrySema : public Parser::Sema {
public:
RegistrySema(const Registry &matcherRegistry)
: matcherRegistry(matcherRegistry) {}
~RegistrySema() override;
std::optional<MatcherCtor>
lookupMatcherCtor(llvm::StringRef matcherName) override;
VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
SourceRange NameRange,
StringRef functionName,
ArrayRef<ParserValue> Args,
Diagnostics *Error) override;
std::vector<ArgKind> getAcceptedCompletionTypes(
llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> context) override;
std::vector<MatcherCompletion>
getMatcherCompletions(llvm::ArrayRef<ArgKind> acceptedTypes) override;
private:
const Registry &matcherRegistry;
};
using NamedValueMap = llvm::StringMap<VariantValue>;
// Methods to parse a matcher expression and return a DynMatcher object,
// transferring ownership to the caller.
static std::optional<DynMatcher>
parseMatcherExpression(llvm::StringRef &matcherCode,
const Registry &matcherRegistry,
const NamedValueMap *namedValues, Diagnostics *error);
static std::optional<DynMatcher>
parseMatcherExpression(llvm::StringRef &matcherCode,
const Registry &matcherRegistry, Diagnostics *error) {
return parseMatcherExpression(matcherCode, matcherRegistry, nullptr, error);
}
// Methods to parse any expression supported by this parser.
static bool parseExpression(llvm::StringRef &code,
const Registry &matcherRegistry,
const NamedValueMap *namedValues,
VariantValue *value, Diagnostics *error);
static bool parseExpression(llvm::StringRef &code,
const Registry &matcherRegistry,
VariantValue *value, Diagnostics *error) {
return parseExpression(code, matcherRegistry, nullptr, value, error);
}
// Methods to complete an expression at a given offset.
static std::vector<MatcherCompletion>
completeExpression(llvm::StringRef &code, unsigned completionOffset,
const Registry &matcherRegistry,
const NamedValueMap *namedValues);
static std::vector<MatcherCompletion>
completeExpression(llvm::StringRef &code, unsigned completionOffset,
const Registry &matcherRegistry) {
return completeExpression(code, completionOffset, matcherRegistry, nullptr);
}
private:
class CodeTokenizer;
struct ScopedContextEntry;
struct TokenInfo;
Parser(CodeTokenizer *tokenizer, const Registry &matcherRegistry,
const NamedValueMap *namedValues, Diagnostics *error);
bool parseChainedExpression(std::string &argument);
bool parseExpressionImpl(VariantValue *value);
bool parseMatcherArgs(std::vector<ParserValue> &args, MatcherCtor ctor,
const TokenInfo &nameToken, TokenInfo &endToken);
bool parseMatcherExpressionImpl(const TokenInfo &nameToken,
const TokenInfo &openToken,
std::optional<MatcherCtor> ctor,
VariantValue *value);
bool parseIdentifierPrefixImpl(VariantValue *value);
void addCompletion(const TokenInfo &compToken,
const MatcherCompletion &completion);
void addExpressionCompletions();
std::vector<MatcherCompletion>
getNamedValueCompletions(llvm::ArrayRef<ArgKind> acceptedTypes);
CodeTokenizer *const tokenizer;
std::unique_ptr<RegistrySema> sema;
const NamedValueMap *const namedValues;
Diagnostics *const error;
using ContextStackTy = std::vector<std::pair<MatcherCtor, unsigned>>;
ContextStackTy contextStack;
std::vector<MatcherCompletion> completions;
};
} // namespace mlir::query::matcher::internal
#endif // MLIR_TOOLS_MLIRQUERY_MATCHER_PARSER_H