apple/swift
SILGen
Active contributors: jckarter, kavon, atrick
Purpose
SILGen lowers the type-checked AST to raw SIL (Swift Intermediate Language). It introduces explicit memory management, calling conventions, and the lowered semantics of language features (initializers, deinitializers, generics, closures, async/await, throws, casts, dynamic dispatch).
The output of SILGen is raw -- it has not yet been validated for definite initialization, ownership, or other invariants enforced by mandatory passes. After mandatory passes run, the SIL is canonical and is the input to IRGen. See SIL and the SIL optimizer for the post-SILGen pipeline.
Directory layout
lib/SILGen/ (71 files)
├── SILGen.cpp # top-level entry: generate SIL for a SourceFile
├── SILGenFunction.cpp # per-function SIL emission state
├── SILGenExpr.cpp # lowering Exprs
├── SILGenStmt.cpp # lowering Stmts
├── SILGenApply.cpp # 8,516 lines — function application
├── SILGenBuilder.cpp # the IRBuilder-style SIL emitter
├── SILGenConvert.cpp # implicit conversions, bridging
├── SILGenDecl.cpp # local var decls, lazy/global init
├── SILGenDestructor.cpp
├── SILGenDistributed.cpp # distributed actor calls
├── SILGenDynamicCast.cpp
├── SILGenEpilog.cpp
├── SILGenForeignError.cpp
├── SILGenGenerics.cpp
├── SILGenLValue.cpp # left-value emission
├── SILGenPattern.cpp
├── SILGenPoly.cpp # reabstraction thunks
├── SILGenProlog.cpp
├── SILGenStmt.cpp
└── SILGenThunk.cppKey abstractions
| Type | File | Description |
|---|---|---|
swift::Lowering::SILGenModule |
lib/SILGen/SILGen.cpp |
Per-module SIL generation state. |
swift::Lowering::SILGenFunction |
lib/SILGen/SILGenFunction.cpp |
Per-function emission. Owns the current SILBuilder, scopes, and the cleanup stack. |
swift::Lowering::ManagedValue |
include/swift/SIL/ManagedValue.h |
A SILValue plus an ownership cleanup. The unit of currency in SILGen. |
swift::Lowering::Cleanup |
include/swift/SIL/Cleanup.h |
A registered piece of teardown code (release, dealloc, ...). |
swift::Lowering::Scope |
include/swift/SIL/Scope.h |
Lexical scope; pops cleanups on exit. |
swift::SILGenBuilder |
lib/SILGen/SILGenBuilder.cpp |
Helper API around SILBuilder for ManagedValue-aware emission. |
How it works
graph TD
AST[Typed AST] --> SILGenModule
SILGenModule -->|"per Decl"| SILGenFunction
SILGenFunction --> Prolog[SILGenProlog<br/>argument lowering]
Prolog --> Body
Body -->|"SILGenStmt / SILGenExpr"| SILBuilder
Body --> Cleanups[Cleanup stack]
Cleanups --> Epilog[SILGenEpilog<br/>destructors / returns]
Epilog --> RawSIL["Raw SIL output"]SILGen is direct-style code generation over the AST. For each function:
- Prolog -- introduce SIL parameters (with appropriate ownership), copy them into local boxes if the language exposes them as
var, register cleanups for owned arguments. - Body -- recursively visit the AST. Statements lower in
SILGenStmt.cpp; expressions inSILGenExpr.cppandSILGenApply.cpp(call expressions, with all the calling-convention complexity). - Cleanup stack -- as values are produced, their
Cleanups are pushed. When a scope exits, the cleanups run in reverse order, emittingdestroy_addr,destroy_value, etc. - Epilog -- emit return cleanup, the
returninstruction, and any remaining unwind machinery (forthrowsorasync).
Notable lowering jobs
- Reabstraction (
SILGenPoly.cpp) -- when a value's calling convention has to change (e.g.,(Int) -> Stringpassed where<T, U> (T) -> Uis expected), SILGen emits a reabstraction thunk. Seedocs/Lexicon.mdentry for "abstraction pattern". async/await--SILGenApply.cppandSILGenStmt.cpplowerawaittoawait_async_continuationorhop_to_executor. The Concurrency runtime instdlib/public/Concurrency/provides the executor.throws-- error-returning functions get a special "error result" parameter (@error).trybecomes atry_applyinstruction with an error successor.- Casts --
as,as?,as!lower inSILGenDynamicCast.cppusingchecked_cast_addr_br/unconditional_checked_cast. - Property accessors --
_read,_modify,get,set,initaccessors are all separate SIL functions; SILGen synthesizes them and chooses an access pattern at call sites (seedocs/Lexicon.md"access pattern"). - Generics -- generic functions lower into
@genericSIL functions witharchetypetypes. Specialization happens in the optimizer, not here. - Distributed actors (
SILGenDistributed.cpp) -- remote calls expand into a witness forDistributedActorSystem.
Integration points
- Reads the typed AST produced by Sema. All types must be resolved.
- Writes raw SIL into a
swift::SILModule(defined ininclude/swift/SIL/). - Coordinates with the SIL optimizer: the mandatory passes immediately following SILGen complete the lowering (definite initialization, ownership lowering for legacy paths, mandatory inlining of
@_transparentand the like). - Knows about the standard library because it emits direct calls to Builtin operations; see
lib/SILGen/SILGenBuiltin.cpp.
Entry points for modification
- Adding a new lowering for a Decl kind: extend
SILGenDecl.cpporSILGen.cpp'semitDecl. - Lowering a new statement: extend
SILGenStmt.cpp::SILGenFunction::emitStmt. - Lowering a new expression: add a visitor in
SILGenExpr.cpp(SILGenFunction::emitExpr). - Investigating a SILGen bug: emit raw SIL via
swift -frontend -emit-silgen file.swift.
Related pages
- Sema -- input.
- SIL and the SIL optimizer -- the next stage and the eventual canonical form.
- IRGen -- consumer of canonical SIL.
- Runtime -- the runtime entry points SILGen emits calls to.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.