Skip to content

References — Chapter 9 · LLVM IR in Depth

Every source this chapter cites, grouped by kind. Lessons cite entries inline as [KEY]; each entry says why and when to read it. Core reading marks the entries the chapter assumes you will open.

Foundational and research papers

  • [BA08] Hans-J. Boehm and Sarita V. Adve. Foundations of the C++ Concurrency Memory Model. PLDI 2008, pp. 68–78, 2008. doi:10.1145/1375581.1375591
    Why and when: The rationale of the C++11 memory model that LLVM's atomics and orderings adopt (Lesson 9.4, Definition 9.4.11), including why data races are undefined. Read §1–4 after Lesson 9.4's atomics section.
    Cited in: 04-memory-and-addresses

  • [CFRWZ91] Ron Cytron, Jeanne Ferrante, Barry K. Rosen, Mark N. Wegman, and F. Kenneth Zadeck. Efficiently Computing Static Single Assignment Form and the Control Dependence Graph. ACM TOPLAS 13(4), pp. 451–490, 1991. doi:10.1145/115372.115320
    Why and when: The origin of SSA form with phi-functions at joins, the representation LLVM IR makes mandatory for register values. Read the definitions of SSA and of the dominance property after Lesson 9.3 §2; the construction algorithm is Chapter 16's topic.
    Cited in: 01-modules-globals-functions, 03-control-flow-and-ssa

  • [HRS+17] Andreas Haas, Andreas Rossberg, Derek L. Schuff, Ben L. Titzer, Michael Holman, Dan Gohman, Luke Wagner, Alon Zakai, and JF Bastien. Bringing the Web up to Speed with WebAssembly. PLDI 2017, pp. 185–200, 2017. doi:10.1145/3062341.3062363
    Why and when: The design of WebAssembly: a validated stack machine with structured control flow, linear memory and deterministic traps. Read §2–4 with Lesson 9.8's Wasm box; §4 is the validation that Proposition 9.8.13 costs.
    Cited in: 08-ir-comparison

  • [LA04] Chris Lattner and Vikram Adve. LLVM: A Compilation Framework for Lifelong Program Analysis & Transformation. CGO 2004, pp. 75–86, 2004. doi:10.1109/CGO.2004.1281665
    Why and when: Core reading. The paper that introduced LLVM IR: a typed, SSA-based, language-neutral instruction set that survives from compile time through link time. Read §2 (the instruction set, types, GEP, memory model, exceptions, the three representations) after Lessons 9.1–9.4 and note which 2004 choices LLVM 23 kept (SSA, GEP, linkage) and which it dropped (typed pointers).
    Cited in: overview, 01-modules-globals-functions, 02-type-system-and-data-layout, 03-control-flow-and-ssa, 04-memory-and-addresses, 08-ir-comparison

  • [LAB+21] Chris Lattner, Mehdi Amini, Uday Bondhugula, Albert Cohen, Andy Davis, Jacques Pienaar, River Riddle, Tatiana Shpeisman, Nicolas Vasilache, and Oleksandr Zinenko. MLIR: Scaling Compiler Infrastructure for Domain Specific Computation. CGO 2021, pp. 2–14, 2021. doi:10.1109/CGO51591.2021.9370308
    Why and when: MLIR generalizes LLVM IR's design into extensible dialects with regions and block arguments instead of phis. Read §2–3 after Lesson 9.8 to see where the block-argument form of Definition 9.8.2 became the default for new IRs.
    Cited in: 01-modules-globals-functions, 08-ir-comparison

  • [LHJ+18] Juneyoung Lee, Chung-Kil Hur, Ralf Jung, Zhengyang Liu, John Regehr, and Nuno P. Lopes. Reconciling High-Level Optimizations and Low-Level Code in LLVM. Proc. ACM Program. Lang. 2 (OOPSLA), Article 125, 2018. doi:10.1145/3276495
    Why and when: A memory model for LLVM IR with pointer provenance and the "twin allocation" semantics for integer-pointer casts: why inttoptr(ptrtoint p) is not simply p, and why GEP, not integer arithmetic, should compute addresses (Lesson 9.4, casts). Read after Lesson 9.4.
    Cited in: 04-memory-and-addresses

  • [LHK+17] Juneyoung Lee, Yoonseung Kim, Youngju Song, Chung-Kil Hur, Sanjoy Das, David Majnemer, John Regehr, and Nuno P. Lopes. Taming Undefined Behavior in LLVM. PLDI 2017, pp. 633–647, 2017. doi:10.1145/3062341.3062343
    Why and when: Core reading. Shows that LLVM's old combination of undef and poison was inconsistent (optimizations that are each "obviously" right miscompile together), proposes poison-only deferred UB plus the freeze instruction, and measures the cost. The source of Lesson 9.7's Definitions 9.7.2–9.7.6 and Proposition 9.7.14; read §2–4 after the lesson.
    Cited in: overview, 07-poison-undef-and-ub

  • [LLM+21] Nuno P. Lopes, Juneyoung Lee, Chung-Kil Hur, Zhengyang Liu, and John Regehr. Alive2: Bounded Translation Validation for LLVM. PLDI 2021, pp. 65–79, 2021. doi:10.1145/3453483.3454030
    Why and when: Core reading. Refinement (Definition 9.7.8) for whole LLVM functions, with undef, poison, memory and loops (bounded), checked by SMT; the tool behind the alive2.llvm.org links in InstCombine tests. Read §2–3 after Lesson 9.7; Chapter 13 uses it in practice.
    Cited in: overview, 03-control-flow-and-ssa, 07-poison-undef-and-ub

  • [LMNR15] Nuno P. Lopes, David Menendez, Santosh Nagarakatte, and John Regehr. Provably Correct Peephole Optimizations with Alive. PLDI 2015, pp. 22–32, 2015. doi:10.1145/2737924.2737965
    Why and when: The DSL and SMT-based checker for InstCombine rules, including the automatic inference of which nsw/nuw/exact flags a rewrite may keep, the question of the flags drill (Algorithm 9.7.10 does it by enumeration). Read §3 after Lesson 9.7.
    Cited in: 07-poison-undef-and-ub

  • [Mer03] Jason Merrill. GENERIC and GIMPLE: A New Tree Representation for Entire Functions. Proceedings of the GCC Developers' Summit 2003, 2003.
    Why and when: The origin of GIMPLE: GENERIC as the language-independent tree form, GIMPLE as its three-address lowering (derived from McCAT's SIMPLE). Read before Lesson 9.8's GIMPLE box for the design motivation.
    Note: Published in the 2003 GCC Summit proceedings (linked from the GCC wiki); the URL could not be checked from the authoring environment. GCC's own GIMPLE documentation [GCC-GIMPLE] covers the same design and is the version-pinned reference.
    Cited in: 08-ir-comparison

  • [Ram22] Norman Ramsey. Beyond Relooper: Recursive Translation of Unstructured Control Flow to Structured Control Flow (Functional Pearl). Proc. ACM Program. Lang. 6 (ICFP), Article 90, 2022. doi:10.1145/3547621
    Why and when: How to turn a reducible CFG into Wasm's block/loop/br nesting without duplicating code, driven by the dominator tree: the constructive half of Proposition 9.8.11. Read after Lesson 9.8 and Chapter 15.
    Cited in: 08-ir-comparison

  • [ZNMZ12] Jianzhou Zhao, Santosh Nagarakatte, Milo M. K. Martin, and Steve Zdancewic. Formalizing the LLVM Intermediate Representation for Verified Program Transformations. POPL 2012, pp. 427–440, 2012. doi:10.1145/2103656.2103709
    Why and when: Vellvm: LLVM IR's syntax, well-formedness (including the SSA dominance property of Theorem 9.3.5) and semantics in Coq, with machine-checked proofs about SSA-based passes. Read §3–4 after Lesson 9.3 to see Definition 9.3.4 made fully formal.
    Cited in: 03-control-flow-and-ssa, 07-poison-undef-and-ub

Textbooks and monographs

  • [EaC3] Keith D. Cooper and Linda Torczon. Engineering a Compiler, 3rd ed.. Morgan Kaufmann, 2022. Read: Ch. 4 (Intermediate Representations: graphical and linear IRs, SSA, symbol tables and naming).
    Why and when: The textbook view of the design space LLVM IR sits in: three-address code, CFGs, SSA and name spaces. Read before Lesson 9.1 if Chapter 8 was a while ago; Lesson 9.8 is its concrete counterpart.
    Cited in: 01-modules-globals-functions

  • [SSAB] Fabrice Rastello and Florent Bouchez Tichadou. SSA-based Compiler Design. Springer, 2022. Read: Ch. 2 Properties and Flavors (strict SSA and the dominance property). doi:10.1007/978-3-030-80515-9
    Why and when: The SSA properties the verifier enforces: strict SSA is exactly the dominance property of Theorem 9.3.5, and the chapter compares SSA flavors. Read Ch. 2 after Lesson 9.3.
    Cited in: 03-control-flow-and-ssa

Theses and technical reports

  • [Lat02] Chris Lattner. LLVM: An Infrastructure for Multi-Stage Optimization. Master's thesis, Department of Computer Science, University of Illinois at Urbana-Champaign, 2002. link
    Why and when: The longer original description of LLVM, with the argument for a persistent, self-contained program representation that is the module of Lesson 9.1. Optional; skim the representation chapter after Lesson 9.1 §1.
    Cited in: 01-modules-globals-functions

Source code (pinned versions)

  • [GCC-SSA] GCC's SSA verifier — gcc/tree-ssa.cc in gcc-mirror/gcc at releases/gcc-15. Symbols: verify_ssa.
    Why and when: GCC's counterpart of LLVM's dominance check (Proposition 9.8.7); compare with Verifier::verifyDominatesUse after Lesson 9.8.
    Cited in: 08-ir-comparison

  • [LLVM-Attributes] The list of all IR attributes and where they may appear — llvm/include/llvm/IR/Attributes.td in llvm/llvm-project at llvmorg-23.1.2. Symbols: NoUndef, Memory, Captures, Range, ZExt, NoAlias.
    Why and when: The authoritative list behind Definition 9.5.3's table (parameter, return and function attributes, with their intersection rules). Skim after Lesson 9.5.
    Cited in: 05-calls-attributes-intrinsics

  • [LLVM-AutoUpgrade] Rewriting old IR constructs on load (bitcode and text) — llvm/lib/IR/AutoUpgrade.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: UpgradeIntrinsicFunction, UpgradeIntrinsicCall, UpgradeCallsToIntrinsic, UpgradeDebugInfo.
    Why and when: How LLVM keeps its compatibility promise: old intrinsic signatures (the two-operand lifetime.start of Lesson 9.6's box), debug intrinsics, and more. Read after Lesson 9.6.
    Cited in: 05-calls-attributes-intrinsics

  • [LLVM-CallingConv] The numbered calling conventions — llvm/include/llvm/IR/CallingConv.h in llvm/llvm-project at llvmorg-23.1.2. Symbols: CallingConv::C, CallingConv::Fast, CallingConv::Cold, CallingConv::Tail, CallingConv::SwiftTail.
    Why and when: The IDs behind ccc, fastcc, coldcc, tailcc and the target conventions; read with Lesson 9.5's calling-convention box.
    Cited in: 05-calls-attributes-intrinsics

  • [LLVM-DataLayout] Data layout parsing, alignment rules and struct layout — llvm/lib/IR/DataLayout.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: DataLayout::parseLayoutString, DataLayout::getAlignment, StructLayout::StructLayout.
    Why and when: Algorithm 9.2.6 (the integer "next larger width" rule, natural alignment for vectors and unknown floats) and Algorithm 9.4.2 (struct layout). Read after Lesson 9.2 and compare with gep_offset in tools/course/lib/llvmir.py.
    Cited in: 02-type-system-and-data-layout, 04-memory-and-addresses

  • [LLVM-FunctionAttrs] Inference of memory(...) and other attributes over call-graph SCCs — llvm/lib/Transforms/IPO/FunctionAttrs.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: addMemoryAttrs, checkFunctionMemoryAccess.
    Why and when: Algorithm 9.5.5 in production: calls to SCC members are skipped and the SCC gets one effect (Proposition 9.5.9). Read after Lesson 9.5 §4.
    Cited in: 05-calls-attributes-intrinsics

  • [LLVM-InstCombine] GEP canonicalization to the byte-offset form, and freeze folding — llvm/lib/Transforms/InstCombine/InstructionCombining.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: InstCombinerImpl::visitGetElementPtrInst, shouldCanonicalizeGEPToPtrAdd, InstCombinerImpl::visitFreeze.
    Why and when: Algorithm 9.4.9 as LLVM implements it ("Canonicalize constant GEPs to i8 type", "gep %T to gep [sizeof(%T) x i8]"). Read after Lesson 9.4 §6 with the instcombine box open.
    Cited in: 04-memory-and-addresses

  • [LLVM-Intrinsics] Target-independent intrinsic definitions (TableGen) — llvm/include/llvm/IR/Intrinsics.td in llvm/llvm-project at llvmorg-23.1.2. Symbols: int_sadd_with_overflow, int_smul_with_overflow, int_umul_with_overflow.
    Why and when: Signatures, overloading and attributes of every target-independent intrinsic (Definition 9.5.6). Read the overflow intrinsics before lab E6.
    Cited in: 05-calls-attributes-intrinsics

  • [LLVM-LLParser] The textual IR parser (W1, W5, slot numbers, forward references) — llvm/lib/AsmParser/LLParser.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: LLParser::Run, LLParser::checkValueID, LLParser::PerFunctionState::setInstName, LLParser::parseGetElementPtr.
    Why and when: The rules the parser enforces before the verifier runs: one terminator per block, types of uses, increasing slot numbers (Algorithm 9.1.7), undefined values. Read the functions listed after Lessons 9.1 and 9.3.
    Cited in: 01-modules-globals-functions

  • [LLVM-Mem2Reg] mem2reg, the main client of IDFCalculator — llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: isAllocaPromotable, PromoteMem2Reg::run.
    Why and when: isAllocaPromotable is Proposition 9.4.12's condition; PromoteMem2Reg::run builds SSA from the memory form (Chapter 16). Read isAllocaPromotable after Lesson 9.4.
    Cited in: 04-memory-and-addresses

  • [LLVM-TBAA] Type-based alias analysis over TBAA metadata — llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: TypeBasedAAResult::alias, matchAccessTags.
    Why and when: The file's header comment explains the scalar and struct-path formats; matchAccessTags is Algorithm 9.6.3 generalized to struct paths. Read after Lesson 9.6.
    Cited in: 06-metadata-and-representation

  • [LLVM-ValueTracking] Poison and UB reasoning used by all of LLVM's optimizers — llvm/lib/Analysis/ValueTracking.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: canCreatePoison, propagatesPoison, isGuaranteedNotToBePoison, programUndefinedIfPoison, handleGuaranteedNonPoisonOps.
    Why and when: Definition 9.7.3 (canCreatePoison), the rules of Definition 9.7.4 (propagatesPoison) and the operands that turn poison into UB (handleGuaranteedNonPoisonOps). Read after Lesson 9.7.
    Cited in: 07-poison-undef-and-ub

  • [LLVM-Verifier] The IR verifier (rules W2–W7 of Definition 9.3.4) — llvm/lib/IR/Verifier.cpp in llvm/llvm-project at llvmorg-23.1.2. Symbols: Verifier::visitFunction, Verifier::visitBasicBlock, Verifier::visitPHINode, Verifier::visitInstruction, Verifier::verifyDominatesUse.
    Why and when: Every message quoted in Lesson 9.3 and in the lab's F-tasks comes from here. After Lesson 9.3, find each W-rule's check; the file is long but each visit function is short.
    Cited in: 02-type-system-and-data-layout, 03-control-flow-and-ssa

Official documentation and specifications

  • [CL-Docs] Cranelift IR reference (cranelift/docs/ir.md) and project documentation. Wasmtime v37.0.2. link
    Why and when: CLIF: SSA with block parameters, types, heaps and the wrap-or-trap integer semantics behind Proposition 9.8.10. Read with Lesson 9.8's CLIF box open.
    Cited in: 08-ir-comparison

  • [GCC-GIMPLE] GCC Internals: GIMPLE. GCC 15. link
    Why and when: GIMPLE's statement codes, operands, SSA names and PHI nodes, maintained with GCC (gcc/doc/gimple.texi). Read with Lesson 9.8's GIMPLE box.
    Cited in: 08-ir-comparison

  • [LLVM-Atomics] LLVM Atomic Instructions and Concurrency Guide. LLVM 23.1.2. link
    Why and when: What each ordering means for optimizations and code generation, and why non-atomic races yield undef (Proposition 9.4.13). Read after Lesson 9.4's atomics section.
    Cited in: 04-memory-and-addresses

  • [LLVM-Bitcode] LLVM Bitcode File Format. LLVM 23.1.2. link
    Why and when: The bitstream container, VBR encoding (the vbr4 example of Lesson 9.6), abbreviations and relative operand IDs. Read with llvm-bcanalyzer -dump output next to it.
    Cited in: 01-modules-globals-functions, 06-metadata-and-representation

  • [LLVM-DbgRecords] Debug info migration: From intrinsics to records (RemoveDIsDebugInfo). LLVM 23.1.2. link
    Why and when: The move from llvm.dbg.value calls to #dbg_value records, the textual format change and the API (getDbgRecordRange). Read with Lesson 9.6's debug-records section.
    Cited in: 06-metadata-and-representation

  • [LLVM-DevPolicy] LLVM Developer Policy: IR Backwards Compatibility. LLVM 23.1.2. link
    Why and when: The compatibility promise quoted in Lesson 9.6: bitcode back to 3.0 is readable, the text format has no promise, non-debug metadata may be dropped. Read the "IR Backwards Compatibility" section after Lesson 9.6.
    Cited in: 06-metadata-and-representation

  • [LLVM-EH] Exception Handling in LLVM. LLVM 23.1.2. link
    Why and when: invoke, landingpad, resume and personality functions for the Itanium ABI, and the funclet instructions for Windows. Read before lab E8.
    Cited in: 03-control-flow-and-ssa

  • [LLVM-GEP] The Often Misunderstood GEP Instruction (GetElementPtr FAQ). LLVM 23.1.2. link
    Why and when: Core reading. Answers the questions Lesson 9.4 raises (the leading zero index, why GEP never dereferences, out-of-bounds GEPs, what inbounds means). Read it right after Lesson 9.4 §3 and before lab E9.
    Cited in: overview, 04-memory-and-addresses

  • [LLVM-LangRef] LLVM Language Reference Manual. LLVM 23.1.2. link
    Why and when: Core reading. The definition of everything in this chapter; every lesson cites the section it follows (Well-Formedness, Linkage Types, Data Layout, Type System, getelementptr, Poison Values, Undefined Values, Memory Model, Calling Conventions, Parameter/Function Attributes, Metadata, Intrinsic Functions). Keep it open while doing the lab.
    Cited in: overview, 01-modules-globals-functions, 02-type-system-and-data-layout, 03-control-flow-and-ssa, 04-memory-and-addresses, 05-calls-attributes-intrinsics, 06-metadata-and-representation, 07-poison-undef-and-ub, 08-ir-comparison

  • [LLVM-OpaquePtr] Opaque Pointers. LLVM 23.1.2. link
    Why and when: Why typed pointers (i32*) were removed, the migration timeline (LLVM 14–17), and what replaced pointee types (types on loads, stores, GEPs and calls). Read after Lesson 9.2.
    Cited in: 02-type-system-and-data-layout

  • [LLVM-UB] Undefined Behavior (UB) in LLVM. LLVM 23.1.2. link
    Why and when: LLVM's own guide to immediate UB, undef, poison and freeze, with the rationale for deferred UB and many small examples. Read it alongside Lesson 9.7 §1–2.
    Cited in: 07-poison-undef-and-ub

  • [RUST-MIR] Rust Compiler Development Guide: The MIR (Mid-level IR). rustc 1.94 era. link
    Why and when: MIR's locals, places, statements, terminators and how to dump it; read with Lesson 9.8's MIR box and compare the assert terminators with PIR's.
    Cited in: 08-ir-comparison

  • [SWIFT-SIL] Swift Intermediate Language (SIL) specification, docs/SIL/SIL.md. Swift 6.2. link
    Why and when: SIL's values, types, ownership and basic block arguments ("This corresponds to LLVM's phi nodes"), quoted in Lesson 9.8. Read the "Basic Blocks" and "Values and Operands" sections after Lesson 9.8.
    Cited in: 08-ir-comparison

  • [WASM-SPEC] WebAssembly Core Specification. WebAssembly 2.0. link
    Why and when: The formal definition of Wasm's structured control, validation (the appendix "Validation Algorithm" is Proposition 9.8.13's algorithm) and execution. Read the control-instruction and validation sections after Lesson 9.8.
    Cited in: 08-ir-comparison

Blog posts and articles

  • [Pop24] Nikita Popov. This year in LLVM (2023). 2024. link
    Why and when: Extra reading by the LLVM maintainer who drove the opaque-pointer migration and the move toward getelementptr i8 / ptradd: why typed GEPs obstruct canonicalization and what the byte-offset form buys. Read after Lesson 9.4 §6.
    Note: Unverified: the URL could not be opened from the authoring or the review environment (the site is blocked there), so neither the link nor the summary of its content below has been checked against the post; the blog's index is www.npopov.com. The LLVM 19 release notes (nusw/nuw GEP flags) and the InstCombine source [LLVM-InstCombine] are the verified references for the same facts.
    Cited in: 04-memory-and-addresses