Skip to content

Commit ae83758

Browse files
Adapt Triton plugin to new PluginInfo API and LLVM 23
Rewrite ApproxTritonPlugin.cpp for Triton's new tritonGetPluginInfo() entry point (replacing the old separate C function API). Upgrade StableHLO submodule to fef90093 for LLVM 23 compatibility, rename applyPatternsAndFoldGreedily to applyPatternsGreedily across passes, and fix plugin link/include issues. Add Triton setup guide to AGENTS.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1897b77 commit ae83758

5 files changed

Lines changed: 237 additions & 66 deletions

File tree

AGENTS.md

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,181 @@ If `runtime/examples/example_triton_wo_tuning.py` fails, check in this order:
235235

236236
Prefer confirming the failure stage with the example script before making broad changes.
237237

238+
## Setup Guide: ApproxMLIR with Triton Support
239+
240+
This section walks through building ApproxMLIR's Triton plugin from scratch. The end goal is running `runtime/examples/example_triton_wo_tuning.py`.
241+
242+
### Prerequisites
243+
244+
| Dependency | Version | Notes |
245+
|---|---|---|
246+
| Python | >= 3.9 | 3.10+ recommended |
247+
| CMake | >= 3.20, < 4.0 | |
248+
| Ninja | >= 1.11.1 | |
249+
| C++17 compiler | GCC 11+ or Clang 14+ | |
250+
| PyTorch | >= 2.0 | Must match your CUDA version. On Jetson, use NVIDIA's pip index |
251+
| CUDA toolkit | >= 12.0 | For GPU execution |
252+
253+
### Step 1: Clone Triton
254+
255+
```bash
256+
git clone https://github.com/triton-lang/triton.git
257+
cd triton
258+
git checkout 3f0a0085a # tested commit; newer may work but API may drift
259+
git submodule update --init --recursive
260+
```
261+
262+
### Step 2: Create a Python virtual environment
263+
264+
```bash
265+
python3 -m venv /path/to/envs/triton-dev
266+
source /path/to/envs/triton-dev/bin/activate
267+
pip install --upgrade pip setuptools wheel
268+
pip install pybind11>=2.13.1 ninja cmake
269+
```
270+
271+
Install PyTorch into the venv:
272+
273+
```bash
274+
# x86_64 Linux / Mac:
275+
pip install torch
276+
277+
# Jetson (aarch64, JetPack 6+):
278+
pip install torch --index-url https://pypi.jetson-ai-lab.dev/jp6/cu126
279+
```
280+
281+
### Step 3: Build Triton from source with plugin support
282+
283+
Triton must be built with `TRITON_EXT_ENABLED=ON` so that `libtriton.so` exports symbols needed by external plugins. Without this flag, the plugin will fail to load at runtime.
284+
285+
```bash
286+
# Triton downloads its own LLVM during build. Set a cache directory:
287+
export TRITON_CACHE_PATH=/path/to/triton-cache
288+
289+
# Option A: pip install (simpler, handles LLVM download automatically)
290+
cd triton/python
291+
TRITON_BUILD_WITH_CCACHE=true pip install -e . \
292+
--config-settings=cmake.define.TRITON_EXT_ENABLED=ON
293+
294+
# Option B: cmake build (more control, useful for debugging)
295+
mkdir -p /path/to/build/triton-cmake
296+
cd /path/to/build/triton-cmake
297+
298+
# Triton bundles a specific LLVM. Download it first:
299+
python triton/python/setup.py --llvm-download # or let cmake find it
300+
# The downloaded LLVM lands at: triton/.triton-home/.triton/llvm/llvm-<hash>-<platform>/
301+
302+
LLVM_SYSPATH=/path/to/triton/.triton-home/.triton/llvm/llvm-7f77ca0d-<platform>
303+
304+
cmake /path/to/triton \
305+
-G Ninja \
306+
-DCMAKE_BUILD_TYPE=Release \
307+
-DLLVM_EXTERNAL_LIT=$(which lit || echo "") \
308+
-DTRITON_EXT_ENABLED=ON \
309+
-DCMAKE_CXX_FLAGS="-Wno-error=attributes"
310+
ninja -j$(nproc) triton
311+
```
312+
313+
> **Jetson note:** Use `ninja -j2` instead of `-j$(nproc)` — the Jetson Orin Nano has limited RAM and will OOM with more parallel jobs.
314+
315+
If you used Option B (cmake), make `triton` importable in Python:
316+
317+
```bash
318+
# Create a .pth file so Python finds the Triton package
319+
echo "/path/to/triton/python" > \
320+
$(python -c "import site; print(site.getsitepackages()[0])")/triton-dev.pth
321+
```
322+
323+
Verify Triton is importable:
324+
325+
```bash
326+
python -c "import triton; print(triton.__version__)"
327+
```
328+
329+
### Step 4: Clone and build the ApproxMLIR plugin
330+
331+
```bash
332+
git clone https://github.com/moomoohorse321/approxMLIR.git
333+
cd approxMLIR
334+
git submodule update --init --recursive
335+
```
336+
337+
Triton downloads a pre-built LLVM during its build. The plugin must be built against that same LLVM — not a separately installed one. Find it at:
338+
339+
```bash
340+
# The hash comes from triton/cmake/llvm-hash.txt
341+
LLVM_DIR=/path/to/triton/.triton-home/.triton/llvm/llvm-7f77ca0d-<platform>/lib/cmake/llvm
342+
MLIR_DIR=/path/to/triton/.triton-home/.triton/llvm/llvm-7f77ca0d-<platform>/lib/cmake/mlir
343+
```
344+
345+
Replace `<platform>` with your system:
346+
- `ubuntu-x64` for x86_64 Linux
347+
- `ubuntu-arm64` for aarch64 / Jetson
348+
- `macos-arm64` for Apple Silicon Mac
349+
350+
Build the plugin:
351+
352+
```bash
353+
mkdir -p /path/to/build/approx-triton-plugin
354+
cd /path/to/build/approx-triton-plugin
355+
356+
cmake /path/to/approxMLIR/external-tools/approx-triton-plugin \
357+
-G Ninja \
358+
-DMLIR_DIR=$MLIR_DIR \
359+
-DLLVM_DIR=$LLVM_DIR \
360+
-DTRITON_DIR=/path/to/triton \
361+
-DTRITON_BUILD_DIR=/path/to/build/triton-cmake \
362+
-DAPPROX_MLIR_DIR=/path/to/approxMLIR
363+
364+
ninja -j$(nproc) # or ninja -j2 on Jetson
365+
```
366+
367+
Output: `lib/libApproxTritonPlugin.so` (or `.dylib` on Mac).
368+
369+
### Step 5: Install the approx_runtime Python package
370+
371+
```bash
372+
cd /path/to/approxMLIR/runtime
373+
pip install -e .
374+
```
375+
376+
### Step 6: Set environment variables and run
377+
378+
```bash
379+
# Required: tells Triton where to find the plugin
380+
export TRITON_PLUGIN_PATHS=/path/to/build/approx-triton-plugin/lib/libApproxTritonPlugin.so
381+
export TRITON_PASS_PLUGIN_PATH=$TRITON_PLUGIN_PATHS
382+
383+
# Required if Triton was built with cmake (Option B), not pip:
384+
export TRITON_BACKENDS_IN_TREE=1
385+
386+
# Run the example
387+
python runtime/examples/example_triton_wo_tuning.py
388+
```
389+
390+
Expected output:
391+
392+
```
393+
kernel launch ok
394+
ttir length: 6270
395+
substitution active: True
396+
max|hooked - exact|: ~0.02
397+
max|hooked - approx_ref|: 0.0
398+
```
399+
400+
> **Tip:** Add these exports to your venv's `bin/activate` script so you don't need to set them every time.
401+
402+
### Troubleshooting
403+
404+
| Symptom | Cause | Fix |
405+
|---|---|---|
406+
| `Failed to load plugin ... undefined symbol` | Plugin built against wrong LLVM | Rebuild plugin using LLVM from `triton/.triton-home/.triton/llvm/` |
407+
| `operation being parsed with an unregistered dialect` | `TRITON_EXT_ENABLED` was OFF when building Triton | Rebuild Triton with `-DTRITON_EXT_ENABLED=ON` |
408+
| `0 active drivers` | cmake-built Triton can't find backends | `export TRITON_BACKENDS_IN_TREE=1` |
409+
| `No module named 'triton'` | Triton not on Python path | Add a `.pth` file or `pip install -e python` |
410+
| OOM during build on Jetson | Too many parallel compile jobs | Use `ninja -j2` |
411+
| `libcudss.so.0: cannot open` (Jetson) | PyTorch needs libcudss at non-standard path | `export LD_LIBRARY_PATH=/usr/lib/aarch64-linux-gnu/libcudss/12:$LD_LIBRARY_PATH` |
412+
238413
## Files Worth Reading First
239414

