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:
- Build an LLVM
Functionwith the right calling convention.swiftccis the default; other CCs (@convention(c),@async,@objc) get their LLVM equivalents. - Lower function arguments. SIL parameters with
@guaranteedor@ownedownership map to plain LLVM values; address-only parameters get an LLVM pointer. - Walk SIL basic blocks and instructions. Each
SILInstructionhas a method inIRGenSIL.cpp::IRGenSILFunction::visit*. - Insert calls to runtime functions where required (
swift_allocObject,swift_retain,swift_dynamicCastClass,swift_getGenericMetadata, ...). The list lives ininclude/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, thevalue witness table, generic args. - Witness tables (
GenProtocol.cpp) -- function pointers for each protocol requirement. - Reflection records (
GenReflection.cpp) -- field names and types forMirrorandswift-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
GenericSpecializerpass), in which case IRGen sees concrete types and emits monomorphic code. - Polymorphic (kept generic), in which case IRGen passes
metadataandwitness_tablearguments 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/andlib/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)toIRGenSILFunction. - Changing a calling convention: edit
lib/IRGen/GenCall.cppand the matching runtime entry points. - Adding a new type-info subclass: see
lib/IRGen/HeapTypeInfo.hand the existing examples for non-trivial types. - Investigating an IRGen bug:
swift -frontend -emit-ir -O file.swiftto dump LLVM IR.
Related pages
- SIL and the SIL optimizer -- IRGen's input.
- Runtime -- IRGen emits calls to these functions.
- Standard library -- low-level types' layouts must match IRGen's expectations.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.