Open-Source Wikis

/

Swift

/

Systems

/

IRGen

apple/swift

IRGen

Active contributors: rjmccall, atrick, slavapestov

Purpose

lib/IRGen/ lowers canonical SIL to LLVM IR. It is the bridge between Swift's high-level type system (with generics, protocols, classes, existentials, metadata) and LLVM's lower-level IR. IRGen makes runtime calls explicit (allocations, casting, metadata lookup), expresses Swift's calling conventions in LLVM CC syntax, and emits the various symbols (type metadata records, witness tables, debug info, reflection data) that the Swift runtime consumes.

Directory layout

lib/IRGen/                            (172 files)
├── IRGen.cpp                         # top-level entry: emit a SILModule
├── IRGenModule.cpp / IRGenModule.h   # per-module state: LLVM module, runtime function decls
├── IRGenSIL.cpp                      # 8,796 lines — lower SIL function bodies
├── IRGenFunction.cpp
├── IRGenDebugInfo.cpp                # DWARF / CodeView for Swift
├── IRGenMangler.cpp                  # name mangling for emitted symbols
├── ClassMetadataVisitor.h
├── EnumPayload.cpp
├── GenCall.cpp                       # calling-convention lowering
├── GenClass.cpp                      # class layout + metadata
├── GenStruct.cpp
├── GenEnum.cpp                       # enum layout (singletons, no-payload, multi-payload)
├── GenExistential.cpp                # `any P` / boxed existentials
├── GenProtocol.cpp                   # witness tables
├── GenericRequirement.cpp
├── GenMeta.cpp                       # type metadata records
├── GenReflection.cpp                 # field reflection metadata
├── GenKeyPath.cpp
├── GenConcurrency.cpp                # async function lowering
├── HeapTypeInfo.h
└── ... (150+ files)

Key abstractions

Type File Description
swift::irgen::IRGenerator lib/IRGen/IRGenerator.cpp Top-level coordinator across multiple IRGenModules.
swift::irgen::IRGenModule lib/IRGen/IRGenModule.h Per-LLVM-module state: holds the llvm::Module, declares of every Swift runtime function, type-info cache.
swift::irgen::IRGenSILFunction lib/IRGen/IRGenSIL.cpp Per-function lowering: walks SIL instructions and emits LLVM.
swift::irgen::TypeInfo lib/IRGen/TypeInfo.h The "shape" of a type at the IR level: size, alignment, copy/destroy operations.
swift::irgen::FixedTypeInfo A TypeInfo whose layout is statically known.
swift::irgen::LoadableTypeInfo Fixed + small enough to live in registers.
swift::Explosion lib/IRGen/Explosion.h A bag of LLVM values representing one Swift value.

How it works

graph TD
    Canonical[Canonical SIL] --> IRGenerator
    IRGenerator -->|"per Decl"| EmitDecl[emit type metadata, witness tables, etc.]
    IRGenerator -->|"per SILFunction"| IRGenSIL[IRGenSILFunction]
    IRGenSIL -->|visit| Inst[SIL instruction]
    Inst -->|"per kind"| LLVMIR[LLVM IR snippet]
    EmitDecl --> Symbols[LLVM globals: $sNNType...]
    LLVMIR --> Module["llvm::Module"]
    Symbols --> Module
    Module --> LLVMBackend[LLVM backend → .o]

For each SILFunction:

  1. Build an LLVM Function with the right calling convention. swiftcc is the default; other CCs (@convention(c), @async, @objc) get their LLVM equivalents.
  2. Lower function arguments. SIL parameters with @guaranteed or @owned ownership map to plain LLVM values; address-only parameters get an LLVM pointer.
  3. Walk SIL basic blocks and instructions. Each SILInstruction has a method in IRGenSIL.cpp::IRGenSILFunction::visit*.
  4. Insert calls to runtime functions where required (swift_allocObject, swift_retain, swift_dynamicCastClass, swift_getGenericMetadata, ...). The list lives in include/swift/Runtime/RuntimeFunctions.def.

For each declaration that needs runtime presence (a class, a struct, a protocol conformance, a global), IRGen emits records that the runtime can read at runtime:

  • Type metadata (GenMeta.cpp) -- size, stride, alignment, the value witness table, generic args.
  • Witness tables (GenProtocol.cpp) -- function pointers for each protocol requirement.
  • Reflection records (GenReflection.cpp) -- field names and types for Mirror and swift-reflection-dump.
  • TBD-emitted symbols -- for ABI-stable libraries, IRGen records every public symbol; the linker uses this to verify ABI.

Type layout

Layout for non-generic, non-resilient types is computed at compile time by lib/IRGen/Gen{Struct,Class,Enum}.cpp. Layout for resilient or generic types is deferred to runtime via the value witness table (stdlib/public/runtime/MetadataLookup.cpp and friends). See docs/ABI/TypeLayout.rst.

Generic specialization vs polymorphic

Generic SIL code is either:

  • Specialized by the SIL optimizer (the GenericSpecializer pass), in which case IRGen sees concrete types and emits monomorphic code.
  • Polymorphic (kept generic), in which case IRGen passes metadata and witness_table arguments alongside the value arguments. The function uses the value-witness table to copy / destroy / move values whose layout is unknown at compile time.

docs/ABI/CallingConvention.rst is the spec.

Async functions

async functions get a complex lowering. Each suspension point becomes an LLVM coroutine (llvm.coro.* intrinsics). The Swift Concurrency runtime (stdlib/public/Concurrency/) provides task allocation, executor switching (swift_task_switch), and continuation resumption (swift_continuation_*). See lib/IRGen/GenConcurrency.cpp.

Integration points

  • Reads canonical SIL from lib/SIL/ and lib/SILOptimizer/.
  • Emits llvm::Module -- consumed by LLVM's optimizer (if -O) and backend.
  • Calls into the Swift runtime (stdlib/public/runtime/) at runtime via emitted function declarations.
  • Coordinates with debug info (lib/IRGen/IRGenDebugInfo.cpp), reflection (lib/IRGen/GenReflection.cpp), and TBD generation (lib/AST/TBDGenRequests.cpp + lib/IRGen/).

Entry points for modification

  • Lowering a new SIL instruction: add void visitFooInst(FooInst *I) to IRGenSILFunction.
  • Changing a calling convention: edit lib/IRGen/GenCall.cpp and the matching runtime entry points.
  • Adding a new type-info subclass: see lib/IRGen/HeapTypeInfo.h and the existing examples for non-trivial types.
  • Investigating an IRGen bug: swift -frontend -emit-ir -O file.swift to dump LLVM IR.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

IRGen – Swift wiki | Factory