240415
For general ApproxMLIR understanding:

external-dialects/stablehlo

Submodule stablehlo updated 243 files

external-tools/approx-triton-plugin/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ if(NOT TRITON_DIR)
2323
message(FATAL_ERROR "Set -DTRITON_DIR=/path/to/triton")
2424
endif()
2525
include_directories(${TRITON_DIR}/include)
26+
include_directories(${TRITON_DIR}) # for python/src/ir.h referenced by PluginUtils.h
2627
if(TRITON_BUILD_DIR)
2728
include_directories(${TRITON_BUILD_DIR}/include) # generated headers
2829
endif()

external-tools/approx-triton-plugin/pass/ApproxTritonPlugin.cpp

Lines changed: 59 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,14 @@
2626
#include "triton/Tools/PluginUtils.h"
2727
#include "llvm/Config/llvm-config.h"
2828

29+
using namespace mlir::triton;
30+
2931
// ---------------------------------------------------------------------------
30-
// Triton plugin entry points
31-
//
32-
// Triton's pass plugin loader calls these three C functions (defined in
33-
// triton/Tools/PluginUtils.h) from the shared library:
34-
// - tritonRegisterPluginPass(passName)
35-
// - tritonAddPluginPass(pm, passName)
36-
// - tritonEnumeratePluginPasses(count, names)
32+
// Pass creation helper
3733
// ---------------------------------------------------------------------------
3834

