Skip to content

Commit 9d093f3

Browse files
committed
updates: increase some of the description of compiler flow, change some minor wording
and fix some syntactic issues. Swift SVN r6590
1 parent 740f8b8 commit 9d093f3

File tree

1 file changed

+63
-44
lines changed

1 file changed

+63
-44
lines changed

docs/SIL.rst

Lines changed: 63 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Swift Intermediate Language (SIL)
88
Abstract
99
--------
1010

11-
SIL is a SSA-form IR with high-level semantic information designed to implement
11+
SIL is an SSA-form IR with high-level semantic information designed to implement
1212
the Swift programming language. SIL accommodates the following use cases:
1313

1414
- High-level optimization passes, including retain/release optimization,
@@ -23,6 +23,10 @@ the Swift programming language. SIL accommodates the following use cases:
2323
inlineable or generic code with Swift library modules, to be optimized into
2424
client binaries.
2525

26+
In contrast to LLVM IR, SIL is a generally target-independent format
27+
representation that can be used for code distribution, but can also express
28+
target-specific concepts as well as Swift can.
29+
2630
SIL in the Swift Compiler
2731
-------------------------
2832

@@ -31,10 +35,16 @@ At a high level, the Swift compiler follows a strict pipeline architecture:
3135
- The *Parse* module constructs an AST from Swift source code.
3236
- The *Sema* module type-checks the AST and annotates it with type information.
3337
- The *SILGen* module generates "raw" SIL from an AST.
34-
- SIL *Passes* run over the raw SIL to emit diagnostics and apply optimizations
35-
to produce canonical SIL.
38+
- A series of *Guaranteed Optimization Passes* and *Diagnostic Passes* are run
39+
over the "raw" to both perform optimizations, but also to emit
40+
language-specific diagnostics. These are always run, even at -O0, and produce
41+
"canonical" SIL.
42+
- General SIL *Optimization Passes* optionally run over the canonical SIL to
43+
improve performance of the resultant executable. These are enabled and
44+
controlled by the optimization level and are not run at -O0.
3645
- *IRGen* lowers optimized SIL to LLVM IR.
37-
- The LLVM backend applies LLVM optimizations and emits binary code.
46+
- The LLVM backend (optionally) applies LLVM optimizations, runs the LLVM code
47+
generator and emits binary code.
3848

3949
The stages pertaining to SIL processing in particular are as follows:
4050

@@ -50,7 +60,7 @@ emitted by SILGen has the following properties:
5060
represents variables as reference-counted "boxes" in the most general case,
5161
which can be retained, released, and shared.
5262
- Dataflow requirements, such as definitive assignment, function returns,
53-
switch coverage, etc. have not yet been enforced.
63+
switch coverage (TBD), etc. have not yet been enforced.
5464
- ``always_inline``, ``always_instantiate``, and other function optimization
5565
attributes have not yet been honored.
5666

@@ -62,7 +72,9 @@ Guaranteed Optimization Passes
6272

6373
After SILGen, a deterministic sequence of optimization passes is run over the
6474
raw SIL. These passes are more concerned with predictability and exposing
65-
dataflow for diagnostic passes than performance.
75+
dataflow for diagnostic passes than performance. Notably, we do not want the
76+
diagnostics produced by the compiler to change as the compiler evolves, so these
77+
passes are intended to be simple and predictable.
6678

6779
- Memory promotion: this is implemented as two optimization phases, the first
6880
of which performs capture analysis to promote alloc_box instructions to
@@ -74,6 +86,7 @@ TODO:
7486
- Always inline
7587
- Constant folding/guaranteed simplifications (including constant overflow
7688
warnings)
89+
- Basic ARC optimization for acceptable performance at -O0.
7790

7891
Diagnostic Passes
7992
~~~~~~~~~~~~~~~~~
@@ -91,11 +104,18 @@ TODO:
91104
- Dead code detection/elimination. Non-implicit dead code is an error.
92105
- Definitive assignment of local variables, and of instance variables in
93106
constructors.
94-
- Basic ARC optimization for decent performance at -O0.
95107

96108
If the diagnostic passes all succeed, the final result is the *canonical SIL*
97-
for the program. Performance optimization, native code generation, and module
98-
distribution are derived from this form.
109+
for the program. Performance optimization and, native code generation are
110+
derived from this form, and a module can be built from this (or later) forms.
111+
112+
General Optimization Passes
113+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
114+
115+
SIL captures language-specific type information, which makes it possible to
116+
perform high-level optimizations such as generics specialization that are
117+
difficult to perform on LLVM IR. The details of these have not been fully
118+
nailed down, but we expect this to be important.
99119

