Skip to content

Commit a1567af

Browse files
committed
introduce mlir-query docs
1 parent e2510b1 commit a1567af

File tree

1 file changed

+354
-0
lines changed

1 file changed

+354
-0
lines changed

mlir/docs/Tools/mlir-query.md

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
`mlir-query` is an interactive tool designed to simplify IR exploration. It provides a REPL interface and supports an interactive query language for MLIR, enabling developers to query the MLIR IR dynamically.
2+
The tool uses matchers as its core mechanism for performing queries over the MLIR IR, relying on simple matchers from `Matchers.h` and slicing-related matchers from `SliceMatchers.h`.
3+
4+
Through its IR exploration capabilities and the interactive query language, `mlir-query` serves both as a prototyping environment for pattern matchers and as a good debugging tool.
5+
6+
## Usage
7+
8+
### Query modes
9+
In order to prototype pattern matchers, explore, test, or debug the MLIR IR, the tool provides two main usage modes:
10+
11+
* **Run queries directly from the CLI:**
12+
```shell
13+
./mlir-query input.mlir -c "<your_query_1>" -c "<your_query_2>" ... "<your_query_N>"
14+
```
15+
The commands are executed and the program exits immediately.
16+
17+
* **Launch an interactive session:**
18+
```shell
19+
./mlir-query input.mlir
20+
```
21+
Opens a REPL-like interface where you can type queries interactively.
22+
23+
### Use with `mlir-opt`
24+
25+
The tool can easily be used with the MLIR pass pipeline infrastructure by running a pass pipeline and passing the result as input to `mlir-query`.
26+
27+
```shell
28+
./mlir-opt input.mlir -canonicalize | ./mlir-query -c "<your_query_1>" -c "<your_query_2>" ... "<your_query_N>"
29+
```
30+
*Command example*
31+
32+
## Register a new matcher
33+
34+
To register a new matcher with `mlir-query`, you need to define a new structure that implements one of the following signatures: `bool match(Operation* op)` or `bool match(Operation* op, SetVector<Operation*> &matchedOps)`. Next, link `MLIRQueryLib` and register the matcher.
35+
36+
```cpp
37+
#include "mlir/Tools/mlir-query/MlirQueryMain.h"
38+
using namespace mlir;
39+
40+
int main(int argc, char **argv) {
41+
42+
DialectRegistry dialectRegistry;
43+
registerAllDialects(dialectRegistry);
44+
45+
query::matcher::Registry matcherRegistry;
46+
47+
// Replace <matcher_name> with your desired matcher identifier string.
48+
matcherRegistry.registerMatcher("<matcher_name>", matcherInstance);
49+
50+
MLIRContext context(dialectRegistry);
51+
return failed(mlirQueryMain(argc, argv, context, matcherRegistry));
52+
}
53+
```
54+
55+
## Features
56+
### Autocompletion
57+
58+
To simplify usage, `mlir-query` provides autocompletion in the REPL interface, enabling users to ease query input by pressing the Tab key.
59+
<div style="overflow-x:auto; margin:1em 0;">
60+
<img
61+
src="https://i.imgur.com/3QiJgrU.gif"
62+
alt="Autocompletion command list"
63+
style="
64+
display: block;
65+
margin: 0 auto;
66+
width: 1250px !important;
67+
max-width: none !important;
68+
height: auto !important;
69+
"
70+
/>
71+
</div>
72+
73+
74+
*When autocompletion is first triggered, a list of available commands is displayed* (e.g., `match`, `help`). *Triggering autocompletion for the* `match` *command then shows a list of available matchers.*
75+
76+
<div style="overflow-x:auto; margin:1em 0;">
77+
<img
78+
src="https://i.imgur.com/bpMS9mf.gif"
79+
alt="Autocompletion matcher"
80+
style="
81+
display: block;
82+
margin: 0 auto;
83+
width: 1250px !important;
84+
max-width: none !important;
85+
height: auto !important;
86+
"
87+
/>
88+
</div>
89+
90+
*Autocompletion use case for constructing queries.*
91+
92+
### Function extraction
93+
94+
Results from a matcher can be isolated into a custom function using the `extract("functionName")` feature, facilitating further exploration or testing.
95+
96+
#### Example
97+
98+
```mlir
99+
func.func @slicing_memref_store_trivial() {
100+
%0 = memref.alloc() : memref<10xf32>
101+
%c0 = arith.constant 0 : index
102+
%cst = arith.constant 0.000000e+00 : f32
103+
affine.for %i1 = 0 to 10 {
104+
%1 = affine.apply affine_map<()[s0] -> (s0)>()[%c0]
105+
memref.store %cst, %0[%1] : memref<10xf32>
106+
%2 = memref.load %0[%c0] : memref<10xf32>
107+
%3 = affine.apply affine_map<()[] -> (0)>()[]
108+
memref.store %cst, %0[%3] : memref<10xf32>
109+
memref.store %2, %0[%c0] : memref<10xf32>
110+
}
111+
return
112+
}
113+
```
114+
115+
*Initial function.*
116+
117+
```shell
118+
./mlir-opt /home/user/llvm-project/mlir/test/mlir-query/slice-function-extraction.mlir "m getDefinitionsByPredicate(hasOpName(\"memref.store\"),hasOpName(\"memref.alloc\"),true,false,false).extract(\"backward_slice\")"
119+
```
120+
121+
*Command used to extract the results of* `getDefinitionsByPredicate` *query.*
122+
123+
```mlir
124+
func.func @backward_slice(%arg0: memref<10xf32>) -> (f32, index, index, f32, index, index, f32) {
125+
%cst = arith.constant 0.000000e+00 : f32
126+
%c0 = arith.constant 0 : index
127+
%0 = affine.apply affine_map<()[s0] -> (s0)>()[%c0]
128+
memref.store %cst, %arg0[%0] : memref<10xf32>
129+
%cst_0 = arith.constant 0.000000e+00 : f32
130+
%1 = affine.apply affine_map<() -> (0)>()
131+
memref.store %cst_0, %arg0[%1] : memref<10xf32>
132+
%c0_1 = arith.constant 0 : index
133+
%2 = memref.load %arg0[%c0_1] : memref<10xf32>
134+
memref.store %2, %arg0[%c0_1] : memref<10xf32>
135+
return %cst, %c0, %0, %cst_0, %1, %c0_1, %2 : f32, index, index, f32, index, index, f32
136+
}
137+
```
138+
139+
*The function containing only the relevant slice.*
140+
141+
## Matcher overview
142+
143+
This section details the current matchers and their capabilities. It does not include examples of every matcher but rather aims to showcase and explain the types of matchers, along with useful examples that should be sufficient for comprehension. For a detailed explanation of each matcher's functionality and its parameters, please refer to the matchers reference section.
144+
145+
### Simple matchers
146+
147+
The tool supports a variety of simple matchers, including `isConstantOp`, which finds all constant operations, `hasOpName`, which finds all operations with a given name and `hasOpAttrName`, which finds all operations with a certain attribute.
148+
149+
#### Simple matcher example
150+
```mlir
151+
func.func @mixedOperations(%a: f32, %b: f32, %c: f32) -> f32 {
152+
%sum0 = arith.addf %a, %b : f32
153+
%sub0 = arith.subf %sum0, %c : f32
154+
%mul0 = arith.mulf %a, %sub0 : f32
155+
%sum1 = arith.addf %b, %c : f32
156+
%mul1 = arith.mulf %sum1, %mul0 : f32
157+
%sub2 = arith.subf %mul1, %a : f32
158+
%sum2 = arith.addf %mul1, %b : f32
159+
%mul2 = arith.mulf %sub2, %sum2 : f32
160+
return %mul2 : f32
161+
}
162+
```
163+
164+
<div style="overflow-x:auto; margin:1em 0;">
165+
<img
166+
src="https://i.imgur.com/dbpn3Xo.gif"
167+
alt="Autocompletion matcher"
168+
style="
169+
display: block;
170+
margin: 0 auto;
171+
width: 1250px !important;
172+
max-width: none !important;
173+
height: auto !important;
174+
"
175+
/>
176+
</div>
177+
178+
*Matches all* `arith.addf` *operations*
179+
180+
### Slice matchers
181+
182+
`mlir-query` includes slicing matchers that compute forward and backward slices. These are abstractions over the methods from the `SliceAnalysis` library, enabling their use in a query context. In contrast to simple matchers, slicing matchers introduce the concept of `inner matchers`, which allow users to specify the `root operation` and the exit condition via other `matchers`.
183+
184+
Two useful backward-slicing matchers are `getDefinitionsByPredicate` and `getDefinitions`. The former matches all definitions by specifying both the starting point of the slice computation and the exit condition using an inner matcher. The latter is similar, except it limits the exit condition to a depth level specified as a numeric literal argument. Both matchers accept three boolean arguments: `omitBlockArguments`, `omitUsesFromAbove`, and `inclusive`. The first two specify traversal configuration, while the last controls inclusion of the root operation in the slice.
185+
186+
Forward-slicing matchers are similar, but their exit condition is currently limited to specification via a nested matcher.
187+
188+
#### Slice matchers examples
189+
190+
```mlir
191+
#map = affine_map<(d0, d1) -> (d0, d1)>
192+
func.func @slice_use_from_above(%arg0: tensor<5x5xf32>, %arg1: tensor<5x5xf32>) {
193+
%0 = linalg.generic {indexing_maps = [#map, #map], iterator_types = ["parallel", "parallel"]} ins(%arg0 : tensor<5x5xf32>) outs(%arg1 : tensor<5x5xf32>) {
194+
^bb0(%in: f32, %out: f32):
195+
%2 = arith.addf %in, %in : f32
196+
linalg.yield %2 : f32
197+
} -> tensor<5x5xf32>
198+
%collapsed = tensor.collapse_shape %0 [[0, 1]] : tensor<5x5xf32> into tensor<25xf32>
199+
%1 = linalg.generic {indexing_maps = [#map, #map], iterator_types = ["parallel", "parallel"]} ins(%0 : tensor<5x5xf32>) outs(%arg1 : tensor<5x5xf32>) {
200+
^bb0(%in: f32, %out: f32):
201+
%c2 = arith.constant 2 : index
202+
%extracted = tensor.extract %collapsed[%c2] : tensor<25xf32>
203+
%2 = arith.addf %extracted, %extracted : f32
204+
linalg.yield %2 : f32
205+
} -> tensor<5x5xf32>
206+
return
207+
}
208+
```
209+
210+
<div style="overflow-x:auto; margin:1em 0;">
211+
<img
212+
src="https://i.imgur.com/e7ObI7P.gif"
213+
alt="getDefinitionsByPredicate matcher"
214+
style="
215+
display: block;
216+
margin: 0 auto;
217+
width: 1250px !important;
218+
max-width: none !important;
219+
height: auto !important;
220+
"
221+
/>
222+
</div>
223+
224+
*Matches all defining operations, using the* `hasOpName("arith.addf")` *inner matcher for the root operation and the* `hasOpName("linalg.generic")` *inner matcher for the exit condition.*
225+
226+
<div style="overflow-x:auto; margin:1em 0;">
227+
<img
228+
src="https://i.imgur.com/V4uegw2.gif"
229+
alt="getDefinitions matcher"
230+
style="
231+
display: block;
232+
margin: 0 auto;
233+
width: 1250px !important;
234+
max-width: none !important;
235+
height: auto !important;
236+
"
237+
/>
238+
</div>
239+
240+
*Matches all defining operations by using* `hasOpName("arith.addf")` *inner matcher for the root operation and limiting traversal to a depth of two levels.*
241+
242+
### Variadic matchers
243+
244+
At this moment, the tool supports two variadic matchers: `anyOf` and `allOf`, which can be conceptualized as matcher combinators, as one can group multiple matchers together to facilitate the construction of complex matchers.
245+
246+
Operator `anyOf` matches if any of the matchers in a given set match succeed (e.g `anyOf(m1, m2 ...)`). Using it brings several benefits, for example, one could construct a matcher that computes the union of two or more slices, initiating slice computation from one or multiple points of interest, or limiting slice computation by a set of inner matchers.
247+
248+
Operator `allOf` matches only if all matchers in a set of matchers succeed (e.g `allOf(m1, m2 ...)`). For example, it enables finding all operations with a certain attribute, or initiating/limiting slice computation when an operation with a certain attribute is encountered.
249+
250+
#### Variadic matchers examples
251+
252+
```mlir
253+
func.func @slice_depth1_loop_nest_with_offsets() {
254+
%0 = memref.alloc() : memref<100xf32>
255+
%cst = arith.constant 7.000000e+00 : f32
256+
affine.for %i0 = 0 to 16 {
257+
%a0 = affine.apply affine_map<(d0) -> (d0 + 2)>(%i0)
258+
affine.store %cst, %0[%a0] : memref<100xf32>
259+
}
260+
affine.for %i1 = 4 to 8 {
261+
%a1 = affine.apply affine_map<(d0) -> (d0 - 1)>(%i1)
262+
%1 = affine.load %0[%a1] : memref<100xf32>
263+
}
264+
return
265+
}
266+
```
267+
<div style="overflow-x:auto; margin:1em 0;">
268+
<img
269+
src="https://i.imgur.com/qQhfyX4.gif"
270+
alt="backward-slice-union-anyof matcher"
271+
style="
272+
display: block;
273+
margin: 0 auto;
274+
width: 1250px !important;
275+
max-width: none !important;
276+
height: auto !important;
277+
"
278+
/>
279+
</div>
280+
281+
*Computes the union of two backward slices.*
282+
<div style="overflow-x:auto; margin:1em 0;">
283+
<img
284+
src="https://i.imgur.com/b1EMdIv.gif"
285+
alt="backward-slice-union-anyof matcher"
286+
style="
287+
display: block;
288+
margin: 0 auto;
289+
width: 1250px !important;
290+
max-width: none !important;
291+
height: auto !important;
292+
"
293+
/>
294+
</div>
295+
296+
*Computes the forward slice by specifying the root operation using* `anyOf(hasOpName("memref.alloc"),isConstant())` *inner matcher and exit condition via* `anyOf(hasOpName("affine.load"),hasOpName("memref.dealloc"))` *inner matcher.*
297+
298+
```mlir
299+
func.func @no_hoisting_collapse_shape(%in_0: memref<1x20x1xi32>, %1: memref<9x1xi32>, %vec: vector<4xi32>) {
300+
%c0_i32 = arith.constant 0 : i32
301+
%c0 = arith.constant 0 : index
302+
%c4 = arith.constant 4 : index
303+
%c20 = arith.constant 20 : index
304+
%alloca = memref.alloca() {alignment = 64 : i64} : memref<1x4x1xi32>
305+
scf.for %arg0 = %c0 to %c20 step %c4 {
306+
%subview = memref.subview %in_0[0, %arg0, 0] [1, 4, 1] [1, 1, 1] : memref<1x20x1xi32> to memref<1x4x1xi32, strided<[20, 1, 1], offset: ?>>
307+
%collapse_shape = memref.collapse_shape %alloca [[0, 1, 2]] : memref<1x4x1xi32> into memref<4xi32>
308+
vector.transfer_write %vec, %collapse_shape[%c0] {in_bounds = [true]} : vector<4xi32>, memref<4xi32>
309+
%read = vector.transfer_read %alloca[%c0, %c0, %c0], %c0_i32 {in_bounds = [true, true, true]} : memref<1x4x1xi32>, vector<1x4x1xi32>
310+
vector.transfer_write %read, %subview[%c0, %c0, %c0] {in_bounds = [true, true, true]} : vector<1x4x1xi32>, memref<1x4x1xi32, strided<[20, 1, 1], offset: ?>>
311+
}
312+
return
313+
}
314+
```
315+
316+
<div style="overflow-x:auto; margin:1em 0;">
317+
<img
318+
src="https://i.imgur.com/MJnhvfD.gif"
319+
alt="backward-slice-union-anyof matcher"
320+
style="
321+
display: block;
322+
margin: 0 auto;
323+
width: 1250px !important;
324+
max-width: none !important;
325+
height: auto !important;
326+
"
327+
/>
328+
</div>
329+
330+
*Computes the forward slice by specifying the root operation using* `allOf(hasOpName("memref.alloca"),hasOpAttrName("alignment"))` *inner matcher and exit condition via* `hasOpName("vector.transfer_read")` *inner matcher.*
331+
332+
## Matcher Reference
333+
334+
335+
| Matcher | Type |
336+
| ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
337+
| `allOf` | `allOfVariadicOperator` |
338+
| `anyOf` | `anyOfVariadicOperator` |
339+
| [`getAllDefinitions`](https://mlir.llvm.org/doxygen/namespacemlir_1_1query_1_1matcher.html#a9a0dba8d855564b67517c778c915389f) | [`BackwardSliceMatcher`](https://mlir.llvm.org/doxygen/classmlir_1_1query_1_1matcher_1_1BackwardSliceMatcher.html) |
340+
| [`getDefinitions`](https://mlir.llvm.org/doxygen/namespacemlir_1_1query_1_1matcher.html#a9a0dba8d855564b67517c778c915389f) | [`BackwardSliceMatcher`](https://mlir.llvm.org/doxygen/classmlir_1_1query_1_1matcher_1_1BackwardSliceMatcher.html) |
341+
| [`getDefinitionsByPredicate`](https://mlir.llvm.org/doxygen/namespacemlir_1_1query_1_1matcher.html#a57916f218941284d7a5c8c912cd7d9f8) | [`PredicateBackwardSliceMatcher`](https://mlir.llvm.org/doxygen/classmlir_1_1query_1_1matcher_1_1PredicateBackwardSliceMatcher.html) |
342+
| [`getUsersByPredicate`](https://mlir.llvm.org/doxygen/namespacemlir_1_1query_1_1matcher.html#a4cfbf14535ac0078e22cf89cafee1fd8) | [`PredicateForwardSliceMatcher`](https://mlir.llvm.org/doxygen/classmlir_1_1query_1_1matcher_1_1PredicateForwardSliceMatcher.html) |
343+
| [`hasOpAttrName`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1AttrOpMatcher.html) | [`AttrOpMatcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1AttrOpMatcher.html) |
344+
| [`hasOpName`](https://mlir.llvm.org/doxygen/namespacemlir.html#a69b52f968271c9a4da1bc766ee083a9c) | [`NameOpMatcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1NameOpMatcher.html) |
345+
| [`isConstantOp`](https://mlir.llvm.org/doxygen/namespacemlir.html#ad402a86ee4c9000c6fa1fceaddab560b) | [`constant_op_matcher`](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/Matchers.h#L182) |
346+
| [`isNegInfFloat`](https://mlir.llvm.org/doxygen/namespacemlir.html#a9e89b015211525b010832d2d2c37650b) | [`constant_float_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__float__predicate__matcher.html) |
347+
| [`isNegZeroFloat`](https://mlir.llvm.org/doxygen/namespacemlir.html#aa9eba8d1292854c0da6c062988ecac9b) | [`constant_float_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__float__predicate__matcher.html) |
348+
| [`isNonZero`](https://mlir.llvm.org/doxygen/namespacemlir.html#a94bb42600b9be680591776fdc14a53cd) | [`constant_int_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__int__predicate__matcher.html) |
349+
| [`isOne`](https://mlir.llvm.org/doxygen/namespacemlir.html#a907f415a4c803b15ef57db37cc732f39) | [`constant_int_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__int__predicate__matcher.html) |
350+
| [`isOneFloat`](https://mlir.llvm.org/doxygen/namespacemlir.html#af0495d84f34cf3238a7741fa6974a485) | [`constant_float_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__float__predicate__matcher.html) |
351+
| [`isPosInfFloat`](https://mlir.llvm.org/doxygen/namespacemlir.html#adc93dfeaa35bda23b16591c462c335f6) | [`constant_float_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__float__predicate__matcher.html) |
352+
| [`isPosZeroFloat`](https://mlir.llvm.org/doxygen/namespacemlir.html#a774a1ae971f4ef00eb57389293dfe617) | [`constant_float_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__float__predicate__matcher.html) |
353+
| [`isZero`](https://mlir.llvm.org/doxygen/namespacemlir.html#a7f5d8af15bd8994b1a7abeaaacfe1b06) | [`constant_int_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__int__predicate__matcher.html) |
354+
| [`isZeroFloat`](https://mlir.llvm.org/doxygen/namespacemlir.html#a8ea33aa665368d4f2108eb2d41c85111) | [`constant_float_predicate_matcher`](https://mlir.llvm.org/doxygen/structmlir_1_1detail_1_1constant__float__predicate__matcher.html) |

0 commit comments

Comments
 (0)