You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
_Libswift_ is the part of the Swift compiler, which is implemented in Swift.
4
-
5
-
With _libswift_ it is possible to add SIL optimization passes written in Swift. It allows to gradually migrate the SIL optimizer from C++ to Swift.
3
+
This is the part of the Swift compiler which is implemented in Swift itself.
6
4
7
5
## Building
8
6
9
-
_Libswift_ is a static library and it is built as part of the swift compiler using build-script and CMake.
7
+
Although this directory is organized like a Swift package, building is done with CMake.
8
+
Beside building, the advantage of a Swift package structure is that it is easy to edit the sources with Xcode.
10
9
11
-
To enable _libswift_, add the build-script option `--libswift`.
10
+
The Swift modules are compiled into object files and linked as a static library. The build-script option `--bootstrapping` controls how the Swift modules are built.
12
11
13
-
Currently the `swift-frontend` and `sil-opt` tools use _libswift_. Tools, which don't use any optimization passes from _libswift_don't need to link _libswift_. For example, all tools, which compile Swift source code, but don't optimize it, like SourceKit or lldb, don't need to link _libswift_. As long as `initializeLibSwift()` is not called there is no dependency on _libswift_.
12
+
Currently, the `swift-frontend` and `sil-opt` tools include the Swift modules. Tools, which don't use any parts from the Swift code don't need to link the Swift library. And also `swift-frontend` does not strictly require to include the Swift modules. If the compiler is built without the Swift modules, the corresponding features, e.g. optimizations, are simply not available.
14
13
15
14
### Build modes
16
15
17
-
There are four build modes for _libswift_, which can be selected with the `--libswift=<mode>` build-script option:
16
+
There are four build modes, which can be selected with the `--bootstrapping=<mode>` build-script option:
18
17
19
-
*`off` (= default when no `--libswift` open is given): the compiler is not built with _libswift_. In this early stage of development this mode is the default.
20
-
*`hosttools` (= default for a `--libswift` option without argument): _libswift_is built with a pre-installed swift toolchain, using a `swiftc` which is expected to be in the command search path. This mode is the preferred way to build for local development, because it is the fastest way to build. It requires a 5.5 (or newer) swift toolchain to be installed on the host system.
21
-
*`bootstrapping`: The compiler and _libswift_ are built with a two-stage bootstrapping process. This is the preferred mode if no swift toolchain is available on the system or if the build should not depend on any pre-installed toolchain.
22
-
*`bootstrapping-with-hostlibs`: This mode is only available on macOS. It's similar to `bootstrapping`, but links the compiler against the host system swift libraries instead of the built libraries. The build is faster than with `bootstrapping` because only the swiftmodule files of the bootstrapping libraries have to be built.
18
+
*`off`: the Swift code is not included in the tools.
19
+
*`hosttools`: the Swift code is built with a pre-installed Swift toolchain, using a `swiftc` which is expected to be in the command search path. This mode is the preferred way to build for local development, because it is the fastest way to build. It requires a 5.5 (or newer) swift toolchain to be installed on the host system.
20
+
*`bootstrapping`: The compiler is built with a two-stage bootstrapping process. This is the preferred mode if no swift toolchain is available on the system or if the build should not depend on any pre-installed toolchain.
21
+
*`bootstrapping-with-hostlibs`: This mode is only available on macOS. It's similar to `bootstrapping`, but links the compiler against the host system swift libraries instead of the built libraries. The build is faster than `bootstrapping` because only the swiftmodule files of the bootstrapping libraries have to be built.
23
22
24
-
The _libswift_ build mode is cached in the `CMakeCache.txt` file in the Swift build directory. When building with a different mode, the `CMakeCache.txt` has to be deleted.
23
+
The bootstrapping mode is cached in the `CMakeCache.txt` file in the Swift build directory. When building with a different mode, the `CMakeCache.txt` has to be deleted.
25
24
26
25
### Bootstrapping
27
26
@@ -33,80 +32,74 @@ Bootstrapping involves the following steps:
33
32
34
33
The build outputs of level-0 are stored in the `bootstrapping0` directory under the main build directory.
35
34
36
-
In this first step `swift-frontend` is built, but without _libswift_. When more optimizations are migrated from C++ to _libswift_, this compiler will produce worse code than the final compiler.
35
+
In this first step `swift-frontend` is built, but without the Swift modules. When more optimizations are migrated from C++ to Swift, this compiler will produce worse code than the final compiler.
37
36
38
37
39
38
#### 2. The level-0 library
40
39
41
-
With the compiler from step 1, a minimal subset of the standard library is built in `bootstrapping0/lib/swift`. The subset contains the swift core library `libswiftCore` and, in case of a debug build, the`libswiftOnoneSupport`library. In the future it will also contain the concurrency library.
40
+
With the compiler from step 1, a minimal subset of the standard library is built in `bootstrapping0/lib/swift`. The subset contains the swift core library `libswiftCore` and some other required libraries, e.g.`libswiftOnoneSupport`in case of a debug build.
42
41
43
-
This library will be less optimized than the final library build.
42
+
These libraries will be less optimized than the final library build.
44
43
45
44
This step is skipped when the build mode is `bootstrapping-with-hostlibs`.
46
45
47
-
#### 3. The level-1 _libswift_
46
+
#### 3. The level-1 Swift modules
48
47
49
48
The build outputs of level-1 are stored in the `bootstrapping1` directory under the main build directory.
50
49
51
-
The _libswift_ library is built using the level-0 compiler and standard library from step 2 - or the OS libraries in case of `bootstrapping-with-hostlibs`.
50
+
The Swift modules are built using the level-0 compiler and standard library from step 2 - or the OS libraries in case of `bootstrapping-with-hostlibs`.
52
51
53
52
#### 4. The level-1 compiler
54
53
55
-
In this step, the level-1 `swift-frontend` is built which includes the _libswift_from step 3. This compiler already produces the exact same code as the final compiler, but might run slower, because its _libswift_ is not optimized as good as in the final build.
54
+
In this step, the level-1 `swift-frontend` is built which includes the Swift modules from step 3. This compiler already produces the exact same code as the final compiler, but might run slower, because its Swift modules are not optimized as good as in the final build.
56
55
57
-
Unless the build mode is `bootstrapping-with-hostlibs`, the level-1 compiler dynamically links against the level-1 library. This is specified with the `RPATH` setting in the executable.
56
+
Unless the build mode is `bootstrapping-with-hostlibs`, the level-1 compiler dynamically links against the level-1 libraries. This is specified with the `RPATH` setting in the executable.
58
57
59
58
#### 5. The level-1 library
60
59
61
60
Like in step 2, a minimal subset of the standard library is built, using the level-1 compiler from step 4.
62
61
63
-
In this step, the buildsystem redirects the compiler's dynamic library path to the level-0 library (by setting `DY/LD_LIBRARY_PATH` in `SwiftSource.cmake`:`_compile_swift_files`). This is needed because the level-1 libraries are not built, yet.
62
+
In this step, the build-system redirects the compiler's dynamic library path to the level-0 library (by setting `DY/LD_LIBRARY_PATH` in `SwiftSource.cmake`:`_compile_swift_files`). This is needed because the level-1 libraries are not built, yet.
64
63
65
64
This step is skipped when the build mode is `bootstrapping-with-hostlibs`.
66
65
67
-
#### 6. The final _libswift_
66
+
#### 6. The final Swift modules
68
67
69
-
The final _libswift_ is built with the level-1 compiler and standard library from step 5 - or the OS libraries in case of `bootstrapping-with-hostlibs`.
68
+
The final Swift modules are built with the level-1 compiler and standard library from step 5 - or the OS libraries in case of `bootstrapping-with-hostlibs`.
70
69
71
70
#### 7. The final compiler
72
71
73
-
Now the final `swift-frontend` can be built, linking the final _libswift_ from step 6.
72
+
Now the final `swift-frontend` can be built, linking the final Swift modules from step 6.
74
73
75
74
#### 8. The final standard library
76
75
77
76
With the final compiler from step 7, the final and full standard library is built. This library should be binary equivalent to the level-1 library.
78
77
79
78
Again, unless the build mode is `bootstrapping-with-hostlibs`, for building the standard library, the build system redirects the compiler's dynamic library path to the level-1 library.
80
79
81
-
### Using and not using _libswift_
82
-
83
-
To include _libswift_ in a tool, `initializeLibSwift()` must be called at the start of the tool. This must be done before any SIL objects are created. So ideally, at the start of the tool, e.g. at the place where `INITIALIZE_LLVM()` is called.
84
-
85
-
Currently the `swift-frontend` and `sil-opt` tools use _libswift_.
80
+
## Using Swift in the compiler
86
81
87
-
Tools, which don't use any optimization passes from _libswift_ don't need to link _libswift_. For example, all tools, which compile Swift source code, but don't optimize it, like SourceKit or lldb, don't need to link _libswift_. As long as `initializeLibSwift()` is not called there is no dependency on _libswift_.
88
-
89
-
This also means that currently it is not possible to implement mandatory passes in _libswift_, because this would break tools which compile Swift code but don't use _libswift_. When we want to implement mandatory passes in _libswift_ in the future, we'll need to link _libswift_ to all those tools.
82
+
To include Swift modules in a tool, `initializeSwiftModules()` must be called at the start of the tool. This must be done before any Swift code is called. ideally, it's done at the start of the tool, e.g. at the place where `INITIALIZE_LLVM()` is called.
90
83
91
84
## SIL
92
85
93
-
The design of SIL in _libswift_ matches very closely the design on the C++ side. For example, there are functions, basic blocks, instructions, SIL values, etc.
86
+
The design of the Swift SIL matches very closely the design on the C++ side. For example, there are functions, basic blocks, instructions, SIL values, etc.
94
87
95
88
Though, there are some small deviations from the C++ SIL design. Either due to the nature of the Swift language (e.g. the SIL `Value` is a protocol, not a class), or improvements, which could be done in C++ as well.
96
89
97
90
Bridging SIL between C++ and Swift is toll-free, i.e. does not involve any "conversion" between C++ and Swift SIL.
98
91
99
92
### The bridging layer
100
93
101
-
The bridging layer is a small interface layer which enables calling into the SIL C++ API from the Swift side. Currently the bridging layer is implemented in C using C interop. In future it can be replaced by a C++ implementation by using C++ interop, which will further simplify the bridging layer or make it completely obsolete. But this is an implementation detail and does not affect the API of SIL in _libswift_.
94
+
The bridging layer is a small interface layer which enables calling into the SIL C++ API from the Swift side. Currently the bridging layer is implemented in C using C interop. In future it can be replaced by a C++ implementation by using C++ interop, which will further simplify the bridging layer or make it completely obsolete. But this is an implementation detail and does not affect the API of Swift SIL.
102
95
103
96
The bridging layer consists of the C header file `SILBridging.h` and its implementation file `SILBridging.cpp`. The header file contains all the bridging functions and some C data structures like `BridgedStringRef` (once we use C++ interop, those C data structures are not required anymore and can be removed).
104
97
105
98
### SIL C++ objects in Swift
106
99
107
-
The core SIL C++ classes have corresponding classes in _libswift_, for example `Function`, `BasicBlock` or all the instruction classes.
100
+
The core SIL C++ classes have corresponding classes in Swift, for example `Function`, `BasicBlock` or all the instruction classes.
108
101
109
-
This makes _libswift_ easy to use and it allows to program in a "Swifty" style. For example one can write
102
+
This makes the SIL API easy to use and it allows to program in a "Swifty" style. For example one can write
110
103
111
104
```swift
112
105
for inst in block.instructions {
@@ -126,7 +119,7 @@ The Swift classes don't define any stored properties, because those would overla
126
119
127
120
### Lazy implementation
128
121
129
-
In the current state the SIL functionality and API is not completely implemented, yet. For example, not all instruction classes have a corresponding class in _libswift_. Whenever a new _libswift_ optimization needs a specific SIL feature, like an instruction, a Builder-function or an accessor to a data field, it's easy to add the missing parts.
122
+
In the current state the SIL functionality and API is not completely implemented, yet. For example, not all instruction classes have a corresponding class in Swift. Whenever a new Swift optimization needs a specific SIL feature, like an instruction, a Builder-function or an accessor to a data field, it's easy to add the missing parts.
130
123
131
124
For example, to add a new instruction class:
132
125
@@ -136,44 +129,46 @@ For example, to add a new instruction class:
136
129
* if needed, add bridging functions to access the instruction's data fields.
137
130
138
131
139
-
No yet implemented instruction classes are mapped to a "placeholder" instruction, e.g `UnimplementedInstruction`. This ensures that optimizations can process any kind of SIL, even if some instructions don't have a representation in _libswift_ yet.
132
+
No yet implemented instruction classes are mapped to a "placeholder" instruction, e.g `UnimplementedInstruction`. This ensures that optimizations can process any kind of SIL, even if some instructions don't have a representation in Swift yet.
140
133
141
134
## The Optimizer
142
135
143
136
Similar to SIL, the optimizer also uses a small bridging layer (`OptimizerBridging.h`).
144
-
Passes are registered in `registerSwiftPasses()`, called from `initializeLibSwift()`.
145
-
The C++ PassManager can then call a _libwift_ pass like any other `SILFunctionTransform` pass.
137
+
Passes are registered in `registerSwiftPasses()`, called from `initializeSwiftModules()`.
138
+
The C++ PassManager can then call a Swift pass like any other `SILFunctionTransform` pass.
146
139
147
140
To add a new function pass:
148
141
149
142
* add a `SWIFT_FUNCTION_PASS` entry in `Passes.def`
150
-
* create a new Swift file in `libswift/Sources/Optimizer/FunctionPasses`
143
+
* create a new Swift file in `SwiftCompilerSources/Optimizer/FunctionPasses`
151
144
* add a `FunctionPass` global
152
145
* register the pass in `registerSwiftPasses()`
153
146
154
-
All SIL modifications, which a pass can do, are going through the `FunctionPassContext` - the second parameter of its run-function. In other words, the context is the central place to make modifications. This enables automatic change notifications to the pass manager. Also, it makes it easier to build a concurrent pass manager in future.
147
+
All SIL modifications, which a pass can do, are going through the `PassContext` - the second parameter of the pass run-function. In other words, the context is the central place to make modifications. This enables automatic change notifications to the pass manager. Also, it makes it easier to build a concurrent pass manager in future.
148
+
149
+
Currently it is not possible to implement mandatory Swift passes, because this would break tools which compile Swift code but don't link the Swift modules, like the bootstrapping level-0 compiler.
155
150
156
151
### Instruction Passes
157
152
158
-
In addition to function passes, _libswift_ provides the infrastructure for instruction passes. Instruction passes are invoked from SILCombine (in the C++ SILOptimizer) and correspond to a visit-function in SILCombine.
153
+
In addition to function passes, it's possible to define Instruction passes. Instruction passes are invoked from `SILCombine` (in the C++ SILOptimizer) and correspond to a visit-function in `SILCombine`.
159
154
160
155
With instruction passes it's possible to implement small peephole optimizations for certain instruction classes.
161
156
162
157
To add a new instruction pass:
163
158
164
159
* add a `SWIFT_INSTRUCTION_PASS` entry in `Passes.def`
165
-
* create a new Swift file in `libswift/Sources/Optimizer/InstructionPasses`
160
+
* create a new Swift file in `SwiftCompilerSources/Optimizer/InstructionPasses`
166
161
* add an `InstructionPass` global
167
162
* register the pass in `registerSwiftPasses()`
168
163
* if this passes replaces an existing `SILCombiner` visit function, remove the old visit function
169
164
170
165
## Performance
171
166
172
-
The performance of _libswift_ is very important, because compile time is critical.
167
+
Performance is very important, because compile time is critical.
173
168
Some performance considerations:
174
169
175
170
* Memory is managed on the C++ side. On the Swift side, SIL objects are treated as "immortal" objects, which avoids (most of) ARC overhead. ARC runtime functions are still being called, but no atomic reference counting operations are done. In future we could add a compiler feature to mark classes as immortal to avoid the runtime calls at all.
176
171
177
-
* Minimizing memory allocations: _libswift_ provides data structures which are malloc-free. For example `StackList` can be used in optimizations to implement work lists without any memory allocations. (Not yet done: `BasicBlockSet`, `BasicBlockData`)
172
+
* Minimizing memory allocations by using data structures which are malloc-free. For example `StackList` can be used in optimizations to implement work lists without any memory allocations. (Not yet done: `BasicBlockSet`, `BasicBlockData`)
178
173
179
-
But most importantly, if there are performance issues with the current compiler, the design of _libswift_ should make it possible to fix performance deficiencies with future compiler improvements.
174
+
* The Swift modules are compiled with `-cross-module-optimization`. This enables the compiler to optimize the Swift code across module boundaries.
0 commit comments