100120
Syntax
101121
------
@@ -131,7 +151,7 @@ Here is an example of a ``.sil`` file::
131151
%1 = function_ref @_TSsoi1pfTSdSd_Sd
132152
%2 = struct_extract %0 : $Point, #Point.x
133153
%3 = struct_extract %0 : $Point, #Point.y
134-
%4 = apply %1(%2 : $Double, %3 : $Double) : $(Double, Double) -> Double
154+
%4 = apply %1(%2, %3) : $(Double, Double) -> Double
135155
%5 = return %4 : Double
136156
}
137157

@@ -152,7 +172,7 @@ type grammar. SIL adds some additional kinds of type of its own:
152172

153173
Addresses of address-only types (see below) can only be used with
154174
instructions that manipulate their operands indirectly by address, such
155-
as ``copy_addr``, ``destroy_addr``, and ``dealloc_var``, or as arguments
175+
as ``copy_addr``, ``destroy_addr``, and ``dealloc_stack``, or as arguments
156176
to functions. For an address-only type ``T``, only the SIL address ``$*T``
157177
can be formed. ``$T`` for address-only ``T`` is an invalid SIL type.
158178

@@ -251,7 +271,7 @@ is always followed by a ``:`` and the SIL type of the value. For example::
251271
%negate = builtin_function_ref #Builtin.neg_Int64
252272
%five = integer_literal 5 : $Builtin.Int64
253273
// Use the values as operands
254-
%neg_five = apply %negate(%five : $Builtin.Int64) : (Builtin.Int64) -> Builtin.Int64
274+
%neg_five = apply %negate(%five) : (Builtin.Int64) -> Builtin.Int64
255275

256276
In SIL, a single instruction may produce multiple values. Operands that refer
257277
to multiple-value instructions choose the value by following the ``%name`` with
@@ -326,8 +346,8 @@ received from the function caller::
326346
sil @bar : $(Int, Int) -> () {
327347
bb0(%x : $Int, %y : $Int):
328348
%foo = function_ref @foo
329-
%1 = apply %foo(%x : $Int) : $(Int) -> Int
330-
%2 = apply %foo(%y : $Int) : $(Int) -> Int
349+
%1 = apply %foo(%x) : $(Int) -> Int
350+
%2 = apply %foo(%y) : $(Int) -> Int
331351
%3 = tuple ()
332352
%4 = return %3 : $()
333353
}
@@ -497,11 +517,10 @@ in the ``apply`` instructions used by callers::
497517
entry:
498518
...
499519
%foo = function_ref @foo : $(x:Int, y:Int) -> ()
500-
%foo_result = apply %foo(%1 : $Int, %2 : $Int) : $(x:Int, y:Int) -> ()
520+
%foo_result = apply %foo(%1, %2) : $(x:Int, y:Int) -> ()
501521
...
502522
%bar = function_ref @bar : $(x:Int, y:(Int, Int)) -> ()
503-
%bar_result = apply %bar(%4 : $Int, %5 : $Int, %6 : $Int) \
504-
: $(x:Int, y:(Int, Int)) -> ()
523+
%bar_result = apply %bar(%4, %5, %6) : $(x:Int, y:(Int, Int)) -> ()
505524
}
506525

507526
Calling a function with trivial value types as inputs and outputs
@@ -514,7 +533,7 @@ simply passes the arguments by value. This Swift function::
514533
gets called in SIL as::
515534

516535
%foo = constant_ref $(Int, Float) -> Char, @foo
517-
%z = apply %foo(%x, %y)
536+
%z = apply %foo(%x, %y) : $(Int, Float) -> Char
518537

519538
Reference Counts
520539
````````````````
@@ -526,15 +545,15 @@ type components each retained and released the same way. This Swift function::
526545

527546
class A {}
528547

529-
func bar(x:A) -> (Int, A)
548+
func bar(x:A) -> (Int, A) { ... }
530549

531550
bar(x)
532551

533552
gets called in SIL as::
534553

535554
%bar = function_ref @bar : $(A) -> (Int, A)
536555
retain %x : $A
537-
%z = apply %bar(%x : $A) : $(A) -> (Int, A)
556+
%z = apply %bar(%x) : $(A) -> (Int, A)
538557
// ... use %z ...
539558
%z_1 = tuple_extract %z : $(Int, A), 1
540559
release %z_1
@@ -563,11 +582,11 @@ gets called in SIL as::
563582
%z = alloc_stack $A
564583
%x_arg = alloc_stack $A
565584
copy_addr %x : $*A to [initialize] %x_arg : $*A
566-
apply %bas(%z : $*A, %x_arg : $*A, %y : $Int) : $(A, Int) -> A
585+
apply %bas(%z, %x_arg, %y) : $(A, Int) -> A
567586
dealloc_stack %x_arg : $*A // callee consumes %x.arg, caller deallocs
568587
// ... use %z ...
569588
destroy_addr %z : $*A
570-
dealloc_var stack %z : $*A
589+
dealloc_stack stack %z : $*A
571590

