apple/swift
SIL and the SIL optimizer
Active contributors: eeckstein, atrick, jckarter, meg-gupta, kavon
Purpose
SIL (Swift Intermediate Language) is Swift's own SSA-form IR. It sits between the typed AST and LLVM IR, preserving Swift-level semantics that LLVM cannot encode: ownership, generics, dynamic dispatch, exclusivity, error throwing. The SIL optimizer runs a pipeline of passes that transform raw SIL into canonical SIL (mandatory phase) and then into highly optimized SIL (performance phase).
This is one of the two largest subsystems in the compiler. New passes are increasingly written in Swift in SwiftCompilerSources/.
Directory layout
lib/SIL/ (88 files)
├── IR/ # SIL IR types (SILFunction, SILInstruction)
│ └── SILInstruction.cpp
├── Parser/ParseSIL.cpp # 9,149 lines — the SIL textual format parser
├── Verifier/ # SIL invariants
└── Utils/
include/swift/SIL/
├── SILInstruction.h # 12,423 lines — every SIL instruction
├── SILValue.h
├── SILFunction.h
├── SILBasicBlock.h
├── SILModule.h
└── ... (180+ headers)
lib/SILOptimizer/ (288 files — largest lib/ subdir)
├── PassManager/
│ ├── PassManager.cpp # the pass runner
│ └── PassPipeline.cpp # pipeline definitions
├── Mandatory/ # mandatory passes (run for any -O level)
│ ├── DefiniteInitialization.cpp
│ ├── DiagnoseUnreachable.cpp
│ ├── MandatoryInlining.cpp
│ └── PredictableMemoryOptimizations.cpp
├── Transforms/ # performance passes
│ ├── SILMem2Reg.cpp
│ ├── ARC/
│ └── SimplifyCFG.cpp
├── LoopTransforms/
├── FunctionSignatureTransforms/
├── IPO/ # interprocedural opts (specializer, devirtualizer)
├── Analysis/ # alias analysis, side-effect analysis
└── Utils/
SwiftCompilerSources/Sources/
├── SIL/ # Swift wrappers around SIL
├── Optimizer/
│ ├── PassManager/
│ ├── FunctionPasses/ # 30+ Swift-implemented function passes
│ ├── ModulePasses/ # 7+ Swift-implemented module passes
│ ├── InstructionSimplification/
│ ├── Analysis/
│ ├── DataStructures/
│ └── Utilities/Key abstractions
| Type | File | Description |
|---|---|---|
swift::SILModule |
include/swift/SIL/SILModule.h |
A unit of SIL: collection of SILFunctions, globals, witness tables. |
swift::SILFunction |
include/swift/SIL/SILFunction.h |
One function: parameters, basic blocks, attributes. |
swift::SILBasicBlock |
include/swift/SIL/SILBasicBlock.h |
A linear sequence of instructions ending in a terminator. |
swift::SILInstruction |
include/swift/SIL/SILInstruction.h |
Base class; ~200 instruction kinds. |
swift::SILValue |
include/swift/SIL/SILValue.h |
An SSA value (operation result or argument). |
swift::SILBuilder |
include/swift/SIL/SILBuilder.h |
IRBuilder-style emitter. |
swift::SILPassManager |
lib/SILOptimizer/PassManager/PassManager.cpp |
The pass runner: schedules and runs passes. |
swift::SILTransform |
include/swift/SILOptimizer/PassManager/Transforms.h |
Base of all C++ passes. Subclasses: SILFunctionTransform, SILModuleTransform. |
swift::SILVerifier |
lib/SIL/Verifier/SILVerifier.cpp |
Invariant checker; runs after every pass with assertions. |
How it works
graph LR
SILGen[SILGen] -->|raw SIL| Mandatory[Mandatory passes]
Mandatory --> Canonical[Canonical SIL]
Canonical --> Perf[Performance passes]
Perf --> Specialized[Specialized + inlined SIL]
Specialized --> IRGen[IRGen]Mandatory passes
Run regardless of optimization level. They make the SIL correct (validate semantics, finalize lowering). Examples:
| Pass | What it does |
|---|---|
DiagnoseInvalidEscapingCaptures |
Catches escaping closures over inout parameters. |
DefiniteInitialization |
Verifies every variable is initialized before read; enforces let. |
MandatoryInlining |
Inlines @_transparent and similar. |
OSLogOptimization |
Constant-folds os_log format strings. |
OnoneSimplification |
Cleanup at -Onone to keep SIL legible. |
LowerOwnership |
Lowers OSSA ownership annotations to ARC semantics where applicable. |
After mandatory passes, the SIL is canonical SIL. This is the point at which IRGen would be valid input.
Performance passes
Enabled by -O, -Osize, -Owholemodule. Hundreds of passes -- function-level (SILFunctionTransform) and module-level (SILModuleTransform). A few representative examples:
| Pass | Implementation |
|---|---|
GenericSpecializer |
lib/SILOptimizer/IPO/GenericSpecializer.cpp (C++) |
Devirtualizer |
lib/SILOptimizer/Transforms/Devirtualizer.cpp |
LetPropertyLowering (Swift) |
SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift |
DeadStoreElimination (Swift) |
.../FunctionPasses/DeadStoreElimination.swift |
LoopInvariantCodeMotion (Swift) |
.../FunctionPasses/LoopInvariantCodeMotion.swift |
ARCSequenceOpts |
lib/SILOptimizer/Transforms/ARC/ |
SimplifyCFG |
lib/SILOptimizer/Transforms/SimplifyCFG.cpp |
SILCombine |
lib/SILOptimizer/SILCombiner/ |
LoopUnroller |
lib/SILOptimizer/LoopTransforms/ |
The pipeline definition lives in lib/SILOptimizer/PassManager/PassPipeline.cpp. Each pass is registered in include/swift/SILOptimizer/PassManager/Passes.def.
Pass implementation language
A pass can be written in C++ or Swift:
- C++ passes are subclasses of
SILFunctionTransformorSILModuleTransforminlib/SILOptimizer/. They use the C++ SIL APIs ininclude/swift/SIL/. - Swift passes live in
SwiftCompilerSources/Sources/Optimizer/FunctionPasses/(orModulePasses/). They use the Swift bridging types inSwiftCompilerSources/Sources/SIL/. A C++ shim registers them with the pass manager viaOptimizerBridging.
New passes are written in Swift when feasible. Read SwiftCompilerSources for the bridging story.
OSSA -- Ownership SIL
All SIL today is OSSA (Ownership SSA). Every SILValue has an ownership kind:
owned-- caller transfers ownership to the operand; consumer must destroy.guaranteed-- borrowed; producer keeps owning, consumer may not destroy.unowned-- weak-like; no retain/release.none-- trivial value (Int, raw pointer, ...).
Operations like copy_value, destroy_value, begin_borrow, end_borrow, move_value make ownership explicit. The verifier enforces well-formedness; many passes only operate over OSSA SIL because the analysis is cleaner. See docs/SIL/ and docs/OwnershipManifesto.md.
The SIL textual format
SIL has a stable textual format that survives round-trips through -emit-sil / -parse-sil. It is the basis of test/SIL* tests. The parser is in lib/SIL/Parser/ParseSIL.cpp (9,149 lines).
sil @add : $@convention(thin) (Int, Int) -> Int {
bb0(%0 : $Int, %1 : $Int):
%2 = struct_extract %0 : $Int, #Int._value
%3 = struct_extract %1 : $Int, #Int._value
%4 = builtin "sadd_with_overflow_Int64"(%2, %3, ...) : ...
%5 = tuple_extract %4 : $..., 0
%6 = struct $Int (%5 : $Builtin.Int64)
return %6 : $Int
}Integration points
- SILGen populates the
SILModule(raw SIL). - The pass manager runs mandatory then performance passes, mutating the module in place.
- IRGen consumes the final canonical SIL.
- Analyses (
lib/SILOptimizer/Analysis/,SwiftCompilerSources/Sources/Optimizer/Analysis/) are cached side data: alias analysis, side-effect analysis, escape analysis, dominance, post-dominance. - The verifier runs in assertion builds after every pass.
Entry points for modification
- Adding a new SIL instruction: extend
include/swift/SIL/SILInstruction.handSILNodes.def. Wire serialization (lib/Serialization/SerializeSIL.cpp), printing (lib/SIL/IR/SILPrinter.cpp), and IRGen handling (lib/IRGen/IRGenSIL.cpp). - Adding a new C++ pass: subclass
SILFunctionTransforminlib/SILOptimizer/Transforms/, register inPasses.def, add to a pipeline inPassPipeline.cpp. - Adding a new Swift pass: write the file in
SwiftCompilerSources/Sources/Optimizer/FunctionPasses/, register via the bridging mechanism, add tests undertest/SILOptimizer/. - Investigating a pass bug: run
swift -frontend -emit-sil -O -Xllvm -sil-print-after=<pass> file.swift. Or-Xllvm -sil-disable-pass=<pass>to bisect.
Documentation
docs/SIL/ is a multi-document specification of SIL. Read docs/SIL/SIL.rst for a thorough reference and docs/OptimizerDesign.md for the optimizer's philosophy.
Related pages
- SILGen -- the producer.
- IRGen -- the consumer.
- SwiftCompilerSources -- the Swift-implemented half of the optimizer.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.
Previous
SILGen
Next
IRGen