3935
namespace {
4036

41-
/// Pass name constants — these are the names users reference when adding
42-
/// passes to Triton's pipeline.
43-
constexpr const char *kPassNames[] = {
44-
"emit-approx",
45-
"emit-management",
46-
"config-approx",
47-
"pre-emit-transform",
48-
"transform-approx",
49-
"finalize-approx",
50-
};
51-
constexpr uint32_t kNumPasses = sizeof(kPassNames) / sizeof(kPassNames[0]);
52-
5337
std::unique_ptr<mlir::Pass> createPassByName(const char *name) {
5438
llvm::StringRef n(name);
5539
if (n == "emit-approx")
@@ -70,57 +54,67 @@ std::unique_ptr<mlir::Pass> createPassByName(const char *name) {
7054
} // namespace
7155

7256
// ---------------------------------------------------------------------------
73-
// Plugin API (exported as C symbols from the shared library)
57+
// Callback functions for each pass
7458
// ---------------------------------------------------------------------------
7559

76-
TRITON_PLUGIN_API
77-
tritonRegisterPluginPass(const char *passName) {
78-
auto pass = createPassByName(passName);
79-
if (!pass)
80-
return TP_GENERIC_FAILURE;
81-
// Register the pass so it can be found by name in the pipeline.
82-
mlir::registerPass([passName]() { return createPassByName(passName); });
83-
return TP_SUCCESS;
84-
}
60+
#define DEFINE_PASS_CALLBACKS(funcName, passName) \
61+
static void add_##funcName(mlir::PassManager *pm, \
62+
const std::vector<std::string> &) { \
63+
pm->addPass(createPassByName(passName)); \
64+
} \
65+
static void register_##funcName() { \
66+
mlir::registerPass([]() { return createPassByName(passName); }); \
67+
}
8568

86-
TRITON_PLUGIN_API
87-
tritonAddPluginPass(mlir::PassManager *pm, const char *passName) {
88-
auto pass = createPassByName(passName);
89-
if (!pass)
90-
return TP_GENERIC_FAILURE;
91-
pm->addPass(std::move(pass));
92-
return TP_SUCCESS;
93-
}
69+
DEFINE_PASS_CALLBACKS(emit_approx, "emit-approx")
70+
DEFINE_PASS_CALLBACKS(emit_management, "emit-management")
71+
DEFINE_PASS_CALLBACKS(config_approx, "config-approx")
72+
DEFINE_PASS_CALLBACKS(pre_emit_transform, "pre-emit-transform")
73+
DEFINE_PASS_CALLBACKS(transform_approx, "transform-approx")
74+
DEFINE_PASS_CALLBACKS(finalize_approx, "finalize-approx")
9475