572591
The implementation of ``@bas`` is then responsible for consuming ``%x_arg`` and
573592
initializing ``%z``.
@@ -588,12 +607,11 @@ gets called in SIL as::
588607
%y_arg = alloc_stack $A
589608
copy_addr %y : $*A to [initialize] %y_arg : $*A
590609
%w_0_addr = element_addr %w : $*(A, Int), 0
591-
%w_0_arg = alloc_var stack $A
610+
%w_0_arg = alloc_stack $A
592611
copy_addr %w_0_addr : $*A to [initialize] %w_0_arg : $*A
593612
%w_1_addr = element_addr %w : $*(A, Int), 1
594613
%w_1 = load %w_1_addr : $*Int
595-
apply %zim(%x : $Int, %y_arg : $*A, %z : $Int, %w_0_arg : $A, %w_1 : $Int) \
596-
: $(x:Int, y:A, (z:Int, w:(A, Int))) -> ()
614+
apply %zim(%x, %y_arg, %z, %w_0_arg, %w_1) : $(x:Int, y:A, (z:Int, w:(A, Int))) -> ()
597615
dealloc_stack %w_0_arg
598616
dealloc_stack %y_arg
599617

@@ -612,8 +630,7 @@ gets called in SIL as::
612630
%zang = function_ref @zang : $(x:Int, (y:Int, z:Int...), v:Int, w:Int...) -> ()
613631
%zs = <<make array from %z1, %z2>>
614632
%ws = <<make array from %w0, %w1, %w2>>
615-
apply %zang(%x : $Int, %y : $Int, %zs : $Int[], %v : $Int, %ws : $Int[]) \
616-
: $(x:Int, (y:Int, z:Int...), v:Int, w:Int...) -> ()
633+
apply %zang(%x, %y, %zs, %v, %ws) : $(x:Int, (y:Int, z:Int...), v:Int, w:Int...) -> ()
617634

618635
Function Currying
619636
`````````````````
@@ -664,8 +681,8 @@ alloc_stack
664681
%1 = alloc_stack $T
665682
// %1 has type $*T
666683

667-
Allocates enough uninitialized memory on the stack to contain a value of type
668-
``T``. The result of the instruction is the address
684+
Allocates enough uninitialized memory that is sufficiently aligned on the stack
685+
to contain a value of type ``T``. The result of the instruction is the address
669686
of the allocated memory. ``alloc_stack`` marks the start of the lifetime of
670687
the value; the allocation must be balanced with a ``dealloc_stack``
671688
instruction to mark the end of its lifetime. The memory is not retainable;
@@ -696,7 +713,8 @@ alloc_box
696713
// %1#1 has type $*T
697714

698715
Allocates a reference-counted "box" on the heap large enough to hold a value of
699-
type ``T``. The result of the instruction is a two-value operand;
716+
type ``T``, along with a retain count and any other metadata required by the
717+
runtime. The result of the instruction is a two-value operand;
700718
the first value is the reference-counted ``ObjectPointer`` that owns the box,
701719
and the second value is the address of the value inside the box.
702720

@@ -785,12 +803,13 @@ store
785803
`````
786804
::
787805

788-
store %0 : $T to %1 : $*T
806+
store %0 to %1 : $*T
789807
// $T must be a loadable type
790808

791-
Stores the value ``%0`` to memory at address ``%1``. ``%0`` must be of a
792-
loadable type. This will overwrite the memory at ``%1``; ``%1`` must reference
793-
uninitialized or destroyed memory.
809+
Stores the value ``%0`` to memory at address ``%1``. The type of %1 is ``*T``
810+
and the type of ``%0 is ``T``, which must be of a loadable type. This will
811+
overwrite the memory at ``%1``; ``%1`` must reference uninitialized or destroyed
812+
memory.
794813

795814
initialize_var
796815
``````````````
@@ -1245,7 +1264,7 @@ apply
12451264
'(' (sil-operand (',' sil-operand)?)? ')'
12461265
':' sil-type
12471266

1248-
%r = apply %0(%1 : $A, %2 : $B, ...) : $(A, B, ...) -> R
1267+
%r = apply %0(%1, %2, ...) : $(A, B, ...) -> R
12491268
// Note that the type of the callee '%0' is specified *after* the arguments
12501269
// %0 must be of a concrete function type $(A, B, ...) -> R
12511270
// %1, %2, etc. must be of the argument types $A, $B, etc.
@@ -1270,7 +1289,7 @@ partial_apply
12701289
'(' (sil-operand (',' sil-operand)?)? ')'
12711290
':' sil-type
12721291

