Skip to content

Commit f6ba49e

Browse files
committed
Add docs/SILDevelopment.rst.
Document SILFunction and `apply` arguments. Create TBD headers to give the document some form.
1 parent ae6645d commit f6ba49e

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

docs/SIL.rst

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ In contrast to LLVM IR, SIL is a generally target-independent format
2828
representation that can be used for code distribution, but it can also express
2929
target-specific concepts as well as LLVM can.
3030

31+
For more information on developing the implementation of SIL and SIL passes, see
32+
SILProgrammersManual.md.
33+
3134
SIL in the Swift Compiler
3235
-------------------------
3336

docs/SILProgrammersManual.md

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# SIL Programmers' Manual
2+
3+
This document provides information for developers working on the
4+
implementation of SIL. The formal specification of the Swift
5+
Intermediate _Language_ is in SIL.rst. This is a guide to the internal
6+
implementation. Source comments normally provide this level of
7+
information as much as possible. However, some features of the
8+
implementation are spread out across the source base. This
9+
documentation is meant to offer a central point for approaching the
10+
source base with links to the code for more detailed comments.
11+
12+
## SILType
13+
14+
TBD: Define the different levels of types. Explain type lowering with
15+
examples.
16+
17+
## SILInstructionResults
18+
19+
TBD: Explain how the various types fit together with pointers to the
20+
source: SILValue, SILInstruction, SingleValueInstruction,
21+
MultipleValueInstructionResult. And why it was done this way.
22+
23+
## `SILFunction` and `apply` arguments.
24+
25+
Throughout the compiler, integer indices are used to identify argument
26+
positions in several different contexts:
27+
28+
- A `SILFunctionType` has a tuple of parameters.
29+
30+
- The SIL function definition has a list of `SILFunctionArgument`.
31+
This is the callee-side argument list. It includes indirect results.
32+
33+
- `apply`, `try_apply`, and `begin_apply` have "applied arguments":
34+
the subset of instruction operands representing the callee's
35+
`SILFunctionArgument` list.
36+
37+
- `partial_apply` has "applied arguments": the subset of instruction
38+
operands representing closure captures. Closure captures in turn map
39+
to a subset of the callee's `SILFunctionArgument` list.
40+
41+
- In the above three contexts, `SILFunctionArgument`, `apply`, and
42+
`partial_apply`, the argument indices also depend on the SIL stage:
43+
Canonical vs. Lowered.
44+
45+
Consider the example:
46+
47+
```
48+
func example<T>(Int, i, t: T) -> (Int, T) {
49+
let foo = { return ($0, t) }
50+
return foo(i)
51+
}
52+
```
53+
54+
The closure `foo` has the indices as numbered below in each
55+
context, ignoring the calling convention and boxing/unboxing of
56+
captures for brevity:
57+
58+
The closure's `SILFunctionType` has two direct formal parameters at
59+
indices (`#0`, `#1`) and one direct formal result of tuple type:
60+
61+
```
62+
SILFunctionType(foo): (#0: Int, #1: T) -> @out (Int, T)
63+
```
64+
65+
Canonical SIL with opaque values matches `SILFunctionType`. The
66+
definition of `foo` has two direct `SILFunctionArgument`s at (`#0`,
67+
`#1`):
68+
69+
```
70+
SILFunctionArguments: (#0: Int, #1: T) -> (Int, T)
71+
```
72+
73+
The Lowered SIL for `foo`s definition has an indirect "result
74+
argument" at index #0. The function parameter indices are now (`#1`,
75+
`#2`):
76+
77+
```
78+
SILFunctionArguments: (#0: *T, #1: Int, #2: T) -> Int
79+
```
80+
81+
Creation of the closure has one applied argument at index `#0`. Note
82+
that the first applied argument is actually the second operand (the
83+
first is the callee), and in lowered SIL, it is actually the third
84+
SILFunctionArgument (after the indirect result and first parameter):
85+
86+
```
87+
%closure = partial_apply @foo(#0: %t)
88+
```
89+
90+
Application of the closure with opaque values has one applied
91+
argument:
92+
93+
```
94+
%resultTuple = apply %closure(#0: i)
95+
```
96+
97+
Lowered application of the closure has two applied arguments:
98+
99+
```
100+
%directResult = apply %closure(#0: %indirectResult: $*T, #1: i)
101+
```
102+
103+
The mapping between `SILFunctionType` and `SILFunctionArgument`, which depends
104+
on the SIL stage, is managed by the
105+
[SILFunctionConventions](https://github.com/apple/swift/blob/master/include/swift/SIL/SILFunctionConventions.h)
106+
abstraction. This API follows naming conventions to communicate the meaning of the integer indices:
107+
108+
- "Parameters" refer to the function signature's tuple of arguments.
109+
110+
- "SILArguments" refer to the set of `SILFunctionArgument` in the callee's entry block, including any indirect results required by the current SIL stage.
111+
112+
These argument indices and their relative offsets should never be
113+
hardcoded. Although this is common practice in LLVM, it should be
114+
avoided in SIL: (a) the structure of SIL instructions, particularly
115+
applies, is much more nuanced than LLVM IR, (b) assumptions that may
116+
be valid at the initial point of use are often copied into parts of
117+
the code where they are no longer valid; and (c) unlike LLVM IR, SIL
118+
is not stable and will continue evolving.
119+
120+
Translation between SILArgument and parameter indices should use:
121+
`SILFunctionConventions::getSILArgIndexOfFirstParam()`.
122+
123+
Translation between SILArgument and result indices should use:
124+
`SILFunctionConventions::getSILArgIndexOfFirstIndirectResult()`.
125+
126+
Convenience methods exist for the most common uses, so there is
127+
typically no need to use the above "IndexOfFirst" methods to translate
128+
one integer index into another. The naming convention of the
129+
convenience method should clearly indicate which form of index it
130+
expects. For example, information about a parameter's type can be retrieved directly from a SILArgument index: `getParamInfoForSILArg(index)`, `getSILArgumentConvention(index)`, and `getSILArgumentType(index)`.
131+
132+
Another abstraction,
133+
[`ApplySite`](https://github.com/search?utf8=✓&q=%22class+ApplySite%22+repo%3Aapple%2Fswift+path%3Ainclude%2Fswift%2FSIL&type=Code&ref=advsearch&l=&l=),
134+
abstracts over the various kinds of `apply` instructions, including
135+
`try_apply`, `begin_apply`, and `partial_apply`.
136+
137+
`ApplySite::getSubstCalleeConv()` is commonly used to query the
138+
callee's `SILFunctionConventions` which provides information about the
139+
function's type and its definition as explained above. Information about the applied arguments can be queried directly from the `ApplySite` API.
140+
141+
For example, `ApplySite::getAppliedArgumentConvention(index)` takes an
142+
applied argument index, while
143+
`SILFunctionArguments::getSILArgumentConvention(index`) takes a
144+
`SILFunctionArgument` index. They both return the same information,
145+
but from a different viewpoint.
146+
147+
A common mistake is to directly map the ApplySite's caller-side
148+
arguments onto callee-side SILFunctionArguments. This happens to work
149+
until the same code is exposed to a `partial_apply`. Instead, use the `ApplySite` API for applied argument indices, or use
150+
`ApplySite::getCalleeArgIndexOfFirstAppliedArg()` to translate the
151+
apply's arguments into function convention arguments.
152+
153+
Consistent use of common idioms for accessing arguments should be
154+
adopted throughout the compiler. Plenty of bugs have resulted from
155+
assumptions about the form of SIL made in one area of the compiler
156+
that have been copied into other parts of the compiler. For example,
157+
knowing that a block of code is guarded by a dynamic condition that
158+
rules out PartialApplies is no excuse to conflate applied arguments
159+
with function arguments. Also, without consistent use of common
160+
idioms, it becomes overly burdensome to evolve these APIs over time.
161+
162+
## SILGen
163+
164+
TBD: Possibly link to a separate document explaining the architecture of SILGen.
165+
166+
Some information from SIL.rst could be moved here.
167+
168+
## IRGen
169+
170+
TBD: Possibly link to a separate document explaining the architecture of IRGen.
171+
172+
## SILAnalysis and the PassManager
173+
174+
TBD: describe the mechanism by which passes invalidate and update the
175+
PassManager and its avaiable analyses.
176+
177+
## High Level SIL Optimizations
178+
179+
HighLevelSILOptimizations.rst discusses how the optimizer imbues
180+
certain special SIL types and SIL functions with higher level
181+
semantics.

0 commit comments

Comments
 (0)