Skip to content

Commit 0395bd6

Browse files
committed
R1 - Addresses feedback
1 parent 7361395 commit 0395bd6

File tree

6 files changed

+318
-172
lines changed

6 files changed

+318
-172
lines changed

mlir/docs/DefiningDialects/Operations.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,93 @@ understanding the operation.
175175
> starting with a capital letter and without trailing punctuation.
176176
> Put expanded explanation in the description.
177177
178+
#### Autogenerated LIT tests from IR examples in operation description
179+
180+
To help ensure that IR based op examples stay synchronized with
181+
the actual operation definitions and remain valid as the codebase evolves,
182+
MLIR supports automatically generating roundtrip verification LIT tests from
183+
code examples embedded in operation descriptions.
184+
185+
##### Embedding an IR example in op description
186+
187+
To embed a testable MLIR example in an operation's description, use a special
188+
markdown code block with the `mlir_example` tag:
189+
190+
```tablegen
191+
def MyOp : MyDialect_Op<"my_op"> {
192+
let summary = "An example operation";
193+
194+
let description = [{
195+
This operation demonstrates example usage.
196+
197+
```mlir_example
198+
# func.func @example(%arg0: i32) -> i32 { // This line will be ignored when generating `.md` documentation
199+
%result = mydialect.my_op %arg0 : i32
200+
return %result : i32
201+
# } // This line is ignored as well
202+
```
203+
204+
```mlir_example(custom-driver)
205+
# func.func @example(%arg0: i32) -> i32 {
206+
%result = mydialect.my_op %arg0 : i32
207+
return %result : i32
208+
# }
209+
```
210+
}];
211+
}
212+
```
213+
214+
Things to note:
215+
216+
1. Any portion of the embedded snippet that need not be included in the
217+
`.md` documentation can be demarcated with a `#` prefix. Lines starting with
218+
`#` are stripped out when generating operation documentation but are included
219+
(without the `#` and indentation) in the generated LIT tests. This allows you
220+
to provide context (like function wrappers) needed for valid MLIR IR without
221+
cluttering the documentation.
222+
223+
2. You can optionally specify a custom tool/driver to use in the generated RUN
224+
line by adding it in parentheses after `mlir_example`, such as
225+
`mlir_example(custom-driver)`. If not specified, `mlir-opt` is used by default.
226+
227+
3. Multiple `mlir_example` blocks can be included in a single operation's
228+
description. Each block will generate a separate test file with a unique name
229+
based on the operation name and example index (e.g.,
230+
`generated_MyOp_example_0.mlir`, `generated_MyOp_example_1.mlir`).
231+
232+
4. The generated RUN line automatically includes the `--verify-roundtrip` flag
233+
to ensure the operation can be parsed and printed correctly.
234+
235+
##### CMake integration for LIT test file generation
236+
237+
MLIR provides a CMake function `add_embedded_lit_tests` to automatically extract
238+
and generate LIT test files from TableGen definitions during the build process.
239+
This function is defined in `mlir/cmake/modules/AddMLIR.cmake`.
240+
241+
**Usage:**
242+
243+
```cmake
244+
add_embedded_lit_tests(<target_name> <tablegen_file> <output_directory>)
245+
```
246+
247+
**Parameters:**
248+
- `target_name`: Name for the CMake target that will be created
249+
- `tablegen_file`: Path to the TableGen file containing operations with `mlir_example` blocks
250+
- `output_directory`: Directory where the extracted test files will be written
251+
252+
**Example:**
253+
254+
```cmake
255+
# Extract tests from MyDialectOps.td and generate them in test/Dialect/MyDialect/
256+
add_embedded_lit_tests(MyDialectEmbeddedTests
257+
${CMAKE_CURRENT_SOURCE_DIR}/include/MyDialect/MyDialectOps.td
258+
${CMAKE_CURRENT_SOURCE_DIR}/test/Dialect/MyDialect/)
259+
```
260+
261+
The generated test files can then be picked up by your LIT test configuration
262+
automatically, ensuring that all embedded examples are continuously tested as
263+
part of your regular test suite.
264+
178265
### Operation arguments
179266

180267
There are three kinds of arguments: operands, attributes, and properties.

mlir/include/mlir/IR/Testable.td

Lines changed: 0 additions & 40 deletions
This file was deleted.

mlir/include/mlir/Pass/PassBase.td

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
#ifndef MLIR_PASS_PASSBASE
1515
#define MLIR_PASS_PASSBASE
1616

