TRACK: iree | DIFFICULTY: 3 | NEEDS: ../.venv (iree-base-compiler / -runtime 3.11), tools/mca_loop.sh
FILES: matmul.mlir (tensor version of 04's payload), run_iree.sh
IREE (with its ARM backend) is the reference this lab measures against. Concretely, that means: for a kernel you're optimising in a production MLIR backend, compile the same computation with IREE for the same CPU, and use it as a target number (how fast can MLIR-generated code be here?) and a source of techniques (which strategy, which tile sizes, which lowering did it pick?). This lab does that for the 512³ matmul from track 04, on x86 (measured) and AArch64 (compiled, then modelled with llvm-mca).
./run_iree.sh
Real output (pinned P-core, single thread, --iree-llvmcpu-target-cpu=host):
iree_default median 233 ms 1.15 GFLOP/s iree_datatiling median 6.03 ms 44.52 GFLOP/s iree_dt_ukernels median 6.01 ms 44.66 GFLOP/s
And ours, from lab 04/01: naive 1.16, best transform schedule ~30–46 (noisy; 4×16 tile around 42–46).
Three findings, each worth knowing before you ever cite "IREE's number":
--iree-opt-data-tiling), which is off by default in this
release. A reference number without its flags is meaningless.--iree-llvmcpu-enable-ukernels=all) add nothing here: for f32
on x86 the codegen path is already as good. (For int8 on Arm with i8mm,
the ukernels are the hand-written mmt4d_arm_64_i8mm.c, lab 05/04.)../.venv/bin/iree-compile matmul.mlir --iree-hal-target-device=local --iree-hal-local-target-device-backends=llvm-cpu \ --iree-llvmcpu-target-cpu=host --iree-hal-dump-executable-configurations-to=out/cfg -o /dev/null grep -oE 'translation_info<pipeline = [A-Za-z]+|lowering_config = #iree_cpu[^}]*' out/cfg/*.mlir
lowering_config = #iree_cpu.lowering_config<cache_parallel = [64, 64, 0], distribution = [64, 64, 0], vector_common_parallel = [1, 1, 0], vector_reduction = [0, 0, 8]> translation_info<pipeline = CPUDoubleTilingExpert
Read the default decision: 64×64 cache tiles, then vector tiles of [1, 1] over (m, n) with a vector reduction of 8 along k: every output element is a dot product over K, reading B down a column. That's lab 04/01's naive access pattern, vectorized. Hence 1.15 GFLOP/s.
With data tiling the dispatch becomes Mmt4dTilingExpert (plus two
CPUDataTiling "encoding" dispatches, the packs), exactly the
pack → mmt4d → unpack structure from lab 05/04.
These configs come from KernelDispatch.cpp:
$IREE_LLVMCPU/KernelDispatch.cpp (see tools/env.sh).
The other dump flags worth knowing:
--iree-hal-dump-executable-sources-to=DIR (the dispatch as linalg, before
codegen) and --iree-hal-dump-executable-intermediates-to=DIR (.ll before and
after LLVM opt, .o, .s).
../.venv/bin/iree-compile matmul.mlir --iree-hal-target-device=local --iree-hal-local-target-device-backends=llvm-cpu \ --iree-llvmcpu-target-triple=aarch64-unknown-linux-gnu --iree-llvmcpu-target-cpu=neoverse-v1 \ --iree-opt-data-tiling=true --iree-hal-dump-executable-intermediates-to=out/a64_true -o out/mm_a64_true.vmfb MCA_FUNC=matmul_dispatch_0_matmul_512x512x512_f32 ../tools/mca_loop.sh \ out/a64_true/module_matmul_linked_embedded_elf_arm_64.s -mtriple=aarch64 -mcpu=neoverse-v1
Results (Neoverse-V1 model, 4 NEON FMA pipes → 4.0 fmla/cycle peak):
| microkernel | instructions | fmla | cycles/iter | fmla/cycle |
|---|---|---|---|---|
| IREE, data tiling (mmt4d) | 23 | 16 | 4.0 | 4.0 = 100% |
| ours, lab 05/03 8×8 | 29 | 16 | 4.3 | 3.7 = 93% |
| ours, lab 05/02 SVE (no hoist) | 14 | 2 | 3.5 | 0.57 |
| IREE default (no data tiling) | 109 | 64 | 16.3 | 3.9 (!) |
What to take from it:
fmla v.4s by-element on 16
accumulators), the same tile llvm-mca ranked best in lab 05/03. Independent
confirmation that the method works.ldp q), with no per-row address arithmetic. That's
what packing buys even when the FMA count is equal.iree-compile it for the same target, with the flags that matter
(data tiling, ukernels, target cpu/features), and dump configurations.KernelDispatch.cpp, Passes.cpp) is the recipe.--iree-llvmcpu-target-cpu-features=+sve (with neoverse-v1). Does IREE use SVE for this matmul?+i8mm and data tiling. Find smmla in the .s../run_iree.sh with --task_topology_max_group_count=4 (4 threads). How does IREE scale?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.