Chapter 20 · Interprocedural & Whole-Program Optimization¶
Part 4 · Optimization · about 3 weeks · Previous: Ch 19 · Next: Ch 21
The problem¶
Chapters 13–19 optimize one function at a time and treat every call as a black box: its arguments escape, its result is unknown, it may read and write anything. The input of this chapter is a whole module — or, with link-time optimization, a whole program — of LLVM IR (and, for virtual calls, the small class-based language of the comparison lab); the output is twofold. First, interprocedural facts: which functions a call may reach (the call graph), in which order to visit them (SCCs, bottom-up and top-down), what each function does (memory effects, norecurse, constant results, taint summaries). Second, transformations across function boundaries that use them: inlining and its cost models, cloning and outlining, interprocedural constant propagation, signature changes (dead arguments, argument promotion), global optimization, devirtualization, tail-recursion elimination — and the build modes that give them the whole program: monolithic LTO, ThinLTO, profile-guided optimization and post-link layout. In LLVM 23 these are the CGSCC inliner, function-attrs, ipsccp, deadargelim, argpromotion, globalopt, wholeprogramdevirt, pgo-icall-prom, tailcallelim and the lto / thinlto pipelines; in pebblec your print<pebble-callgraph>, pebble-inline, pebble-funcattrs and pebble-tre run on them.
What you will be able to do¶
- Build CHA, RTA and XTA call graphs by hand and in code, prove them sound, and measure how much each removes against a dynamic call graph.
- Run Tarjan's algorithm exactly as LLVM's
scc_iteratordoes, explain bottom-up and top-down traversals, and state the invariants of the CGSCC pass manager under call-graph mutation. - Compute inline costs and decisions under a size threshold, a cost/benefit model with bonuses, and a profile, and explain why the problem is NP-hard and what MLGO learns.
- Run IFDS tabulation by hand, prove its \(O(ED^3)\) bound (for call relations with \(O(D)\) edges), and say when summaries beat call strings.
- Infer memory effects and
norecurseover SCCs and prove the fixed point sound; decide dead arguments, argument promotion and GlobalOpt rewrites. - Transform tail recursion into loops with accumulators and prove it correct; decide when a call may be a sibling call.
- Explain monolithic LTO, ThinLTO's summaries and import decisions, instrumentation and sampling PGO, and post-link layout, and read their output (
llvm-lto2 -save-temps,llvm-profdata,-Rpass). - Implement
print<pebble-callgraph>,pebble-inline,pebble-funcattrsandpebble-treand pass./course test 20; find where LLVM 23 and GCC 15 implement each technique.
Prerequisites: Ch 12 (writing passes, the new pass manager, pebble-bbcount counters), Ch 14 (lattices, least fixed points, MOP/MFP, the IFDS preview), Ch 15 (DFS, SCCs, dominators), Ch 16 (SSA and phis), Ch 17 (SCCP), Ch 19 (points-to sets, capture, mod/ref).
Notation¶
Shared notation follows the house notation: §1 (sets, functions, logic), §2 (orders and lattices), §3 (graphs), §7 (dataflow). Orientation: summaries and points-to sets grow up (\(\sqsubseteq\)), fixed points are least fixed points; for call graphs, \(G_1 \sqsubseteq G_2\) means \(G_1\) is at least as precise. In this chapter:
| Symbol | Meaning |
|---|---|
| \(F\), \(\mathit{CS}\), \(\mathrm{body}(c)\) | functions (bodies), call sites, the body containing call site \(c\) (Definition 20.1.1) |
| \(G = (R, T)\), \(\lvert G \rvert\) | a call graph: reachable bodies and targets per call site; its number of edges (Definition 20.1.2) |
| \(\mathrm{Dyn}\) | the edges taken by some execution (Definition 20.1.1) |
| \(\mathit{ext}_{in}\), \(\mathit{ext}_{out}\) | LLVM's external calling node and calls-external node (Algorithm 20.1.3) |
| \(C \preceq D\), \(\mathrm{sub}(D)\), \(\mathrm{lookup}(C, m)\), \(\mathrm{decl}(x)\) | subclass order, subclasses, dispatch, declared type (Definition 20.1.4) |
| \(S[B]\), \(S[@g]\) | XTA class sets of a body and of a global (Definition 20.1.7) |
| \(X_1, \dots, X_k\) | SCCs in bottom-up order (Definition 20.2.2) |
| \(\mathrm{sum}(f)\), \(\mathrm{body}_f\) | a function's summary and its summary equation (Algorithm 20.2.5) |
| \(b(e)\), \(\Delta(e)\), \(B\) | benefit and size growth of inlining edge \(e\), size budget (Definition 20.3.3) |
| \(T\), cost | inline threshold and cost of a call site (Definitions 20.3.6–20.3.8) |
| \(\varphi_c\), \(g_\varphi\) | constant facts of call site \(c\); the clone of \(g\) specialized for \(\varphi\) (Definition 20.4.1) |
| \(b(w)\), \(k\), \(\ell\), \(\kappa_c\), \(\kappa_f\) | outlining benefit of a sequence of length \(\ell\) occurring \(k\) times; call and function overheads (Definition 20.4.6) |
| \(D\), \(0\), \(\langle n, d \rangle\) | IFDS fact domain, the zero fact, a node of the exploded supergraph (Definitions 20.5.2–20.5.3) |
| \(E\), \(N\) | supergraph edges and nodes in complexity statements (Theorem 20.5.6) |
| none \(<\) read \(<\) write | the memory-effect lattice (Definition 20.6.1) |
| \(\mathrm{tid}(T)\), \(\mathrm{Compat}(T)\) | type identifier, compatible vtable address points (Definition 20.7.1) |
| \(\oplus\), \(e\), \(acc\) | accumulator operation, its identity, the accumulator phi (Definition 20.8.3) |
| \(L\), \(\alpha\) | ThinLTO import limit and evolution factor (Algorithm 20.9.5) |
| \(c(e)\), \(N_g\), \(n_k\) | edge count, entry count of \(g\), count of call site \(k\) (Definition 20.10.1, Theorem 20.10.4) |
| \(\Phi\) | weighted distance of a function order (Algorithm 20.10.6) |
Numbered statements are N.k.m (chapter, lesson, counter), as in NOTATION.md §9.
Technique map¶
| Family | Techniques (origin) | Lesson |
|---|---|---|
| Call-graph construction | Direct call graphs (LLVM CallGraph, LazyCallGraph); class hierarchy analysis, CHA (Dean, Grove & Chambers 1995); rapid type analysis, RTA (Bacon & Sweeney 1996); XTA (Tip & Palsberg 2000) and VTA (Sundaresan et al. 2000); points-to-based, on-the-fly call graphs (Andersen-style; Lhoták & Hendren 2003) |
20.1 |
| SCCs and traversal | Tarjan's SCC algorithm (Tarjan 1972) as scc_iterator; bottom-up and top-down traversal (Sharir & Pnueli 1981); the CGSCC pass manager over LazyCallGraph (LLVM) |
20.2 |
| Inlining | Classic heuristics: knapsack formulation (Scheifler 1977), size thresholds, benefit/cost priorities (Davidson & Holler 1992; Ayers, Schooler & Gottlieb 1997; GCC badness); LLVM's InlineCost and inline advisor; ML-guided inlining, MLGO (Trofin et al. 2021) |
20.3 |
| Specialization and outlining | Procedure cloning (Cooper, Hall & Kennedy 1993) and LLVM function specialization; partial inlining (LLVM PartialInliner, GCC ipa-split); outlining by suffix trees (Fraser, Myers & Wendt 1984; LLVM MachineOutliner, IROutliner) and hot/cold splitting (Pettis & Hansen 1990; LLVM HotColdSplitting) |
20.4 |
| Interprocedural analysis | Interprocedural constant propagation with jump functions (Callahan, Cooper, Kennedy & Torczon 1986) and IPSCCP (after Wegman & Zadeck 1991); summary-based vs call-string analysis (Sharir & Pnueli 1981); IFDS (Reps, Horwitz & Sagiv 1995) and IDE (Sagiv, Reps & Horwitz 1996) | 20.5 |
| Attributes and signatures | Attribute inference as an SCC fixed point (side effects after Banning 1979 and Cooper & Kennedy 1988; LLVM FunctionAttrs); dead-argument elimination; argument promotion; global optimization (LLVM deadargelim, argpromotion, globalopt) |
20.6 |
| Devirtualization | Whole-program devirtualization over type metadata (LLVM WholeProgramDevirt); speculative devirtualization and indirect-call promotion (type feedback, Hölzle & Ungar 1994; GCC; LLVM pgo-icall-prom) |
20.7 |
| Tail calls | Tail-call elimination (Steele 1977; sibling calls); tail-recursion elimination with accumulators (Burstall & Darlington 1977; LLVM tailcallelim, GCC tailr) |
20.8 |
| Whole-program compilation | Monolithic LTO (Lattner & Adve 2004); ThinLTO (Johnson, Amini & Li 2017) | 20.9 |
| Profile-guided optimization | Instrumentation PGO (Knuth & Stevenson 1973; Ball & Larus 1994; LLVM IR PGO, CSPGO); sampling PGO, AutoFDO (Chen, Li & Moseley 2016); post-link layout (Pettis & Hansen 1990; BOLT: Panchenko et al. 2019; Propeller: Shen et al. 2023) | 20.10 |
flowchart LR
D[Direct call graph] -->|resolve virtual calls by hierarchy| CHA[CHA 1995]
CHA -->|only instantiated classes| RTA[RTA 1996]
RTA -->|one set per method/global| XTA[XTA 2000]
XTA -->|one set per variable| VTA[VTA 2000]
VTA -->|allocation sites, on the fly| PTA[Points-to call graphs]
PTA --> SCC[Tarjan SCCs, bottom-up / top-down]
SCC --> SUM[Summaries: attributes, modref]
SCC --> INL[Inlining: size, cost model, MLGO]
SCC --> IPA[IPSCCP · IFDS/IDE]
INL --> SPEC[Cloning · partial inlining · outlining]
SUM --> SIG[DAE · argpromotion · GlobalOpt]
CHA --> WPD[Whole-program devirtualization]
WPD --> ICP[Speculative devirt / ICP]
INL --> TRE[TCE · TRE with accumulators]
LTO[Monolithic LTO] -->|summaries, parallel backends| THIN[ThinLTO]
LTO --> INL
PGO[Instrumentation PGO] -->|samples from production| AFDO[AutoFDO]
PGO --> ICP
AFDO --> POST[BOLT / Propeller]
Who uses what¶
| System | Technique | Notes |
|---|---|---|
| LLVM 23 | CallGraph/LazyCallGraph, CGSCC inliner with InlineCost (MLGO advisor when built with a model), function-attrs and rpo-function-attrs, IPSCCP with function specialization, partial inliner, machine/IR outliners, hot/cold splitting, deadargelim, argpromotion, globalopt, wholeprogramdevirt, pgo-icall-prom, tailcallelim, full and thin LTO, IR/CS/sample PGO, basic-block sections |
lessons 20.1–20.10, §7 of each |
| GCC 15 | IPA call graph; ipa-inline (badness priority queue, unit growth); ipa-cp with jump functions and .constprop clones; ipa-split; ipa-pure-const and ipa-modref; ipa-devirt (type inheritance graph, speculative devirtualization); tailr; WHOPR LTO; -fprofile-use, -fauto-profile |
20.3, 20.4, 20.6, 20.7, 20.9 |
| Soot 4.6 | CHA, RTA and VTA call graphs (Spark with rta/vta), on-the-fly Spark |
20.1 |
| WALA, PhASAR | IFDS/IDE solvers (Java; LLVM IR) | 20.5 |
| HotSpot, V8 | CHA without guards plus deoptimization; profile-driven inlining and type feedback | 20.3, 20.7 |
| BOLT, Propeller | post-link block and function layout from sampled profiles | 20.10 |
| Pebble | print<pebble-callgraph>, pebble-inline (size, cost, profile), pebble-funcattrs, pebble-tre; the lab's CHA, RTA and ★ XTA |
exercises, labs A and B |
Comparison¶
The fixed columns follow docs/authoring/DEPTH_CONTRACT.md §3 item 8; each lesson repeats its own rows and defines its variables.
Call-graph construction: direct calls, CHA, RTA, XTA/VTA and points-to (lesson 20.1)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Direct call graph | Exact for direct calls; every indirect call goes to "unknown" | \(O(S)\) · one pass | Sound without any whole-program assumption | Low | LLVM CallGraph/LazyCallGraph, GCC cgraph, every C compiler |
| CHA | All subclasses of the declared type (21 edges on the example) | \(O(S \lvert\mathcal{C}\rvert h)\) · fastest OO resolution | Sound in a closed world | Low (hierarchy + dispatch) | Devirtualization in C++/Java compilers, LLVM WPD's type metadata, JIT class-hierarchy checks |
| RTA | CHA ∩ instantiated classes (12) | ~CHA · a few rounds | Sound in a closed world; removes never-constructed classes | Low | GCC type_possibly_instantiated_p, Soot, whole-program Java tools |
| XTA / VTA | Per-method (9) / per-variable (8) type sets | \(O(\text{sets} \cdot \lvert\mathcal{C}\rvert \cdot S)\) · seconds on large Java programs | Sound, flow-insensitive | Medium (propagation graph) | Soot vta, OPAL, WALA; GCC polymorphic call contexts (flow-sensitive cousin) |
| Points-to based | Allocation sites, on the fly (6 = dynamic here) | \(O(V^3)\) · the most expensive | Sound; the precision of Ch 19's analysis | High | Soot Spark, Doop, SVF; indirect-call resolution in analyzers |
SCCs and traversal orders: Tarjan, bottom-up and top-down, the CGSCC pass manager (lesson 20.2)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Tarjan's SCC algorithm | All SCCs, bottom-up order, one pass | \(O(n + e)\) · one DFS | Deterministic given successor order (matters for reproducible pipelines) | Low (iterative version: medium) | scc_iterator, LazyCallGraph, GCC ipa_reduced_postorder, print<pebble-callgraph> |
| Bottom-up / top-down traversal | Least fixed point of summary systems (Theorem 20.2.10); top-down for caller contexts | one evaluation per non-recursive function | Summaries are reusable (ThinLTO, caching) | Low given SCCs | FunctionAttrs, inliner, modref (bottom-up); IPSCCP args, rpo-function-attrs, ipa-cp (top-down) |
| CGSCC pass manager | Bottom-up order under mutation (Proposition 20.2.11) | near-linear, bounded devirt repeats | Pass-level interleaving: each SCC fully simplified before its callers see it | High (incremental SCCs, analysis invalidation) | LLVM's default<O2> inliner pipeline |
Inlining: heuristics, cost models and learned policies (lesson 20.3)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Classic heuristics (size threshold; GCC badness priority) | Size: blind to call-site facts; priority: global benefit/growth order | \(O(c)\) / \(O(c \log c)\) · cheap | Predictable; GCC's dumps explain every decision | Low / medium (needs summaries) | -O1-style inliners, GCC's IPA inliner, pebble-inline<size> |
LLVM InlineCost + advisor |
Per call site, simulates folding with the actual arguments; bonuses and profile thresholds | \(O(\lvert g \rvert)\) per site, early exit · the dominant IPO cost at -O2 |
Remarks with cost and threshold (-pass-remarks=inline) |
High (every instruction kind, bonuses) | LLVM default<O2>, pebble-inline<cost> / <profile=…> |
| MLGO | Learned from whole-binary outcomes; not tied to one cost formula | Model evaluation \(O(1)\) · features incremental | Hard to explain an individual decision | High (training infrastructure), low to deploy | -Oz builds with a released model (Chrome, Android, Fuchsia toolchains) |
Specialization and outlining: cloning, partial inlining, the outliners and hot/cold splitting (lesson 20.4)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Cloning / function specialization | Per-call-site-class constants without inlining; turns indirect calls direct | estimation \(O(s \lvert g \rvert)\) + re-solves · bounded clones | Clones named .specialized.N / .constprop.N |
Medium (on top of IPSCCP) | LLVM ipsccp<func-spec> (-O3, LTO), GCC ipa-cp |
| Partial inlining | Inlines the hot entry path only | \(O(\lvert g \rvert)\) · cheap | .1.slow / .part.N functions |
Medium (code extraction) | LLVM partial-inliner, GCC fnsplit |
| Outlining / hot/cold splitting | Size: shares repeats (MachineOutliner, IROutliner); locality: moves cold code (HotColdSplitting) | \(O(n)\) suffix tree / linear regions | OUTLINED_FUNCTION_N, .cold.N |
High (liveness and call variants per target) / medium | -Oz on AArch64/RISC-V (mobile), hot/cold with profiles; BOLT does the post-link version |
Interprocedural analysis: IPSCCP, summaries vs contexts, IFDS and IDE (lesson 20.5)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| IPSCCP | Constants and dead branches across calls; merges all call sites of a function (context-insensitive) | near-linear · cheap, runs in default<O2> |
Replaced arguments and returns; poison for unused returns |
Medium on top of SCCP | LLVM ipsccp, GCC ipa-cp |
| Summary-based vs context-sensitive | Summaries: exact for distributive problems, reusable; call strings: exact only without recursion, \(C^k\) blow-up | summaries once per function; call strings exponential in \(k\) | Summaries are inspectable data (modref dumps, ThinLTO index) | Low (summaries of simple lattices) to high (general call strings) | FunctionAttrs, modref, ThinLTO (summaries); points-to (call strings, object sensitivity) |
| IFDS / IDE | MVP exactly for distributive (IFDS) and linear-environment (IDE) problems | \(O(E D^3)\), \(O(E D)\) separable · on-demand | Facts per point plus the summary edges that explain them | Medium (tabulation) to high (IDE micro-functions) | Taint and security analyses (FlowDroid/Heros, PhASAR), typestate; rarely in optimizers |
Attribute inference and signature transformations: FunctionAttrs, dead arguments, argument promotion, GlobalOpt (lesson 20.6)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Attribute inference | Sound summaries (Theorem 20.6.6); SCC-optimistic; bottom-up norecurse is conservative | \(O(n + e)\) · negligible | Attributes in the IR, readable and checkable (-S) |
Low per attribute; high for the full set (captures, willreturn) | LLVM function-attrs (3× in default<O2>), GCC ipa-pure-const, pebble-funcattrs |
| Dead-argument elimination | Removes unused parameters/returns of internal functions | linear · cheap | New signatures; unchanged behavior | Medium (rewriting all calls) | LLVM deadargelim (module simplification, LTO); GCC IPA-SRA |
| Argument promotion | By-pointer → by-value for read-only, dereferenceable arguments of internal functions | linear + alias queries | Parameters named %p.0.val |
Medium (safety checks) | LLVM argpromotion in the CGSCC pipeline |
| Global optimization | Constant, dead, split, shrunk and localized internal globals | linear per round | Fewer/simpler globals | Medium (many rules) | LLVM globalopt (twice in default<O2>, and in LTO) |
Devirtualization: whole-program, speculative and profile-guided (lesson 20.7)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Whole-program devirtualization | Exact single targets and constant results in a closed hierarchy; no guard | linear in the LTO module · cheap | Remarks per devirtualized call; relies on a programmer promise | High (type metadata in the front end, LTO plumbing) | Clang/LLVM with -flto -fwhole-program-vtables (Chromium, Android) |
| Speculative devirtualization / ICP | Any likely target, open world; a guard keeps the fallback | linear · a compare per promoted target | Branch weights show the expected frequencies; wrong guesses only cost time | Medium (profiles or a heuristic single target) | GCC -fdevirtualize-speculatively (-O2), LLVM PGO/AutoFDO (pgo-icall-prom), JITs |
Tail calls: tail-call elimination and tail-recursion elimination with accumulators (lesson 20.8)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Tail-call elimination | Any call in tail position whose frame does not escape; ABI permitting | \(O(n)\) · in the backend | # TAILCALL in assembly; musttail makes failure a compile error |
Medium (per-target ABI checks) | Every C/C++ compiler at -O2; mandatory in Scheme, Swift swifttailcc |
| Tail-recursion elimination with accumulators | Self-recursion in tail position, or followed by one associative-commutative op | \(O(n)\) · cheap | A loop the IR optimizer can transform further | Low–medium (phis, the accumulator, return rewriting) | LLVM tailcallelim (in default<O2>), GCC tailr, pebble-tre |
Whole-program compilation: monolithic LTO and ThinLTO (lesson 20.9)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Monolithic LTO | Every interprocedural pass sees the whole program | serial, \(O(P)\) memory · slow for large programs, no incrementality | One module: -save-temps stages are easy to inspect |
Low for the compiler (reuses the pipeline), high for linkers | Small and medium programs, release builds, when every percent counts |
| ThinLTO | Whole-program decisions on summaries; transformations per module with imports | thin link on the index + parallel, cached backends · near non-LTO build times | Import and export decisions are printable (-print-imports, index dumps) |
High (summaries, promotion, index-based WPD) | Large C/C++ code bases (Chromium, Android, Linux kernel with Clang), default LTO mode in many toolchains |
Profile-guided optimization: instrumentation, sampling and post-link layout (lesson 20.10)
| Technique | Power / precision | Speed (asymptotic · practical) | Output / error quality | Implementation effort | Typical use |
|---|---|---|---|---|---|
| Instrumentation PGO | Exact counts for the training run; value profiles; CSPGO adds post-inline contexts | linear instrumentation · instrumented run markedly slower, separate training build | Stale profiles are detected by CFG checksums and dropped with a warning | Moderate (spanning tree, runtime, profile format) | Release builds of compilers, browsers, databases; with LTO/ThinLTO |
| Sampling PGO (AutoFDO) | Statistical, per source line; loses precision where optimization blurs line info | linear annotation · no training build, negligible production overhead | Staleness tolerated by line offsets; mismatches degrade silently | High (debug-info mapping, inference, converters) | Continuous FDO of data-center fleets, kernels |
| Post-link (BOLT, Propeller) | Layout only (blocks, functions, splitting) but for the whole final binary including libraries | near linear in binary size · BOLT: one rewrite; Propeller: relink | Works on the binary actually shipped; BOLT needs relocations (--emit-relocs) |
Very high (binary rewriting; or compiler + linker co-design) | Large, front-end-bound server binaries, compilers (on top of PGO+LTO) |
Comparison-lab results (reproduce with the commands in the lab specs). Part A (ch20-cg --table --xta labs/ch20-callgraph/inputs/*.oo): call edges CHA 36, RTA 20, XTA 17 on the two hand-written programs (dynamic: 11); on 400 random programs CHA 5 649, RTA 4 869, XTA 4 048, VTA 3 211, dynamic 759 edges (Lesson 20.1 §5). Part B (measure.py --table, seven C benchmarks): executed calls 5 397 680 without inlining, 1 824 657 with the size threshold, 300 008 with the cost model, 8 with the profile; executed IR instructions −11 %, −16 % and −17 %, at +5 %, +5 % and +23 % static size (Lesson 20.3 §3). |
Route through this chapter¶
| Step | What | Techniques | How it is exercised |
|---|---|---|---|
| 1 | Lesson 20.1 | direct, CHA, RTA, XTA/VTA, points-to call graphs | drill cha-rta; quiz; flashcards |
| 2 | Lesson 20.2 | Tarjan, bottom-up/top-down, CGSCC | drill scc-order; quiz |
| 3 | Exercises E1 and lab A | Pebble implements the SCC order; CHA vs RTA (★ XTA) | ./course test 20 |
| 4 | Lesson 20.3, E2, lab B | size, cost model, profile; MLGO | drill inline-decision; tests; measurements |
| 5 | Lesson 20.4 | cloning, partial inlining, outlining | quiz computations |
| 6 | Lesson 20.5 | IPSCCP, summaries, IFDS/IDE | drill ifds-tabulation; quiz |
| 7 | Lesson 20.6, E3 | attributes, DAE, argpromotion, GlobalOpt | drill funcattrs-fixpoint; tests |
| 8 | Lesson 20.7 | WPD, speculative devirtualization / ICP | quiz |
| 9 | Lesson 20.8, E4 | TCE, TRE (★ accumulators) | tests |
| 10 | Lesson 20.9, Lesson 20.10 | LTO, ThinLTO, PGO, AutoFDO, BOLT/Propeller | real-world boxes; quiz |
| 11 | Theory test | all | ./course quiz 20 (≥ 80 % to finish) |
Practice and check¶
./course drill scc-order --difficulty easy # Tarjan as scc_iterator; --solution shows every step
./course drill cha-rta --difficulty medium # CHA, RTA (hard: XTA) on a random program
./course drill inline-decision --difficulty hard # cost, threshold, hot/cold sites
./course drill ifds-tabulation --difficulty medium # path edges, summary edges, facts
./course drill funcattrs-fixpoint --difficulty medium # memory effects and norecurse over SCCs
./course flash 20 # daily, a few minutes
./course quiz 20 # after the lessons
./course test 20 # after the exercises and labs
./course status # done = quiz ≥ 80 % and tests pass
References¶
The chapter's annotated bibliography — papers, textbook sections, pinned source files and docs — is in references.md. Start with: [GC01] (one framework for every call-graph construction of Lesson 20.1), [RHS95] (IFDS, the core of Lesson 20.5), [LLVM-InlineCost] (the production cost model behind Lesson 20.3), [JAL17] (ThinLTO's design and numbers).