Files
clang-p2996/mlir/lib/Query/Matcher/RegistryManager.cpp
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

150 lines
4.4 KiB
C++

//===- RegistryManager.cpp - Matcher registry -----------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Registry map populated at static initialization time.
//
//===----------------------------------------------------------------------===//
#include "RegistryManager.h"
#include "mlir/Query/Matcher/Registry.h"
#include <set>
#include <utility>
namespace mlir::query::matcher {
namespace {
// Enum to string for autocomplete.
static std::string asArgString(ArgKind kind) {
switch (kind) {
case ArgKind::Boolean:
return "Boolean";
case ArgKind::Matcher:
return "Matcher";
case ArgKind::Signed:
return "Signed";
case ArgKind::String:
return "String";
}
llvm_unreachable("Unhandled ArgKind");
}
} // namespace
void Registry::registerMatcherDescriptor(
llvm::StringRef matcherName,
std::unique_ptr<internal::MatcherDescriptor> callback) {
assert(!constructorMap.contains(matcherName));
constructorMap[matcherName] = std::move(callback);
}
std::optional<MatcherCtor>
RegistryManager::lookupMatcherCtor(llvm::StringRef matcherName,
const Registry &matcherRegistry) {
auto it = matcherRegistry.constructors().find(matcherName);
return it == matcherRegistry.constructors().end()
? std::optional<MatcherCtor>()
: it->second.get();
}
std::vector<ArgKind> RegistryManager::getAcceptedCompletionTypes(
llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> context) {
// Starting with the above seed of acceptable top-level matcher types, compute
// the acceptable type set for the argument indicated by each context element.
std::set<ArgKind> typeSet;
typeSet.insert(ArgKind::Matcher);
for (const auto &ctxEntry : context) {
MatcherCtor ctor = ctxEntry.first;
unsigned argNumber = ctxEntry.second;
std::vector<ArgKind> nextTypeSet;
if (argNumber < ctor->getNumArgs())
ctor->getArgKinds(argNumber, nextTypeSet);
typeSet.insert(nextTypeSet.begin(), nextTypeSet.end());
}
return std::vector<ArgKind>(typeSet.begin(), typeSet.end());
}
std::vector<MatcherCompletion>
RegistryManager::getMatcherCompletions(llvm::ArrayRef<ArgKind> acceptedTypes,
const Registry &matcherRegistry) {
std::vector<MatcherCompletion> completions;
// Search the registry for acceptable matchers.
for (const auto &m : matcherRegistry.constructors()) {
const internal::MatcherDescriptor &matcher = *m.getValue();
llvm::StringRef name = m.getKey();
unsigned numArgs = matcher.getNumArgs();
std::vector<std::vector<ArgKind>> argKinds(numArgs);
for (const ArgKind &kind : acceptedTypes) {
if (kind != ArgKind::Matcher)
continue;
for (unsigned arg = 0; arg != numArgs; ++arg)
matcher.getArgKinds(arg, argKinds[arg]);
}
std::string decl;
llvm::raw_string_ostream os(decl);
std::string typedText = std::string(name);
os << "Matcher: " << name << "(";
for (const std::vector<ArgKind> &arg : argKinds) {
if (&arg != &argKinds[0])
os << ", ";
bool firstArgKind = true;
// Two steps. First all non-matchers, then matchers only.
for (const ArgKind &argKind : arg) {
if (!firstArgKind)
os << "|";
firstArgKind = false;
os << asArgString(argKind);
}
}
os << ")";
typedText += "(";
if (argKinds.empty())
typedText += ")";
else if (argKinds[0][0] == ArgKind::String)
typedText += "\"";
completions.emplace_back(typedText, decl);
}
return completions;
}
VariantMatcher RegistryManager::constructMatcher(
MatcherCtor ctor, internal::SourceRange nameRange,
llvm::StringRef functionName, llvm::ArrayRef<ParserValue> args,
internal::Diagnostics *error) {
VariantMatcher out = ctor->create(nameRange, args, error);
if (functionName.empty() || out.isNull())
return out;
if (std::optional<DynMatcher> result = out.getDynMatcher()) {
result->setFunctionName(functionName);
return VariantMatcher::SingleMatcher(*result);
}
error->addError(nameRange, internal::ErrorType::RegistryNotBindable);
return {};
}
} // namespace mlir::query::matcher