Chapter 10 · The LLVM C++ API¶
Part 2 · Intermediate Representations & LLVM · about 2 weeks · Previous: Ch 9 · Next: Ch 11
The problem¶
Chapter 9 defined LLVM IR as a language. This chapter treats it as a C++ data structure that your code creates, inspects, rewrites and runs. The input is a program written against LLVM 23's headers and libraries; the output is IR built in memory, facts read from it, rewrites that keep it valid and meaning-preserving, and native code executed from it. Seven questions decide whether such a program is correct and fast:
- Who owns each object, and what does
eraseFromParentfree? - How are the def-use edges kept, and what does replace-all-uses-with (RAUW) do to them?
- Where does
IRBuilderput a new instruction, and when does it create none at all? - How do you test an object's kind cheaply?
- How do you recognize a shape of IR?
- Which containers are fast, and what invalidates your references into them?
- How are errors reported without exceptions, and how is IR executed and LLVM linked?
Every later chapter depends on these answers. The Pebble code generator (Ch 11) is IRBuilder calls, and every pass from Ch 12 on walks and rewrites def-use chains while iterating over instruction lists.
What you will be able to do¶
- Trace the use lists of a function through RAUW,
setOperandanderaseFromParent, predicting the exact orderV->uses()visits, and prove that RAUW preserves SSA dominance when the replacement dominates the replaced value. - Say for any loop over an ilist, a use list, a
SmallVectoror aDenseMapwhether it is safe while mutating, and fix it withmake_early_inc_rangeor a collect-then-mutate pass. - Build functions with
IRBuilderfrom a specification alone (loops with phis, memory,switch), choosing insertion points and folders deliberately (Lab 10.1). - Evaluate
isa/cast/dyn_cast/_if_presenton LLVM's hierarchy, deriveclassofranges from a preorder numbering, and explain whydynamic_caston aValuedoes not compile. - Write the same peephole analysis with raw casts,
InstVisitorandPatternMatch, and explain where PatternMatch is incomplete (Lab 10.3). - Place keys in LLVM 23's
DenseMap(linear probing, Algorithm R) and in the pre-23 tombstone design, and state what each operation invalidates. - Classify
Error/Expectedcode as checked or unchecked, and choose betweenllvm::Expected, exceptions andstd::expected. - Run IR through the interpreter,
LLJITandLLLazyJIT, predict what each compiles and when, and link against LLVM from CMake with the right flags.
Prerequisites: Ch 9 (the IR itself: types, SSA, phis, poison), Ch 0 (interpreters vs JITs), and C++ at the level of templates, RAII and move semantics. Dominance (Ch 15) is used in one proof and is defined there.
How the real-world boxes compile. Each box's programs are in examples/ and compile with
clang++-23 $(llvm-config --cxxflags) -std=c++23 prog.cpp $(llvm-config --ldflags --libs) \
-Wl,-rpath,$(llvm-config --libdir) -o prog
-std=c++23 must come after --cxxflags, which contains -std=c++17 (Lesson 10.8). The outputs were captured on Linux x86-64 with LLVM 23.1.2 from conda-forge. To run the same commands on your machine:
-
macOS with Homebrew (the course's main platform). Put Homebrew's LLVM first on
PATH. It installs unversioned drivers, so typeclang++andclangwhere a box saysclang++-23andclang-23:export PATH="$(brew --prefix llvm)/bin:$PATH" # clang++, llvm-config, lli, opt cd chapters/10-llvm-cpp-api/examples clang++ $(llvm-config --cxxflags) -std=c++23 uniq.cpp $(llvm-config --ldflags --libs) \ -Wl,-rpath,$(llvm-config --libdir) -o uniq && ./uniq # the ASan boxes (Lessons 10.1 and 10.6): the same line plus the box's sanitizer flags clang++ $(llvm-config --cxxflags) -std=c++23 -g -O0 -fsanitize=address erase.cpp \ $(llvm-config --ldflags --libs) -Wl,-rpath,$(llvm-config --libdir) -o erase && ./erase dce.llHomebrew's
llvmships compiler-rt, so-fsanitize=addressneeds nothing else. Addresses, paths and the frames insidelibLLVMdiffer on macOS. Compare the error kind (heap-use-after-free,stack-use-after-scope), the access size and the frame inmain. -
Linux with apt.llvm.org packages (
clang-23,llvm-23-dev,libclang-rt-23-dev).clang++-23exists as written. Put/usr/lib/llvm-23/binfirst onPATHso thatllvm-config,lliandoptare version 23. -
The course container (conda-forge LLVM in
/opt/llvm-23, where these outputs were captured). Add--gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/14to everyclang++-23line (libstdc++ 14). This clang has no sanitizer runtimes. Either install conda-forge'scompiler-rt23_linux-6423.1.2 package into the LLVM prefix, which puts them under$(clang++-23 -print-resource-dir)/lib/linux, or build a resource directory elsewhere and point clang at it:RD=$HOME/clang-rd-23; mkdir -p $RD cp -r "$(clang++-23 -print-resource-dir)/include" $RD/ # clang's own headers # copy lib/clang/23/lib from the unpacked compiler-rt23_linux-64 package to $RD/lib, then add # --gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/14 -resource-dir=$RD # to the ASan boxes' clang++-23 lines
Notation¶
Shared notation follows the house notation: §1 (sets, functions, logic), §3 (graphs), §4 (dominance, used in Theorem 10.2.13) and §8 (complexity). In this chapter:
| Symbol | Meaning |
|---|---|
| \(\mathrm{own}(o)\), \(\mathrm{sub}(p)\) | owner of an object; the subtree an owner deletes (Definition 10.1.1) |
| \(\kappa(v)\), \(T_k\) | structural key of a uniqued object; the uniquing table of kind \(k\) (Definition 10.1.3) |
| \(s\), \(\mathrm{next}(x)\), \(\mathrm{prev}(x)\) | list sentinel and links (Definition 10.1.6) |
| \(\mathrm{val}(u)\), \(\mathrm{user}(u)\), \(\mathrm{opno}(u)\) | value, user and operand number of a use \(u\) (Definition 10.2.1) |
| \(\mathrm{uses}(v)\), \(\mathrm{users}(v)\), \(\mathrm{ops}(U)\) | use list of a value (head first), its users, the operand list of a user |
user[k] |
the use in operand slot \(k\) of user (drills, worked examples) |
| \((B, p, \eta)\) | insertion point: block, position, head bit (Definition 10.3.1) |
| \(\phi\), \(\mathrm{dom}(\phi)\) | a folder and the inputs it folds (Definition 10.3.2) |
| \(\sigma\) | builder state (Definition 10.3.6) |
| \(C \sqsubseteq D\), \(\mathrm{dyn}(o)\) | subclass relation; dynamic class of an object (Definition 10.4.1) |
| \(S_D\), \([\mathit{first}_D, \mathit{last}_D]\) | kind numbers classof of \(D\) accepts; their interval (Definition 10.4.2, Theorem 10.4.10) |
| \(\mathsf{Value}(x)\), \(\mathsf{Deferred}(x)\), \(\mathsf{Bin}_o\), \(\mathsf{cBin}_o\) | pattern constructors (Definition 10.5.1) |
| \(\rho\), \(\ell \xrightarrow{\theta} r\) | variable bindings; a rewrite rule with side condition (Definitions 10.5.2, 10.5.5) |
| \(s, c, N\) | size, capacity, inline capacity of a SmallVector (Definition 10.6.1) |
| \(B\), \(n\), \(\alpha = n/B\), \(\mathrm{home}(k)\) | buckets, entries, load factor, home bucket of a hash table (Definition 10.6.3) |
| \(\mathrm{u}(a)\), \(\mathrm{s}(a)\), \(w\) | unsigned and signed reading of a \(w\)-bit pattern (Definition 10.6.12) |
| checked | the must-check bit of Error/Expected (Definition 10.7.2) |
| \(D\), link order | a JITDylib and its search order (Definition 10.8.4) |
| \(\overline{C}\) | closure of a set of LLVM components (Definition 10.8.7) |
| \(I\), \(K\), \(t_i\), \(t_c\) | executed instructions, JIT compile cost, per-instruction times (Proposition 10.8.12) |
Numbered statements are N.k.m (chapter, lesson, counter), as in NOTATION.md §9.
Technique map¶
| Family | Techniques (origin) | Lesson |
|---|---|---|
| Ownership and IR containers | Context uniquing / hash-consing (Ershov 1958; LLVM, Lattner & Adve 2004), the ownership tree (Lattner 2002), intrusive doubly linked lists with erase vs remove and early-increment iteration (Knuth 1968/1997; LLVM ilist), index-based entity arenas (Cranelift, rustc MIR) |
10.1 |
| Values, users, uses | Use lists and def-use chains (LLVM; SSA per Cytron et al. 1991), operand layout: co-allocated vs hung-off (LLVM User), replace-all-uses-with, value handles (WeakVH, WeakTrackingVH, AssertingVH, CallbackVH, …), metadata as value (MetadataAsValue, ValueAsMetadata) |
10.2 |
| Building IR | Direct construction with InsertPosition, insertion points and the debug-record head bit (LLVM 19+), folders (ConstantFolder, NoFolder, InstSimplifyFolder, TargetFolder), inserters (default, callback, Clang's CGBuilderInserter), builder state (fast-math, debug locations, constrained FP, guards) |
10.3 |
| Casting and dispatch | LLVM-style RTTI (classof, isa/cast/dyn_cast/dyn_cast_if_present, CastInfo), C++ RTTI (dynamic_cast, Itanium ABI; Stroustrup 1994), closed sum types (std::variant/std::visit, P0088 2016), static visitors (InstVisitor; the Visitor pattern, Gamma et al. 1994) |
10.4 |
| Pattern matching | Hand-written matching, PatternMatch combinators (m_Add, m_Value, m_Specific, m_Deferred, m_ConstantInt, m_c_*, m_OneUse), declarative rule DSLs (GCC match.pd 2014, GlobalISel TableGen combiner rules, Cranelift ISLE 2021) |
10.5 |
| ADTs | SmallVector, DenseMap (LLVM 23: linear probing + Knuth's Algorithm R; ≤ 22: quadratic probing + tombstones), SetVector, StringRef/ArrayRef/Twine, StringMap, BitVector/SparseBitVector, PointerIntPair/PointerUnion, APInt/APFloat (IEEE 754) |
10.6 |
| Error handling | Error/Expected with must-check semantics (LLVM 2016), C++ exceptions with zero-cost tables (Itanium ABI), std::expected (P0323, C++23) |
10.7 |
| Running IR and consuming LLVM | The IR interpreter (ExecutionEngine, lli -force-interpreter), MCJIT (2013), ORC LLJIT (Hames 2016/2018), ORC LLLazyJIT, llvm-config and LLVMConfig.cmake (dylib vs components, RTTI/EH flags) |
10.8 |
flowchart LR
CTX[Context uniquing] --> OWN[Ownership tree]
OWN --> IL[Intrusive lists<br/>erase vs remove]
ARENA[Index arenas<br/>Cranelift] -.alternative.-> OWN
OWN --> UL[Use lists<br/>Value/User/Use]
UL --> RAUW[RAUW]
UL --> VH[Value handles]
UL --> MAV[Metadata as value]
IL --> IRB[IRBuilder<br/>insertion points]
IRB --> FOLD[Folders]
IRB --> INS[Inserters]
RTTI[LLVM-style RTTI] --> VIS[InstVisitor]
RTTI --> PM[PatternMatch]
PM -->|scale up| DSL[Rule DSLs<br/>match.pd, GlobalISel, ISLE]
CXX[C++ RTTI] -.slower alternative.-> RTTI
VAR[std::variant] -.closed alternative.-> RTTI
ADT[ADTs: SmallVector, DenseMap, views] --> UL
ERR[Error/Expected] --> JIT[ORC LLJIT / LLLazyJIT]
INT[Interpreter] -.slower, no codegen.-> JIT
MCJIT[MCJIT] -->|superseded by| JIT
Who uses what¶
| System | Technique | Notes |
|---|---|---|
| LLVM 23 | all of the above; DenseMap switched to linear probing + Algorithm R in 23; BranchInst split into UncondBrInst/CondBrInst |
lessons 10.1–10.8 |
| Clang 23 | IRBuilder<TargetFolder, CGBuilderInserter>; LLVM-style RTTI on its AST (Stmt::getStmtClass); StringMap<IdentifierInfo *> |
10.3, 10.4, 10.6 |
| MLIR (llvm-project 23) | intrusive op lists, use lists (UseDefLists.h), CastInfo for value-type handles, TypeSwitch |
10.2, 10.4 |
| Cranelift (Wasmtime 37) | entity arenas + Layout instead of an ownership tree; value aliases instead of use lists; ISLE rules |
10.1, 10.2, 10.5 |
| GCC 15 | match.pd + genmatch; immediate-use lists for SSA names; auto_vec, sparse bitmap; wide_int |
10.2, 10.5, 10.6 |
| rustc 1.90 | IndexVec arenas for MIR; SmallVec; FxIndexSet (insertion-ordered) |
10.1, 10.6 |
| clang-repl, Julia, PostgreSQL JIT | ORC LLJIT / lazy compilation |
10.8 |
Comparison¶
The fixed columns follow docs/authoring/DEPTH_CONTRACT.md §3 item 8; each lesson repeats its rows.
Ownership and IR containers (lesson 10.1)
| Technique | Power / precision | Speed | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Context uniquing | equality of types/constants is pointer equality (Theorem 10.1.11) | \(O(k)\) expected per get; equality \(O(1)\) |
mixing contexts is a hard error (assert/verifier) | a hash table per kind | LLVM types, constants, uniqued metadata |
| Ownership tree | exact deletion, no leaks (Theorem 10.1.12) | \(O(L)\) teardown | use-after-erase is silent UB without ASan | parent pointers + destructors + dropAllReferences |
LLVM, MLIR, GCC's IR |
| Intrusive lists | \(O(1)\) insert/erase anywhere, stable iterators to other nodes (Lemma 10.1.13) | \(O(1)\) edits; \(O(n)\) size() |
erase-while-iterating is UB unless early-inc (Theorem 10.1.14) | small; the traits are the subtle part | instruction, block, function lists |
| Index-based arenas | no dangling memory (Proposition 10.1.15); stale refs undetected | \(O(1)\) access, 4-byte refs, cache-friendly | stale reference = silent wrong data | arena + layout + secondary maps | Cranelift, rustc MIR, many Rust compilers |
Values, users, uses (lesson 10.2)
| Technique | Power / precision | Speed | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Use lists | exact def-use chains, always current (Theorem 10.2.11) | \(O(1)\) per operand change; \(O(m)\) to walk | order is unspecified: never depend on it | Use objects + two-pointer links |
every LLVM/MLIR/GCC SSA pass |
| Operand layout | co-allocated: fixed \(k\); hung-off: growable | one allocation vs two; \(O(1)\) access either way | stale Use * after hung-off growth |
per-class operand traits | fixed instructions vs phi/switch |
| RAUW | rewrites all uses at once; dominance-safe under Theorem 10.2.13 | \(\Theta(m)\) | verifier catches dominance/type mistakes | one call | folding, CSE, simplification, SSA construction |
| Value handles | caches survive deletion/RAUW (Proposition 10.2.15) | \(O(1)\) register, \(O(h)\) notify | AssertingVH checks only in assertion builds |
pick the right kind | analysis caches, ValueMap |
| Metadata as value | metadata as operands; values inside metadata that follow RAUW | \(O(1)\) expected | — | two wrapper classes | constrained FP, debug info, type tests |
Building IR (lesson 10.3)
| Technique | Power / precision | Speed | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Direct construction | full control, no folding | \(O(k)\) per instruction | no help: you set flags, names, locations yourself | verbose | passes rewriting single instructions (Lab 10.2) |
| Insertion points | exact placement incl. debug-record side (Definition 10.3.1) | \(O(1)\) | wrong point = verifier error, or silently wrong debug info | remember to move it | every emitter |
| Folders | none / constants / InstSimplify identities (Proposition 10.3.8) | \(O(1)\) / \(O(s)\) / bounded recursion | less IR to clean up; NoFolder gives exact IR for tests |
choose a template argument | ConstantFolder default; InstSimplifyFolder in passes; NoFolder in tests |
| Inserters | a hook per created instruction (Theorem 10.3.9) | \(O(1)\) + callback | — | subclass or lambda | Clang bookkeeping, worklists, instrumentation |
| Builder state | flags, locations, strict FP applied uniformly | \(O(1)\) | forgotten state is silent (missing !dbg, wrong fast-math) |
setters + guards | front ends, FP-sensitive passes |
Casting and dispatch (lesson 10.4)
| Technique | Power / precision | Speed | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| LLVM-style RTTI | single-inheritance hierarchies you control; exact (Theorem 10.4.10) | \(O(1)\), ~1 compare; fastest measured | wrong cast asserts only in debug builds |
a kind enum + a classof per class |
LLVM, Clang, MLIR, Pebble AST |
| C++ RTTI | any hierarchy incl. multiple/virtual inheritance, cross-casts | \(O(1)\)–\(O(b)\); 6.7× slower measured | failed cast → null; no per-class code to get wrong | none (compiler-generated) | general C++ code; not LLVM (-fno-rtti) |
std::variant + visit |
closed sets of value types; exhaustive at compile time (Theorem 10.4.13) | \(O(1)\) switch | a missing case is a compile error | small; clumsy for deep hierarchies | small ASTs, tokens, results |
| InstVisitor | per-opcode dispatch with class-level fallbacks (Theorem 10.4.14) | \(O(1)\) switch, delegation inlined | an unhandled case silently reaches the fallback | a class with overrides | interpreters, analyses over all instructions, Lab 10.3 |
Pattern matching (lesson 10.5)
| Technique | Power / precision | Speed | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Hand-written | anything, including searches the others cannot express | fastest when structured as a switch (2.3 ms in Lab 10.3) | commuted cases are easy to forget | high; verbose | expression-tree passes (Reassociate), one-off checks |
| PatternMatch | sound (Theorem 10.5.6); complete when no m_Deferred depends on an inner m_c_ choice (Theorem 10.5.7) |
\(O(\lvert P \rvert)\) per pattern, but patterns run one after another (11.5 ms in Lab 10.3) | compile errors are template-heavy; patterns read like the math | low per rule | InstCombine, InstSimplify, most modern LLVM peepholes |
| Rule DSL | declarative; alternatives explicit; verifiable as data | decision tree shared by all rules | the generator checks well-formedness (and, in ISLE, overlaps) | a generator to build and maintain | GlobalISel combiners, GCC match.pd, Cranelift ISLE |
ADTs (lesson 10.6)
| Technique | Power / precision | Speed | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| SmallVector | a vector; inline up to \(N\) | amortized \(O(1)\), no allocation while \(\le N\) | growth invalidates everything | drop-in for std::vector |
operand lists, worklists, temporary buffers |
| DenseMap | hash map for small, trivially copyable keys | expected \(O(1)\); \(< 2.5\) probes on success at \(\alpha < 3/4\) | LLVM 23: erase moves entries; iteration order is unspecified | provide DenseMapInfo for new key types |
pointer-keyed side tables everywhere |
| SetVector | set with insertion-order iteration | \(O(1)\) expected insert/find, \(O(n)\) remove | deterministic output (Theorem 10.6.17) | none | worklists, ordered uniquing |
| StringRef/ArrayRef/Twine | free string/array parameters; lazy concatenation | \(O(1)\) to pass | dangling views are silent without ASan | discipline, not code | API parameters, names |
| StringMap | string-keyed map with stable keys | expected \(O(\lvert k \rvert)\) | keys stable (Proposition 10.6.19) | none | symbol tables, name interning |
| Bit sets | exact sets over integer universes | dense: \(O(U/64)\) ops; sparse: \(O(\#\text{elements})\) | — | none | dataflow (dense), points-to (sparse) |
| Pointer packing | a pointer plus \(\le a\) bits in one word | \(O(1)\) | wrong alignment assumptions assert | a traits specialization for new types | tagged pointers, QualType, PointerUnion operands |
| APInt/APFloat | exact integer and IEEE semantics at any width | \(O(w/64)\)–\(O((w/64)^2)\) | host-independent results | none | constant folding, known bits, ranges |
Error handling (lesson 10.7)
| Technique | Power / precision | Speed | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
Error/Expected |
typed, composable payloads; handler dispatch by type | one test per call; cheap failures | unhandled errors abort in checking builds (Theorem 10.7.8) | verbose (takeError, handlers) |
LLVM libraries, tools, ORC, object/bitcode readers |
| C++ exceptions | non-local, cannot be ignored, automatic cleanup | free success path, very expensive throws | uncaught → std::terminate with a message |
least code at call sites | general C++ outside LLVM |
std::expected |
value-or-error, monadic composition | one test per call | ignoring an error is not detected (only [[nodiscard]]) |
standard, concise | Pebble's APIs, modern C++ libraries |
Running IR and consuming LLVM (lesson 10.8)
| Technique | Power / precision | Speed | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Interpreter | IR semantics; few intrinsics, limited external calls | instant start; ~30–60× slower (measured) | unsupported features abort (report_fatal_error) |
EngineBuilder + runFunction |
quick checks of tiny functions, short runs below the crossover |
| MCJIT | full codegen; whole modules | codegen of whole modules at the first lookup | ExecutionEngine string errors |
EngineBuilder |
legacy code; superseded |
| ORC LLJIT | full codegen; JITDylibs, link order, concurrency, remote execution | per-module codegen at first lookup | Error/Expected everywhere |
LLJITBuilder, ThreadSafeModule, lookup |
test harnesses (Lab 10.1), REPLs, embedding |
| ORC LLLazyJIT | as LLJIT, compiling only executed functions (Theorem 10.8.10) | stubs up front; codegen on first call | as LLJIT | LLLazyJITBuilder, addLazyIRModule |
large modules where little code runs |
| CMake integration | shared or static linking with the right flags | shared: fast links | configure-time errors are clear; flag mismatches are link errors | find_package + four lines |
every out-of-tree LLVM client |
Comparison-lab results (reproduce with build/<preset>/bin/ch10-apibench after ./course test 10 --solution):
- findPatterns over the corpus, 2 000 rounds: raw casts 2.3 ms,
InstVisitor2.9 ms,PatternMatch11.5 ms. fib(1000000): interpreter 412.8 ms, LLJIT 13.3 ms.fibrec(24): interpreter 109.8 ms, LLJIT 12.1 ms.collatz(837799): interpreter 0.7 ms, LLJIT 12.0 ms.
Route through this chapter¶
| Step | What | Techniques | How it is exercised |
|---|---|---|---|
| 1 | Lesson 10.1 | uniquing, ownership tree, ilists, arenas | drill iterator-invalidation; quiz; flashcards |
| 2 | Lesson 10.2 | use lists, operand layout, RAUW, handles, metadata as value | drill use-lists; quiz |
| 3 | Lesson 10.3 | construction, insertion points, folders, inserters, state | drill irbuilder-fold; Lab 10.1 |
| 4 | Lesson 10.4 | LLVM RTTI, C++ RTTI, variant, InstVisitor | drill cast-semantics |
| 5 | Lesson 10.5 | hand-written, PatternMatch, rule DSLs | drill pattern-match; Lab 10.3 (three styles) |
| 6 | Lesson 10.6 | the ADTs | drills densemap-probe, adt-costs, view-lifetime; Lab 10.2 |
| 7 | Lesson 10.7 | Error/Expected, exceptions, std::expected | drill must-check; Labs 10.2–10.3 error paths |
| 8 | Lesson 10.8 | interpreter, MCJIT, LLJIT, LLLazyJIT, CMake | drill jit-compile-set; Lab 10.3 (two engines) |
| 9 | Exercises | Labs 10.1–10.3 | ./course test 10 |
| 10 | Theory test | all | ./course quiz 10 (≥ 80 % to finish) |
This chapter adds no Pebble compiler component. Its labs are standalone (labs/ch10-*), and the APIs they teach are the ones Ch 11 and every pass chapter use.
Practice and check¶
./course drill use-lists --difficulty easy # warm up; --solution shows every step
./course drill densemap-probe --difficulty hard # the LLVM 22 tombstone design
./course flash 10 # daily, a few minutes
./course quiz 10 # after the lessons
./course test 10 # after the labs
./course status
References¶
The chapter's annotated bibliography (papers, textbook sections, pinned source files, docs and talks) is in references.md. Start with [LLVM-PM] (the Programmer's Manual, the chapter's backbone), [LLVM-IRB] and [LLVM-Casting] (the two headers you will read most), [LLVM-DenseMap] with [TAOCP3] (LLVM 23's hash table and its source), and [LLVM-ORC] (the JIT).