- Python 69.5%
- C++ 26.1%
- CMake 2%
- Jupyter Notebook 1.7%
- Shell 0.3%
- Other 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Closes item 6d of #593 (the "branch helper that also wires the successor"). **Stacked on #623 (item 6b)** — base branch is `mbb-double-terminator-guard`. Review/merge #623 first. MIR tracks a block's CFG **successor list** and its **branch terminator operands** separately, so emitting a branch and wiring the matching successor edge are two steps that must stay in sync — forgetting the `add_successor` produces MIR whose terminator points somewhere the CFG doesn't list, which the verifier only catches later. Two additive helpers fold both: - **`branch(dest)`** — `G_BR` to `dest` + the successor edge from the current block; returns the `G_BR` so its target can be repointed. - **`cond_branch(cond, true_block, false_block)`** — `G_BRCOND` on `cond` to `true_block`, fall-through `G_BR` to `false_block`, and both successor edges, in one call. Returns the fall-through `G_BR` (the repointable one). `branch`/`cond_branch` sit on top of the existing surface — `build_br`, `build_brcond`, and `add_successor` are unchanged. The successor edge attaches to `getMBB()`, the builder's current insert block, which is exactly the block the terminator lands in. Because this is stacked on 6b, both helpers route through the same `requireNotTerminated` double-terminator guard as `build_br`/`build_brcond`, so neither appends a terminator past a barrier (`test_branch_helpers_reject_second_terminator`). Adopted at the call sites to show the ergonomics win: - the if-diamond primitive test (`test_build_if_diamond_with_phi`): the `add_successor` × 2 + `build_brcond` + `build_br` block becomes one `cond_branch`, and each closing `build_br` + `add_successor` becomes `branch`. - the DSL lowering in `machine_cf.py` (`_MIRIfOp`, `_MIRLoop`): the four-line brcond/br/two-successor blocks collapse to a single `cond_branch`, and the preheader/body back-edge `build_br` + `add_successor` pairs to `branch`. |
||
| .github | ||
| docs/images | ||
| pages | ||
| projects | ||
| scripts | ||
| third_party | ||
| .clang-format | ||
| .clang-tidy | ||
| .gitignore | ||
| .gitmodules | ||
| CMakeLists.txt | ||
| LICENSE | ||
| README.md | ||
| requirements-dev.txt | ||
(pronounced "you-dsl")
Embedded Universal DSL: a good DSL for us, by us
This repository contains the source code for EUDSL, a toolkit for the construction of
embedded DSLs, in arbitrary languages, for targeting MLIR.
FYI: this project is currently "alpha" quality.
Currently, there are seven components:
- eudsl-tblgen: Python bindings to LLVM's TableGen library;
- eudsl-nbgen: A source-to-source translator that translates MLIR headers1 into direct
nanobindbindings; - eudsl-py: Direct Python bindings to MLIR, generated using
eudsl-nbgen;- Currently only TableGen outputs (various
*.h.incfiles generated bymlir-tblgen) are automatically translated but theeudsl-nbgentool can be manually run to translate any MLIR header (to varying degrees of success); - See projects/eudsl-py/tests for a few examples of what these bindings look like;
- Currently only TableGen outputs (various
- mlir-python-bindings: Scripts/CMake for nightly builds of the upstream MLIR Python bindings;
- Available via
pip install mlir-python-bindings -f https://llvm.github.io/eudsl.
- Available via
- eudsl-python-extras: Extra utilities for the upstream MLIR Python bindings;
- Available via
pip install eudsl-python-extras -f https://llvm.github.io/eudslif used with the upstream bindings. - In reality, this package is meant to work in concert with any set of "host bindings" (some distribution of the actual MLIR Python bindings).
So that means the pip install should be amended to
where$ EUDSL_PYTHON_EXTRAS_HOST_PACKAGE_PREFIX=<YOUR_HOST_MLIR_PYTHON_PACKAGE_PREFIX> \ pip install eudsl-python-extras -f https://llvm.github.io/eudslEUDSL_PYTHON_EXTRAS_HOST_PACKAGE_PREFIXis (as it says) the package prefix for your chosen host bindings. When in doubt about this prefix, it is everything up untilirwhen you import your bindings, e.g., inimport torch_mlir.ir,torch_mliris theEUDSL_PYTHON_EXTRAS_HOST_PACKAGE_PREFIXfor the torch-mlir bindings.
- Available via
- mlir-python-mcp: An MCP server exposing a persistent MLIR Python REPL, so that a coding agent can build and transform IR through the bindings rather than by editing MLIR text;
- Available via
pip install mlir-python-mcp -f https://llvm.github.io/eudsl. - See projects/mlir-python-mcp/README.md for the
.mcp.jsonsnippet and the list of tools.
- Available via
- eudsl-llvmpy: Python bindings for LLVM IR (and Machine IR), plus small DSLs for authoring both from Python;
- The bindings are a hand-written
nanobindwrapper over the LLVM C++ API, so the Python class hierarchy mirrorsllvm::; the DSL lowers a decorated Python function (with ordinary arithmetic andif/while/for) to a compiledllvm::Function. - A third surface,
llvm.mir, reaches one level lower — LLVM's post-instruction-selection Machine IR — with the same split: hand-written bindings over theMachineFunction/MachineInstrobject model plus a@machine_functionDSL for building generic (GlobalISel) MIR. - Available via
pip install eudsl-llvmpy -f https://llvm.github.io/eudsl. - See projects/eudsl-llvmpy/README.md and projects/eudsl-llvmpy/tests.
- The bindings are a hand-written
Wasm Playground
We currently provide two online playgrounds where you can try out the WebAssembly version of mlir-python-bindings and eudsl-python-extras directly in your browser:
-
https://llvm.github.io/eudsl/jupyter – A JupyterLite instance with a Pyodide kernel. You can install the MLIR Python bindings with:
await piplite.install("mlir-python-bindings"). -
https://llvm.github.io/eudsl/console – A Pyodide-based REPL with
mlir-python-bindingsandeudsl-python-extraspreloaded. Just run:from mlir.ir import *to start coding.
Getting started
Python wheels of all the tools are available at the eudsl release page.
They are also pip install-able with .e.g
$ pip install eudsl-py -f https://llvm.github.io/eudsl
// or
$ pip install mlir-python-bindings -f https://llvm.github.io/eudsl
// or
$ pip install eudsl-python-extras -f https://llvm.github.io/eudsl
eudsl-py has a slowly growing set of tests @ projects/eudsl-py/tests.
If you don't want to install locally, here is a colab notebook minimal working example.
Developing/building
Strong recommendation: check the CI scripts @ .github/workflows - they do a fresh checkout and build on every commit and are written to be read by a non-CI expert.
Firstly, you need a distribution of LLVM. You can build LLVM from source using our submodule by doing (on Mac/Linux or mingw):
$ cd <EUDSL_CHECKOUT_DIR>
$ ./scripts/build_llvm.sh
Alternatively you can download a distribution for your platform from the llvm release page.
Then each of the above tools can both be built as a conventional, standalone, CMake project and as a Python wheel. The wheel build looks something like:
$ cd <EUDSL_CHECKOUT_DIR>
$ export CMAKE_PREFIX_PATH=$PWD/llvm-install
$ pip wheel projects/eudsl-nbgen -w wheelhouse -v
$ pip wheel projects/eudsl-py -w wheelhouse -v --find-links $PWD/wheelhouse
Note, the trailing --find-links $PWD/wheelhouse on pip wheel projects/eudsl-py is because eudsl-nbgen is a dependency of eudsl-py (that can be satisfied using the eudsl-nbgen wheel).
If you want to build an individual tool via CMake you can do something like:
$ cd <EUDSL_CHECKOUT_DIR>
$ pip install -r requirements.txt
$ export CMAKE_PREFIX_PATH=$PWD/llvm-install
$ cmake -B $PWD/eudsl-nbgen-build -S $PWD/projects/eudsl-nbgen -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PWD/eudsl-nbgen-install
$ cmake --build "$PWD/eudsl-build" --target install
If you want to build all the tools at once using CMake you can use the root CMakeLists.txt.
Note, in this case, eudsl-nbgen will automatically be built prior to eudsl-py.
If you want to build all the tools at once using CMake directly against third_party/llvm-project then (roughly) the CMake invocation is:
cmake -GNinja -B build -S <EUDSL_CHECKOUT_DIR>/third_party/llvm-project/llvm \
-DLLVM_EXTERNAL_PROJECTS=EUDSL \
-DLLVM_EXTERNAL_EUDSL_SOURCE_DIR=<EUDSL_CHECKOUT_DIR> \
-DLLVM_BUILD_LLVM_DYLIB=ON \
-DLLVM_ENABLE_PROJECTS=clang;mlir
Footnotes
-
Yes C++ headers... ↩︎