1273-
%c = partial_apply %0(%1 : $A, %2 : $B, ...) : $[thin] (T..., A, B, ...) -> R
1292+
%c = partial_apply %0(%1, %2, ...) : $[thin] (T..., A, B, ...) -> R
12741293
// Note that the type of the callee '%0' is specified *after* the arguments
12751294
// %0 must be of a thin concrete function type $[thin] (T..., A, B, ...) -> R
12761295
// %1, %2, etc. must be of the argument types $A, $B, etc.,
@@ -1295,21 +1314,21 @@ clarity)::
12951314
func @foo : $[thin] A -> B -> C -> D -> E {
12961315
entry(%a : $A):
12971316
%foo_1 = function_ref @foo_1 : $[thin] (B, A) -> C -> D -> E
1298-
%thunk = partial_apply %foo_1(%a : $A) : $[thin] (B, A) -> C -> D -> E
1317+
%thunk = partial_apply %foo_1(%a) : $[thin] (B, A) -> C -> D -> E
12991318
return %thunk : $B -> C -> D -> E
13001319
}
13011320

13021321
func @foo_1 : $[thin] (B, A) -> C -> D -> E {
13031322
entry(%b : $B, %a : $A):
13041323
%foo_2 = function_ref @foo_2 : $[thin] (C, B, A) -> D -> E
1305-
%thunk = partial_apply %foo_2(%b : $B, %a : $A) : $[thin] (C, B, A) -> D -> E
1324+
%thunk = partial_apply %foo_2(%b, %a) : $[thin] (C, B, A) -> D -> E
13061325
return %thunk : $(B, A) -> C -> D -> E
13071326
}
13081327

13091328
func @foo_2 : $[thin] (C, B, A) -> D -> E {
13101329
entry(%c : $C, %b : $B, %a : $A):
13111330
%foo_3 = function_ref @foo_3 : $[thin] (D, C, B, A) -> E
1312-
%thunk = partial_apply %foo_3(%c : $C, %b : $B, %a : $A) : $[thin] (D, C, B, A) -> E
1331+
%thunk = partial_apply %foo_3(%c, %b, %a) : $[thin] (D, C, B, A) -> E
13131332
return %thunk : $(C, B, A) -> D -> E
13141333
}
13151334

@@ -1339,11 +1358,11 @@ lowers to an uncurried entry point and is curried in the enclosing function::
13391358
entry(%x : $Int):
13401359
// Create the bar closure
13411360
%bar_uncurried = function_ref @bar : $(Int, Int) -> Int
1342-
%bar = partial_apply %bar_uncurried(%x : $Int) : $(Int, Int) -> Int
1361+
%bar = partial_apply %bar_uncurried(%x) : $(Int, Int) -> Int
13431362

13441363
// Apply it
13451364
%1 = integer_literal $Int, 1
1346-
%ret = apply %bar(%1 : $Int) : $(Int) -> Int
1365+
%ret = apply %bar(%1) : $(Int) -> Int
13471366

13481367
// Clean up
13491368
release %bar : $(Int) -> Int
@@ -1676,7 +1695,7 @@ compiles to this SIL sequence::
16761695
%bar = protocol_method %foo : $*Foo, #Foo.bar!1
16771696
%foo_p = project_existential %foo : $*Foo
16781697
%one_two_three = integer_literal $Int, 123
1679-
%_ = apply %bar(%one_two_three : $Int, %foo_p : $Builtin.OpaquePointer) : $(Int, Builtin.OpaquePointer) -> ()
1698+
%_ = apply %bar(%one_two_three, %foo_p) : $(Int, Builtin.OpaquePointer) -> ()
16801699

16811700
It is undefined behavior if the result of ``project_existential`` is used as
16821701
anything other than the "this" argument of an instance method reference
@@ -1739,7 +1758,7 @@ compiles to this SIL sequence::
17391758
%bar = protocol_method %foo : $Foo, #Foo.bar!1
17401759
%foo_p = project_existential_ref %foo : $Foo
17411760
%one_two_three = integer_literal $Int, 123
1742-
%_ = apply %bar(%one_two_three : $Int, %foo_p : $Builtin.ObjCPointer) : $(Int, Builtin.ObjCPointer) -> ()
1761+
%_ = apply %bar(%one_two_three, %foo_p) : $(Int, Builtin.ObjCPointer) -> ()
17431762

17441763
It is undefined behavior if the result of ``project_existential_ref`` is used
17451764
as anything other than the "this" argument of an instance method reference
@@ -2222,7 +2241,7 @@ For example::
22222241
%a = tuple_extract %ab : $(Int, Int), 0
22232242
%b = tuple_extract %ab : $(Int, Int), 1
22242243
%add = function_ref @add : $(Int, Int) -> Int
2225-
%result = apply %add(%a : $Int, %b : $Int) : $(Int, Int) -> Int
2244+
%result = apply %add(%a, %b) : $(Int, Int) -> Int
22262245
return %result : $Int
22272246
}
22282247

0 commit comments

Comments
 (0)