Skip to content

Commit 7c241cd

Browse files
j2kunjoker-eph
andauthored
Add pattern catalog page to MLIR website (#230)
This PR adds a basic pattern-search index to the MLIR website. ## Features: - Autocomplete operation name on search input - Links to GitHub search for the class name in `path:mlir` - Clicking on a search result shows a popup with the class and all the operations it touches (each of which is a link to the search) - Filters by C++ namespace of the pattern and the "modification type" (insert, remove, replace) the pattern applies to that op - Support regex inputs for operation name (e.g., `.*\.for`) ## Screenshots <img width="1580" height="1308" alt="image" src="https://github.com/user-attachments/assets/d70f60cc-de86-4d3d-ad13-e0b43e8d57a3" /> <img width="1598" height="1010" alt="image" src="https://github.com/user-attachments/assets/eaf25e57-720b-4022-9a3a-d4aa114f969b" /> --------- Co-authored-by: Jeremy Kun <[email protected]> Co-authored-by: Mehdi Amini <[email protected]>
1 parent c5c6f00 commit 7c241cd

File tree

8 files changed

+1617
-1
lines changed

8 files changed

+1617
-1
lines changed

.github/workflows/main.yml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
run: ./mlir-www-helper.sh --help
3232

3333
- name: Install dependencies
34-
run: sudo apt-get install doxygen graphviz
34+
run: sudo apt-get install doxygen graphviz python3
3535

3636
- name: Clone LLVM repo
3737
uses: actions/checkout@v3
@@ -44,8 +44,10 @@ jobs:
4444
run: |
4545
mkdir llvm_src/build
4646
cd llvm_src/build
47+
# Assert mode is needed for the pattern search index
4748
cmake ../llvm \
4849
-DCMAKE_BUILD_TYPE=Release \
50+
-DLLVM_ENABLE_ASSERTIONS=ON \
4951
-DLLVM_ENABLE_PROJECTS=mlir \
5052
-DLLVM_TARGETS_TO_BUILD="host" \
5153
-DMLIR_INCLUDE_DOCS="true" \
@@ -55,6 +57,25 @@ jobs:
5557
- name: Install docs
5658
run: ./mlir-www-helper.sh --install-docs "llvm_src" "website"
5759

60+
- name: Build pattern search index
61+
run: |
62+
cd llvm_src/build
63+
# Run the tests once to ensure they are passing.
64+
# The next run used to generate the patterns log is disabling error checking. This first
65+
# run will ensure we don't generate the website when tests are broken.
66+
make -j$(nproc) check-mlir
67+
echo "finished building tests"
68+
# ignore nonzero exit codes in this command, since MLIR_GENERATE_PATTERN_CATALOG
69+
# implicitly enables`--mlir-disable-threading` which some tests are incompatible with.
70+
{ MLIR_GENERATE_PATTERN_CATALOG=1 bin/llvm-lit -j$(nproc) -v -a tools/mlir/test || true ; } \
71+
| grep '# | \[pattern-logging-listener' \
72+
| sed 's/# | \[pattern-logging-listener:[0-9]*\] PatternLoggingListener.cpp:[0-9]* //g' \
73+
| sort | uniq > $HOME/pattern_catalog.txt
74+
# back to mlir-www root
75+
cd ../..
76+
head $HOME/pattern_catalog.txt
77+
python3 build_pattern_catalog_index.py $HOME/pattern_catalog.txt website/static/pattern-search/pattern-index.json
78+
5879
- name: Setup Hugo
5980
uses: peaceiris/actions-hugo@v2
6081
with:

build_pattern_catalog_index.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Convert pipe-delimited text file to JSON format for MLIR operation search.
4+
Usage: python convert_to_json.py input.txt output.json
5+
"""
6+
7+
from collections import defaultdict
8+
import json
9+
import os
10+
import re
11+
import sys
12+
13+
14+
def extract_namespace(class_name):
15+
"""Extract namespace from qualified class name."""
16+
# Remove template parameters and anonymous namespace markers
17+
cleaned = re.sub(r"<[^>]*>", "", class_name)
18+
cleaned = re.sub(r"\(anonymous namespace\)::", "", cleaned)
19+
20+
# Split by :: and take all but the last part
21+
parts = cleaned.split("::")
22+
if len(parts) > 1:
23+
return "::".join(parts[:-1])
24+
return ""
25+
26+
27+
def fix_method_name(method):
28+
"""Convert from the logger's method name to a UI-friendly name."""
29+
if method == "notifyOperationReplaced (with op)":
30+
return "replace op with new op"
31+
if method == "notifyOperationReplaced (with values)":
32+
return "replace op with values"
33+
if method == "notifyOperationErased":
34+
return "erase op"
35+
if method == "notifyOperationInserted":
36+
return "insert op"
37+
if method == "notifyOperationModified":
38+
return "modify op"
39+
40+
41+
def parse_line(line):
42+
"""Parse a single line from the input file."""
43+
parts = [part.strip() for part in line.strip().split("|")]
44+
45+
if len(parts) < 3 or parts[0].strip() == "":
46+
return None
47+
48+
class_name = parts[0]
49+
method = parts[1]
50+
operations = parts[2:]
51+
52+
namespace = extract_namespace(class_name)
53+
method = fix_method_name(method)
54+
55+
return {
56+
"className": class_name,
57+
"namespace": namespace,
58+
"method": method,
59+
"operations": operations,
60+
}
61+
62+
63+
def build_reverse_index(entries):
64+
"""Build reverse index from operation names to class entries."""
65+
index = defaultdict(list)
66+
67+
for entry in entries:
68+
for op in entry["operations"]:
69+
index[op].append(
70+
{
71+
"className": entry["className"],
72+
"namespace": entry["namespace"],
73+
"method": entry["method"],
74+
"operations": entry["operations"],
75+
}
76+
)
77+
78+
return dict(index)
79+
80+
81+
def extract_metadata(entries):
82+
"""Extract unique namespaces and methods for filtering."""
83+
namespaces = set()
84+
methods = set()
85+
86+
for entry in entries:
87+
if entry["namespace"]:
88+
namespaces.add(entry["namespace"])
89+
methods.add(entry["method"])
90+
91+
return {"namespaces": sorted(list(namespaces)), "methods": sorted(list(methods))}
92+
93+
94+
def main():
95+
if len(sys.argv) != 3:
96+
print("Usage: python convert_to_json.py input.txt output.json")
97+
sys.exit(1)
98+
99+
input_file = sys.argv[1]
100+
output_file = sys.argv[2]
101+
102+
entries = []
103+
lines = []
104+
105+
try:
106+
with open(input_file, "r", encoding="utf-8") as f:
107+
for line_num, line in enumerate(f, 1):
108+
if not line.strip():
109+
continue
110+
lines.append((line_num, line))
111+
except FileNotFoundError:
112+
print(f"Error: Input file '{input_file}' not found")
113+
sys.exit(1)
114+
115+
for line_num, line in lines:
116+
entry = parse_line(line)
117+
if entry:
118+
entries.append(entry)
119+
else:
120+
print(f"Warning: Skipped malformed line {line_num}: {line.strip()}")
121+
122+
print(f"Parsed {len(entries)} entries")
123+
124+
# Build reverse index
125+
operations_index = build_reverse_index(entries)
126+
print(f"Created index for {len(operations_index)} operations")
127+
128+
# Extract metadata
129+
metadata = extract_metadata(entries)
130+
print(
131+
f"Found {len(metadata['namespaces'])} namespaces and {len(metadata['methods'])} methods"
132+
)
133+
134+
# Create final JSON structure
135+
result = {"operations": operations_index, "metadata": metadata}
136+
137+
directory = os.path.dirname(output_file)
138+
os.makedirs(directory, exist_ok=True)
139+
# Write to output file
140+
with open(output_file, "w", encoding="utf-8") as f:
141+
json.dump(result, f, indent=2, ensure_ascii=False)
142+
143+
print(f"Successfully wrote JSON to {output_file}")
144+
145+
146+
if __name__ == "__main__":
147+
main()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
title: "Pattern Search"
3+
date: 1970-01-01T00:00:00Z
4+
draft: false
5+
---
6+
7+
Search for an operation name below (e.g., `linalg.matvec`) to find a list of
8+
all Pattern classes that insert, erase, or modify that operation.
9+
10+
The search index used here is generated by running all `lit` tests in MLIR with
11+
the additional flag `--pattern-logging-listener`, which produces a record of
12+
each rewrite operation and the names of the operations it affected.
13+
14+
Caveats:
15+
16+
- Some records may be missing due to incomplete test coverage.
17+
- Patterns are only indexed if they define a `debugName`, and while most
18+
patterns have one, they are not required to.
19+
- Patterns defined in PDLL are not supported.
20+
- Dialect Conversion patterns are only partially supported (only insertions).
21+
22+
{{< pattern-search >}}

0 commit comments

Comments
 (0)