17-
include "mlir/IR/Testable.td"
18-
1917
//===----------------------------------------------------------------------===//
2018
// Options
2119
//===----------------------------------------------------------------------===//
@@ -64,7 +62,7 @@ class Statistic<string varName, string statName, string desc> {
6462
// Pass
6563
//===----------------------------------------------------------------------===//
6664

67-
class PassBase<string passArg, string base> : Testable {
65+
class PassBase<string passArg, string base> {
6866
// The command line argument of the pass.
6967
string argument = passArg;
7068

Lines changed: 66 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,74 @@
1-
// RUN: mlir-tblgen -gen-lit-tests -I %S/../../include -dialect=test %s | FileCheck %s
1+
// RUN: mlir-tblgen -gen-lit-tests -I %S/../../include %s | FileCheck %s
22

3-
include "mlir/Pass/PassBase.td"
4-
include "mlir/IR/Testable.td"
3+
include "mlir/IR/OpBase.td"
54

6-
def TestPassWithEmbeddedLitTests : Pass<"test-pass-with-embedded-lit-tests"> {
7-
let summary = "pass summary";
5+
def Test_Dialect : Dialect {
6+
let name = "test";
7+
let cppNamespace = "test";
8+
}
9+
10+
def TestOp : Op<Test_Dialect, "test_op"> {
11+
let summary = "test op with mlir_example code blocks";
812
let description = [{
9-
Pass description
13+
This operation demonstrates the mlir_example feature for ops.
14+
15+
Basic usage:
16+
```mlir_example(mlir-opt)
17+
# func.func @foo(%arg0: i32) -> i32 {
18+
%0 = test.test_op %arg0 : i32
19+
return %0 : i32
20+
# }
21+
```
22+
23+
And some more back to back examples -
24+
25+
```mlir_example(some-other-tool)
26+
# func.func @foo1(%arg1: i32) -> i32 {
27+
%0 = test.test_op %arg1 : i32
28+
return %0 : i32
29+
# }
30+
```
31+
```mlir_example(yet-another-tool)
32+
# func.func @foo2(%arg2: i32) -> i32 {
33+
%0 = test.test_op %arg2 : i32
34+
return %0 : i32
35+
# }
36+
```
1037
}];
11-
12-
let tests = [
13-
LitTest<
14-
"lit_test_file_1.mlir",
15-
[{
16-
func.func @test1() {
17-
return 42;
18-
}
19-
}],
20-
[
21-
"// RUN: mlir-opt %s --verify-roundtrip | FileCheck %s",
22-
],
23-
[
24-
"// RANDOM-CHECK-LABEL: func.func @test1",
25-
]
26-
>,
27-
LitTest<
28-
"lit_test_file_2.mlir",
29-
[{
30-
func.func @test2() {
31-
return 42;
32-
}
33-
}],
34-
[
35-
"// RUN: mlir-opt %s --verify-roundtrip | FileCheck %s",
36-
],
37-
[
38-
"// RANDOM-CHECK-LABEL: func.func @test2",
39-
]
40-
>,
41-
];
38+
39+
let arguments = (ins I32:$input);
40+
let results = (outs I32:$output);
4241
}
4342

44-
// CHECK-LABEL: // Generated 2 LIT test files
45-
// CHECK: // Use the following files for LIT testing:
43+
// CHECK-LABEL: // Generated 3 LIT test files
44+
// CHECK: // Use the following files for LIT testing:
45+
46+
// CHECK: // File: generated_TestOp_example_0.mlir
47+
// CHECK: // --- BEGIN generated_TestOp_example_0.mlir ---
48+
// CHECK: mlir-opt %s --verify-roundtrip
49+
// CHECK: // Generated from TableGen definition: TestOp
50+
// CHECK: func.func @foo(%arg0: i32) -> i32 {
51+
// CHECK: %0 = test.test_op %arg0 : i32
52+
// CHECK: return %0 : i32
53+
// CHECK: }
54+
// CHECK: // --- END generated_TestOp_example_0.mlir ---
4655

47-
// CHECK: // File: generated_TestPassWithEmbeddedLitTests_lit_test_file_1.mlir
48-
// CHECK: // --- BEGIN generated_TestPassWithEmbeddedLitTests_lit_test_file_1.mlir ---
49-
// CHECK: // RUN: mlir-opt %s --verify-roundtrip | FileCheck %s
50-
// CHECK: // Generated from TableGen definition: TestPassWithEmbeddedLitTests
51-
// CHECK: func.func @test1() {
52-
// CHECK: return 42;
53-
// CHECK: }
54-
// CHECK: // RANDOM-CHECK-LABEL: func.func @test1
55-
// CHECK: --- END generated_TestPassWithEmbeddedLitTests_lit_test_file_1.mlir ---
56+
// CHECK: // File: generated_TestOp_example_1.mlir
57+
// CHECK: // --- BEGIN generated_TestOp_example_1.mlir ---
58+
// CHECK: some-other-tool %s --verify-roundtrip
59+
// CHECK: // Generated from TableGen definition: TestOp
60+
// CHECK: func.func @foo1(%arg1: i32) -> i32 {
61+
// CHECK: %0 = test.test_op %arg1 : i32
62+
// CHECK: return %0 : i32
63+
// CHECK: }
64+
// CHECK: // --- END generated_TestOp_example_1.mlir ---
5665

57-
// CHECK: // File: generated_TestPassWithEmbeddedLitTests_lit_test_file_2.mlir
58-
// CHECK: // --- BEGIN generated_TestPassWithEmbeddedLitTests_lit_test_file_2.mlir ---
59-
// CHECK: // RUN: mlir-opt %s --verify-roundtrip | FileCheck %s
60-
// CHECK: // Generated from TableGen definition: TestPassWithEmbeddedLitTests
61-
// CHECK: func.func @test2() {
62-
// CHECK: return 42;
63-
// CHECK: }
64-
// CHECK: // RANDOM-CHECK-LABEL: func.func @test2
65-
// CHECK: // --- END generated_TestPassWithEmbeddedLitTests_lit_test_file_2.mlir ---
66+
// CHECK: // File: generated_TestOp_example_2.mlir
67+
// CHECK: // --- BEGIN generated_TestOp_example_2.mlir ---
68+
// CHECK: yet-another-tool %s --verify-roundtrip
69+
// CHECK: // Generated from TableGen definition: TestOp
70+
// CHECK: func.func @foo2(%arg2: i32) -> i32 {
71+
// CHECK: %0 = test.test_op %arg2 : i32
72+
// CHECK: return %0 : i32
73+
// CHECK: }
74+
// CHECK: // --- END generated_TestOp_example_2.mlir ---

0 commit comments

Comments
 (0)