Skip to content

Commit 6079cbe

Browse files
committed
AccessBase documentation
Split the SIL function convention and memory access documentation into separate documents. Reference them from SIL.rst.
1 parent 19cff2e commit 6079cbe

File tree

5 files changed

+634
-632
lines changed

5 files changed

+634
-632
lines changed

Diff for: docs/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ documentation, please create a thread on the Swift forums under the
123123
Describes how to maintain compatibility when changing the serialization
124124
format.
125125
- SIL and SIL Optimizations:
126+
- [SILFunctionConventions.md](/docs/SILFunctionConventions.md):
127+
- [SILMemoryAccess.md](/docs/SILMemoryAccess.md):
126128
- [SILProgrammersManual.md](/docs/SILProgrammersManual.md):
127129
Provides an overview of the implementation of SIL in the compiler.
128130
- [OptimizerDesign.md](/docs/OptimizerDesign.md):

Diff for: docs/SIL.rst

+5-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@ In contrast to LLVM IR, SIL is a generally target-independent format
2929
representation that can be used for code distribution, but it can also express
3030
target-specific concepts as well as LLVM can.
3131

32-
For more information on developing the implementation of SIL and SIL passes, see
33-
`SILProgrammersManual.md <SILProgrammersManual.md>`_.
32+
For more information on developing the implementation of SIL and SIL passes, see:
33+
34+
- `SILProgrammersManual.md <SILProgrammersManual.md>`_.
35+
- `SILFunctionConventions.md <SILFunctionConventions.md>`_.
36+
- `SILMemoryAccess.md <SILMemoryAccess.md>`_.
3437

3538
SIL in the Swift Compiler
3639
-------------------------

