Chapter 10 exercises¶
This chapter's implementation work is three standalone labs in labs/ch10-*. Each one ships a specification (SPEC.md) and the smallest possible test contract, and you design everything else. Run the tests after every step:
./course test 10 # builds, then runs every test labelled ch10
ctest --test-dir build/<preset> -L ch10 -R IrBuild # one lab's suite while iterating
Before you start, every ch10 test fails with TODO(ch10): …. That's expected: each message names the lab and the requirement that fixes it.
Stuck? Work through the hints in each spec in order. The reference solutions are in solutions/labs/ch10-*/src/, but only look at them after you've passed the tests, or after an honest hour.
L1 · Build IR with IRBuilder¶
Contract: buildFib, buildHorner and buildDispatch in labs/ch10-irbuild/include/irbuild/Build.h (stubbed in labs/ch10-irbuild/src/Stub.cpp; your code goes anywhere under labs/ch10-irbuild/src/)
Spec: labs/ch10-irbuild/SPEC.md
Tests: ch10.IrBuild.*, tests/ch10/lit/irbuild-*.test
Build three functions in memory, specified only by what they compute: an iterative Fibonacci with phi-carried loop state, a Horner polynomial evaluator reading coefficients through a GEP, and a switch-based dispatcher. The tests verify each module, check its shape and JIT-compile it with ORC LLJIT against a C++ reference on hundreds of inputs. Lessons: 10.1, 10.2, 10.3.
Hint 1 — where to start
Draw each CFG on paper first, then create every block before emitting into any of them. buildDispatch has no loop, so start there.
Hint 2 — the key idea
A phi's back-edge value does not exist when you create the phi: create it with CreatePHI(Ty, 2), build the loop body, then addIncoming both edges (Lesson 10.2, Theorem 10.2.13).
Done when: ctest -L ch10 -R 'IrBuild|irbuild' passes.
L2 · An IR inspection and rewriting tool¶
Contract: the ch10-tool --stats|--def-use|--rewrite-pow2 <file.ll> command line, entered through irtool::run in labs/ch10-irtool/include/irtool/Tool.h
Spec: labs/ch10-irtool/SPEC.md (exact output formats)
Tests: ch10.IrTool.ExitCodes, tests/ch10/lit/tool-*
Parse and verify IR with proper error reporting, walk the ownership tree for statistics, print def-use chains in a canonical order (not use-list order), and rewrite multiplications, unsigned divisions and remainders by powers of two into shifts and masks, while iterating, keeping flags right and preserving meaning under lli. Lessons: 10.1, 10.2, 10.4, 10.7.
Hint 1 — where to start
Get R1 (usage and error exit codes) and --stats working first; they exercise parsing, verifying and walking Module → Function → BasicBlock → Instruction.
Hint 2 — the key idea
For the rewrite, create the replacement before the old instruction (iterator position), takeName, RAUW, erase, all inside make_early_inc_range(instructions(F)) (Theorem 10.1.14).
Done when: ctest -L ch10 -R 'IrTool|ch10.lit' passes.
L3 · Comparison lab: one analysis three ways, one function on two engines¶
Contract: findPatterns(F, Style), runInterpreter, runLLJIT in labs/ch10-compare/include/apicmp/Compare.h
Spec: labs/ch10-compare/SPEC.md
Tests: ch10.Compare.*, ch10.lab.bench-smoke
Write the same peephole analysis (nine pattern kinds) with raw casts, as an InstVisitor and with PatternMatch, and make all three agree on a corpus and on 600 random functions. Then run the same IR function through the ExecutionEngine interpreter and ORC LLJIT, with errors reported as llvm::Error. Finally measure with ch10-apibench and fill in the table in the spec. Lessons: 10.4, 10.5, 10.7, 10.8.
Hint 1 — where to start
Write the raw-cast style against inputs/patterns.ll, whose comments give every instruction's index and expected kind.
Hint 2 — the key idea
In LLVM 23, m_SMax matches only the intrinsic, and m_c_Add(m_Sub(m_Value(Y), m_Value(X)), m_Deferred(X)) states add-sub-cancel in one line. The interpreter aborts on intrinsics, so refuse them first.
Done when: ctest -L ch10 -R Compare and ch10.lab.bench-smoke pass. Then compare your measurements with Lesson 10.5 §5 and Lesson 10.8 §5.
★ Optional: add a declarative rule-table style (Lesson 10.5 §6), and time MCJIT and LLLazyJIT too.