TRACK: setup | DIFFICULTY: 1 | NEEDS: git, cmake, ninja, a C++ compiler, ~25 GB free disk
FILES: check_env.sh (the verifier), ../tools/env.sh (the shell setup), ../tools/env.local.sh.example
Unlike the rest of debug_lab, these labs do not run on a stock distro
toolchain. They need one consistent LLVM/MLIR build — mlir-opt,
mlir-translate, mlir-runner, opt, llc and clang all from the same
commit. Mixing a distro llc with a newer mlir-translate works most of the
time and fails confusingly the rest of the time, which is the worst
possible behaviour for a lab whose whole point is reading exact output.
The good news: most tracks need only that one build. Triton, IREE and qemu are per-track extras, and the table in STEP 5 says exactly what you lose without each one. You can do tracks 01–06 and 09 with nothing but LLVM.
Distros increasingly package the MLIR tools. If you get a version here, you may be able to skip the build entirely.
$ mlir-opt --version
If that prints a version, check that clang --version reports the same
major version. If both agree, jump to STEP 4.
If it is not found, search your package manager before building — a package is minutes, a build is an hour:
$ apt-cache search mlir # Debian / Ubuntu $ dnf search mlir # Fedora $ pacman -Ss mlir # Arch
Two things to check on a packaged install: that it includes
libmlir_runner_utils.so (several labs JIT-execute and need it), and that
mlir-runner exists. It was called mlir-cpu-runner before LLVM 20; if you
only have the old name, export MLIR_RUNNER=mlir-cpu-runner and substitute it
where the labs say mlir-runner.
A shallow clone is enough unless you plan to bisect upstream.
$ git clone --depth 1 https://github.com/llvm/llvm-project.git ~/llvm-project $ cd ~/llvm-project
Configure. Every option here earns its place, and the comments say which lab needs it:
$ cmake -G Ninja -S llvm -B build \ -DLLVM_ENABLE_PROJECTS="mlir;clang" \ -DLLVM_TARGETS_TO_BUILD="X86;AArch64" \ -DCMAKE_BUILD_TYPE=Release \ -DLLVM_ENABLE_ASSERTIONS=ON \ -DMLIR_ENABLE_BINDINGS_PYTHON=ON \ -DLLVM_CCACHE_BUILD=ON
mlir;clang — clang must come from the same build, because tracks 02, 04 and
05 hand mlir-translate output straight to clang.X86;AArch64 — AArch64 is not optional: tracks 05 and 07 cross-compile to it.
Add your host arch if it is neither.LLVM_ENABLE_ASSERTIONS=ON — this is what gives you -debug-only and pass
statistics. Without it, tracks 06 and 09 lose their main instrument. A release
build without assertions still runs every other lab.MLIR_ENABLE_BINDINGS_PYTHON=ON — only track 10 needs it. Drop it to save
build time if you are skipping that track.Then build. This is the long part:
$ ninja -C build
Budget roughly 20–30 GB of disk and 30–90 minutes on a modern
multi-core machine; both vary enough with core count and linker that you should
measure rather than trust the range. If you are short on RAM, add
-DLLVM_PARALLEL_LINK_JOBS=1 to the cmake line — LLVM's link steps are the
memory spike, and an OOM at 95 % is a miserable way to find that out.
To build only what the labs invoke, rather than all of LLVM:
$ ninja -C build mlir-opt mlir-translate mlir-runner opt llc clang \ llvm-mca FileCheck llvm-lit llvm-reduce mlir-reduce not
Your paths go in tools/env.local.sh, which is not tracked by git. That is
deliberate: nobody should have to edit a tracked file to use these labs, and no
one's home directory should end up in the repository.
$ cp tools/env.local.sh.example tools/env.local.sh $ $EDITOR tools/env.local.sh # set LLVM_BUILD, and LLVM_SRC if you cloned it
Then source the environment. Every lab assumes you have done this in the shell you are working in:
$ source tools/env.sh
That puts one toolchain on PATH and defines the helpers the labs use:
mrun (JIT-run a lowered module), lower_std (the textbook
tensor-to-LLVM pipeline), $LOWER_STD / $LOWER_SVE (those pipelines as
strings), a64cc / a64run (cross-compile and run under qemu), and mca_v2.
$ 00_setup/check_env.sh
It prints one line per tool: OK, WARN or MISSING, and for anything missing
it names the fix. Two results are worth understanding rather than just fixing:
WARN assertions build — your LLVM was built without assertions. Labs
06/01 and 09 use -debug-only and pass statistics, which do not exist in such
a build. Everything else works.WARN headers != build — your LLVM source tree is at a different commit
than your build. Harmless until you write out-of-tree C++ (track 09), where
it produces link errors that look like missing symbols rather than a version
mismatch. Lab 09 STEP 0 covers this, and 09_write_a_pass/sync_headers.sh
fixes it.WARN governor is about measurement noise, not correctness — see STEP 5.
Nothing below is needed for tracks 01, 02, 03, 06 or 09.
| extra | how | tracks | without it |
|---|---|---|---|
| qemu-aarch64 + sysroot | tools/a64-setup.sh at the repo root — no sudo, it installs under ~/.local | 02/04, 05, 07/02 | You can still compile to AArch64 and read the asm; you cannot run it, so correctness claims become "it compiled" |
| Triton | python3 -m venv .venv && .venv/bin/pip install numpy triton | 07 | No TTIR to dump. The lab's pasted TTIR is still readable, but you are reading rather than doing |
| IREE (runtime) | .venv/bin/pip install iree-base-compiler iree-base-runtime | 08 | No reference numbers of your own |
| IREE (source) | git clone https://github.com/iree-org/iree, then set IREE_SRC | 08, 11 | The "go read how they decided that" steps. Track 11 is only source reading, so it needs this |
| MLIR Python bindings | built by MLIR_ENABLE_BINDINGS_PYTHON=ON above, plus a venv on the same Python version the bindings were built for | 10 | Track 10 does not run |
| perf | your distro's package; may need kernel.perf_event_paranoid lowered | 04/02, 07/02 | The profile steps. These labs are built around "profile before you touch the compiler", so this one costs more than it looks |
| CPU pinning | taskset, via tools/pin.sh | 04, 05 | Much noisier timings |
On the last two: this lab's own numbers were taken on a laptop with 30–50 % run-to-run variation. That is why the labs insist on explaining a speedup with an artifact — instruction counts, spill counts, page faults — rather than a stopwatch. Treat a ratio under 2× as unproven until you have repeats or a noise-free counter, whatever your machine.
check_env.sh and write down every WARN. Decide for each whether you
are going to fix it or work around it, before you start track 01 — that
decision is easier now than halfway through a lab.for t in mlir-opt clang llc opt; do $t --version | head -1; done.
All four should agree. If they do not, PATH is finding a distro tool.echo "$LOWER_STD" and read it. It is 8 lines and it is the pipeline behind
most of tracks 01–04; you will meet every pass in it individually.A lab is done when you can say what it showed on your machine — not when you have read it.
It decides which problems come first, which drills open, which labs you see and how the Learn surface is organised. Change it any time from the switch in the top bar, or press Escape to look around first.