Diff for: docs/SILFunctionConventions.md

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# SIL Function Conventions
2+
3+
Throughout the compiler, integer indices are used to identify argument
4+
positions in several different contexts:
5+
6+
- A `SILFunctionType` has a tuple of parameters.
7+
8+
- The SIL function definition has a list of `SILFunctionArgument`.
9+
This is the callee-side argument list. It includes indirect results.
10+
11+
- `apply`, `try_apply`, and `begin_apply` have "applied arguments":
12+
the subset of instruction operands representing the callee's
13+
`SILFunctionArgument` list.
14+
15+
- `partial_apply` has "applied arguments": the subset of instruction
16+
operands representing closure captures. Closure captures in turn map
17+
to a subset of the callee's `SILFunctionArgument` list.
18+
19+
- In the above three contexts, `SILFunctionArgument`, `apply`, and
20+
`partial_apply`, the argument indices also depend on the SIL stage:
21+
Canonical vs. Lowered.
22+
23+
Consider the example:
24+
25+
```swift
26+
func example<T>(i: Int, t: T) -> (Int, T) {
27+
let foo = { return ($0, t) }
28+
return foo(i)
29+
}
30+
```
31+
32+
The closure `foo` has the indices as numbered below in each
33+
context, ignoring the calling convention and boxing/unboxing of
34+
captures for brevity:
35+
36+
The closure's `SILFunctionType` has two direct formal parameters at
37+
indices (`#0`, `#1`) and one direct formal result of tuple type:
38+
39+
```
40+
SILFunctionType(foo): (#0: Int, #1: T) -> @out (Int, T)
41+
```
42+
43+
Canonical SIL with opaque values matches `SILFunctionType`. The
44+
definition of `foo` has two direct `SILFunctionArgument`s at (`#0`,
45+
`#1`):
46+
47+
```
48+
SILFunctionArguments: (#0: Int, #1: T) -> (Int, T)
49+
```
50+
51+
The Lowered SIL for `foo`s definition has an indirect "result
52+
argument" at index #0. The function parameter indices are now (`#1`,
53+
`#2`):
54+
55+
```
56+
SILFunctionArguments: (#0: *T, #1: Int, #2: T) -> Int
57+
```
58+
59+
Creation of the closure has one applied argument at index `#0`. Note
60+
that the first applied argument is actually the second operand (the
61+
first is the callee), and in lowered SIL, it is actually the third
62+
SILFunctionArgument (after the indirect result and first parameter):
63+
64+
```
65+
%closure = partial_apply @foo(#0: t)
66+
```
67+
68+
Application of the closure with opaque values has one applied
69+
argument:
70+
71+
```
72+
%resultTuple = apply %closure(#0: i)
73+
```
74+
75+
Lowered application of the closure has two applied arguments:
76+
77+
```
78+
%directResult = apply %closure(#0: %indirectResult: *T, #1: i)
79+
```
80+
81+
The mapping between `SILFunctionType` and `SILFunctionArgument`, which depends
82+
on the SIL stage, is managed by the
83+
[SILFunctionConventions](https://github.com/apple/swift/blob/main/include/swift/SIL/SILFunctionConventions.h)
84+
abstraction. This API follows naming conventions to communicate the meaning of the integer indices:
85+
86+
- "Parameters" refer to the function signature's tuple of arguments.
87+
88+
- "SILArguments" refer to the set of `SILFunctionArgument` in the callee's entry block, including any indirect results required by the current SIL stage.
89+
90+
These argument indices and their relative offsets should never be
91+
hardcoded. Although this is common practice in LLVM, it should be
92+
avoided in SIL: (a) the structure of SIL instructions, particularly
93+
applies, is much more nuanced than LLVM IR, (b) assumptions that may
94+
be valid at the initial point of use are often copied into parts of
95+
the code where they are no longer valid; and (c) unlike LLVM IR, SIL
96+
is not stable and will continue evolving.
97+
98+
Translation between SILArgument and parameter indices should use:
99+
`SILFunctionConventions::getSILArgIndexOfFirstParam()`.
100+
101+
Translation between SILArgument and result indices should use:
102+
`SILFunctionConventions::getSILArgIndexOfFirstIndirectResult()`.
103+
104+
Convenience methods exist for the most common uses, so there is
105+
typically no need to use the above "IndexOfFirst" methods to translate
106+
one integer index into another. The naming convention of the
107+
convenience method should clearly indicate which form of index it
108+
expects. For example, information about a parameter's type can be retrieved directly from a SILArgument index: `getParamInfoForSILArg(index)`, `getSILArgumentConvention(index)`, and `getSILArgumentType(index)`.
109+
110+
Another abstraction,
111+
[`ApplySite`](https://github.com/search?utf8=✓&q=%22class+ApplySite%22+repo%3Aapple%2Fswift+path%3Ainclude%2Fswift%2FSIL&type=Code&ref=advsearch&l=&l=),
112+
abstracts over the various kinds of `apply` instructions, including
113+
`try_apply`, `begin_apply`, and `partial_apply`.
114+
115+
`ApplySite::getSubstCalleeConv()` is commonly used to query the
116+
callee's `SILFunctionConventions` which provides information about the
117+
function's type and its definition as explained above. Information about the applied arguments can be queried directly from the `ApplySite` API.
118+
119+
For example, `ApplySite::getAppliedArgumentConvention(index)` takes an
120+
applied argument index, while
121+
`SILFunctionArguments::getSILArgumentConvention(index`) takes a
122+
`SILFunctionArgument` index. They both return the same information,
123+
but from a different viewpoint.
124+
125+
A common mistake is to directly map the ApplySite's caller-side
126+
arguments onto callee-side SILFunctionArguments. This happens to work
127+
until the same code is exposed to a `partial_apply`. Instead, use the `ApplySite` API for applied argument indices, or use
128+
`ApplySite::getCalleeArgIndexOfFirstAppliedArg()` to translate the
129+
apply's arguments into function convention arguments.
130+
131+
Consistent use of common idioms for accessing arguments should be
132+
adopted throughout the compiler. Plenty of bugs have resulted from
133+
assumptions about the form of SIL made in one area of the compiler
134+
that have been copied into other parts of the compiler. For example,
135+
knowing that a block of code is guarded by a dynamic condition that
136+
rules out PartialApplies is no excuse to conflate applied arguments
137+
with function arguments. Also, without consistent use of common
138+
idioms, it becomes overly burdensome to evolve these APIs over time.
139+

0 commit comments

Comments
 (0)