Compiler Foundation
Every AI compiler ultimately emits machine code. The chain from your Python model to that machine code goes through one or two intermediate representations — usually MLIR (with multiple dialects) and then LLVM. This module is the substrate: what those IRs are, how passes transform them, and how lowering walks a program down to hardware.
0 / 4 lessons ~60 min total
Module capstone — build it
Write your first MLIR pass — fuse two operations The MLIR ecosystem stops being mysterious the day you watch your own pass rewrite an IR dump.
Advanced · One focused weekend (~12 h, mostly the LLVM build) · Runs on your laptop
Build LLVM + MLIR from source, write a transformation pass in MLIR's pass framework that fuses an `arith.addf` followed by an `arith.mulf` into a single `arith.fma` (fused multiply-add). Run it on a small program; inspect the IR before and after. The artifact is the pass, a test, and an `opt -before -after` diff.
Build it — step by step
01 Build LLVM + MLIR locally 120 min
Clone llvm-project. Configure with CMake using `-DLLVM_ENABLE_PROJECTS=mlir`. Build (this takes 1–2 hours; let it run while you read).
checkpoint You can run `mlir-opt --help` and see the list of available passes. `mlir-translate` is also on PATH.
watch out Building all of LLVM unnecessarily eats a day. Set `-DLLVM_TARGETS_TO_BUILD=X86;NVPTX` to skip targets you don't need.
02 Author the smallest possible MLIR program 20 min
Write a `.mlir` file with a `func.func` that does `%c = arith.addf %a, %b : f32` then `%d = arith.mulf %c, %e : f32`. This is the input your pass will rewrite.
checkpoint Running `mlir-opt program.mlir` echoes back valid MLIR.
03 Skeleton a transformation pass 60 min
In a new directory: write a `Pass.cpp` registering a pass class deriving from `OperationPass<func::FuncOp>`. Use the new pass-manager registration macros. Build it as a shared library (`MyPass.so`).
checkpoint `mlir-opt --load=./MyPass.so --my-pass program.mlir` runs, even if the pass does nothing yet.
watch out MLIR API churns: ensure your tutorial source is for the same MLIR version as your build. Pre-2024 examples rarely compile against current main.
04 Pattern-match and rewrite addf+mulf → fma 120 min
Use `RewritePatternSet` and `OpRewritePattern<arith::MulFOp>`. In `matchAndRewrite`, check that the multiplicand is the result of an `arith::AddFOp`. If so, rewrite to `arith::FmaOp`. Run greedy pattern application.
checkpoint Before pass: 2 ops. After pass: 1 op. `mlir-opt --my-pass program.mlir` shows the transformation.
watch out Forgetting to check that the addf result has only one use — if it's used elsewhere, you can't fuse without duplicating.
05 Add a FileCheck test 40 min
Write a `.mlir` test file with `// RUN: mlir-opt %s --my-pass | FileCheck %s` and `// CHECK-NOT: arith.addf` plus `// CHECK: arith.fma` directives. Add to a `lit` test config and run.
checkpoint `lit` reports PASS for your test.
06 Push to GitHub 40 min
Repo with `Pass.cpp`, `program.mlir`, `test/fuse.mlir`, `CMakeLists.txt`, `README.md` linking to MLIR docs and explaining what the pass does in two paragraphs.
checkpoint A reader who has MLIR built can clone, `cmake --build .`, run the pass, and see the IR change.
You walk away with
A working out-of-tree MLIR pass — your first real compiler engineering artifact Fluency with `mlir-opt`, FileCheck, and the lit testing framework A built copy of LLVM + MLIR — the foundation for any future compiler work The mental model that lets you read MLIR dumps from torch.compile, IREE, JAX, etc. Tools you'll use LLVM 18+ MLIR (LLVM tree) CMake mlir-opt + FileCheck for testing a small linalg program as input