95-
TRITON_PLUGIN_API
96-
tritonEnumeratePluginPasses(uint32_t *passCount, const char **passNames) {
97-
if (!passCount)
98-
return TP_GENERIC_FAILURE;
99-
*passCount = kNumPasses;
100-
if (passNames) {
101-
for (uint32_t i = 0; i < kNumPasses; ++i)
102-
passNames[i] = kPassNames[i];
103-
}
104-
return TP_SUCCESS;
105-
}
76+
#undef DEFINE_PASS_CALLBACKS
77+
78+
// ---------------------------------------------------------------------------
79+
// Dialect registration callback
80+
// ---------------------------------------------------------------------------
10681

107-
TRITON_PLUGIN_API
108-
tritonEnumeratePluginDialects(uint32_t *dialectCount,
109-
const char **dialectNames) {
110-
if (!dialectCount)
111-
return TP_GENERIC_FAILURE;
112-
*dialectCount = 1;
113-
if (!dialectNames)
114-
return TP_SUCCESS;
115-
dialectNames[0] = "approx";
116-
return TP_SUCCESS;
82+
static void registerApproxDialect(mlir::DialectRegistry *registry) {
83+
registry->insert<mlir::approx::approxDialect>();
84+
mlir::func::registerInlinerExtension(*registry);
11785
}
11886

119-
TRITON_PLUGIN_API_TYPE(::mlir::DialectPluginLibraryInfo)
120-
tritonGetDialectPluginInfo(const char * /*name*/) {
121-
return {MLIR_PLUGIN_API_VERSION, "ApproxPlugin", LLVM_VERSION_STRING,
122-
[](mlir::DialectRegistry *registry) {
123-
registry->insert<mlir::approx::approxDialect>();
124-
mlir::func::registerInlinerExtension(*registry);
125-
}};
87+
// ---------------------------------------------------------------------------
88+
// Plugin entry point (new Triton PluginInfo API)
89+
// ---------------------------------------------------------------------------
90+
91+
static const char *PLUGIN_NAME = "ApproxPlugin";
92+
static const char *VERSION = "0.1.0";
93+
94+
TRITON_PLUGIN_API plugin::PluginInfo *tritonGetPluginInfo() {
95+
static plugin::PassInfo passes[] = {
96+
{"emit-approx", VERSION, add_emit_approx, register_emit_approx},
97+
{"emit-management", VERSION, add_emit_management, register_emit_management},
98+
{"config-approx", VERSION, add_config_approx, register_config_approx},
99+
{"pre-emit-transform", VERSION, add_pre_emit_transform, register_pre_emit_transform},
100+
{"transform-approx", VERSION, add_transform_approx, register_transform_approx},
101+
{"finalize-approx", VERSION, add_finalize_approx, register_finalize_approx},
102+
};
103+
104+
static plugin::DialectInfo dialects[] = {
105+
{"approx", VERSION, registerApproxDialect},
106+
};
107+
108+
static plugin::PluginInfo info = {
109+
TRITON_PLUGIN_API_VERSION,
110+
PLUGIN_NAME,
111+
VERSION,
112+
passes,
113+
sizeof(passes) / sizeof(passes[0]),
114+
dialects,
115+
sizeof(dialects) / sizeof(dialects[0]),
116+
nullptr, // no custom ops
117+
0,
118+
};
119+
return &info;
126120
}

external-tools/approx-triton-plugin/pass/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ target_link_libraries(ApproxTritonPlugin PRIVATE
4949
${LLVM_LIB_DIR}/libMLIRQuantUtils.a
5050
${LLVM_LIB_DIR}/libMLIRComplexDialect.a
5151
${LLVM_LIB_DIR}/libMLIRFuncInlinerExtension.a
52+
${LLVM_LIB_DIR}/libMLIRPass.a
5253
${LLVM_LIB_DIR}/libMLIRIR.a
5354
${LLVM_LIB_DIR}/libMLIRDialect.a
5455
-Wl,--end-group

0 commit comments

Comments
 (0)