Swift コンパイラのアーキテクチャ

Swift のコンパイラの開発に手を出してみたい方向けに、コンパイラの全体構成がどうなっているのかを、大まかに説明します。コードリーディングの参考になればいいなと。

# Swift コンパイラの構成

僕はプログラムを把握するときに、エントリポイント（最初に実行される箇所、 `main` 関数）が分からないとすごく不安になります。逆に言えば、エントリポイントさえ分かれば、そこから処理を追っていけば良いのでその後の理解が非常に楽になります。なので最初は `swift` コマンドのエントリポイントから。

注意: このエントリで、 GitHub にある実際のコードにリンクを張っていますが、行番号は時と共に変わってしまうので、ファイルまでのリンクになっています。関数名などで検索してください。


## ドライバー (Driver)

`swift` コマンドですが、実体は [`tools/driver`](https://github.com/apple/swift/tree/master/tools/driver) です。
 `tools/driver/driver.cpp` に [`main`]
(https://github.com/apple/swift/blob/master/tools/driver/driver.cpp) 関数があり、ここから [`lib` ディレクトリ](https://github.com/apple/swift/tree/master/lib) で実装されている各種ライブラリを呼び出していくようになります。

ドライバにはコマンドライン引数などによって、いくつかのモードがあります。

### サブコマンドランチャー

`swift package` と呼び出されたら `swift` の実行ファイルと同ディレクトリにある `swift-package` を起動するだけのランチャーです。`swift` コマンドへの第一引数が下記の条件にすべて合致したときに実行されます。

- `-` から始まらない
- `.` を含まない (ファイル名ではない)
- `repl` ではない[^swift_run]

試しに `swift hogehoge` みたいなコマンドを実行すると `swift-hogehoge` が見つからない的なエラーが表示されるはずです。

[^swift_run]: 最近まで `run` も対象だったのですが、組み込みの `swift run` は [SE-0179](https://github.com/apple/swift-evolution/blob/master/proposals/0179-swift-run-command.md) の swiftpm の機能と被るので廃止になりました。 [SR-5332](https://bugs.swift.org/browse/SR-5332)

### バッチモード

`swiftc` コマンドです。 `swiftc` は `swift` のシンボリックリンクになっていて、 `argv[0]` が `"swiftc"` のときにバッチモードになります。ソースファイルから実行可能ファイルを作るには、コンパイルやリンクなど複数のステップを踏む必要がありますが、このモードはその一連の動作を構築し、バッチ処理する形で実行します。

```hello.swift
func hello() {
  print("Hello Swift!")
}
```

```main.swift
hello()
```

`-v` オプションをつけるとサブプロセス呼び出しが行われていることが見えます。

```shell-session:実行するサブプロセス表示しながらコンパイル
$ swiftc -v -o hello main.swift hello.swift
Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)
Target: x86_64-apple-macosx10.9
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c -primary-file main.swift hello.swift -target x86_64-apple-macosx10.9 -enable-objc-interop -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -color-diagnostics -module-name hello -o /var/folders/y0/845byh512k53x98tw3ch5j2w0000gn/T/main-4e5977.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c main.swift -primary-file hello.swift -target x86_64-apple-macosx10.9 -enable-objc-interop -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -color-diagnostics -module-name hello -o /var/folders/y0/845byh512k53x98tw3ch5j2w0000gn/T/hello-6eeba6.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld /var/folders/y0/845byh512k53x98tw3ch5j2w0000gn/T/main-4e5977.o /var/folders/y0/845byh512k53x98tw3ch5j2w0000gn/T/hello-6eeba6.o -force_load /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_macosx.a -framework CoreFoundation -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -lobjc -lSystem -arch x86_64 -L /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -rpath /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -macosx_version_min 10.9.0 -no_objc_category_merging -o hello
```

1. ソースファイル毎に `swift -frontend -c` を呼び出して `.o` ファイルを作る
2. リンカである `ld` で `.o` をリンクし、実行ファイルを作る

という感じですね。 `-frontend` は後述のフロントエンドモードです。

実行せずに、コマンドだけを表示したいなら `-driver-print-jobs` です。

```shell-session:実行するコマンド一覧(macOS)
$ swiftc -driver-print-jobs -o hello main.swift hello.swift
```

### フロントエンドモード

Swiftコンパイラの核です。`swift -frontend <action> [options...] <inputs...>` で呼び出されます。Clang における `-cc1` みたいなもので、ザックリ言えば `.swift` ファイルを読み込んで `.o` ファイルに変換するところまでを担当します。コンパイルの本体ですね。前述の通りバッチモード( `swiftc` ) でのコンパイルも、実際にはフロントエンドモードをサブプロセスとして実行しています。フロントエンドの中でもいろいろモード（アクション）があるのですが、フルで実行するのは `-c`(`-emit-object`) です。

```shell-session:emit-object
$ swift -frontend -emit-object -o test.o test.swift
```

次節では、このアクションを実行されたときの処理のフローを説明していきます。

注意：フロントエンドモードはドライバモードを通して起動されるのが通常であり、普通の Swift プログラマが直接 `-frontend` を指定して起動することは想定されていません。コマンドラインオプションも結構な頻度で変わります。

フロントエンド（またはそのサブシステム）は、コンパイルの他にも SourceKit から使用されてコード補完をしたり、シンタックスカラーリング等にも利用されます。


### 即実行モード

Swiftのソースファイルをそのまま実行するモードです。Immediateモードと呼ばれます。
その実は `swift -frontend -interpret <オプションいろいろ> <入力ファイル>`を起動しているだけです。

```shell-session:Swiftスクリプト実行
$ swift hello.swift
```

また標準入力にソースを流して実行することもできます。その場合は入力ファイル名を `-` にします。

```shell-session:標準入力実行
$ echo 'print("Hello Swift!")' | swift -
Hello Swift!
```

### REPLモード

入力ファイル名を指定せずに `swift` コマンドを実行すると REPL モードになります。 

```shell-session:REPL
$ swift
Welcome to Apple Swift version 4.0 (swiftlang-900.0.49.1 clang-900.0.29). Type :help for assistance.
  1>  
```

`lldb` コマンドが特定のディレクトリに存在する場合 `lldb` を Swift の REPL モードで実行、そうでなければ Frontend 組み込みの REPL を実行します[^integrated-repl]。

[^integrated-repl]: Swift3 まで Linux では組み込み REPL はサポートされていなかったので、 `lldb` が無い場合エラーになっていたのですが、実装されたようです。[PR-7709](https://github.com/apple/swift/pull/7709)

また標準入力にソースを流して実行することもできます。入力ファイル名を `-` も含めて一切指定せず、標準入力にソースを流すと起動します。

```shell-session:標準入力をREPL実行
$ echo 'print("Hello Swift!")' | swift
Welcome to Apple Swift version 4.0 (swiftlang-900.0.49.1 clang-900.0.29). Type :help for assistance.
Hello Swift!
```

どうして Immediate モードと別になっているのかよく分からないですが、標準入力は REPLへの入力となるので、REPLのコマンドも効きます。

```shell-session
$ echo ':help' | swift
Welcome to Apple Swift version 4.0 (swiftlang-900.0.49.1 clang-900.0.29). Type :help for assistance.

The REPL (Read-Eval-Print-Loop) acts like an interpreter.  Valid statements,
expressions, and declarations are immediately compiled and executed.
The complete set of LLDB debugging commands are also available as described
below.  Commands must be prefixed with a colon at the REPL prompt (:quit for
example.)  Typing just a colon followed by return will switch to the LLDB
prompt.
Debugger commands:
  apropos           -- List debugger commands related to a word or subject.
  breakpoint        -- Commands for operating on breakpoints (see 'help b' for
... 略
```


### その他モード

他にもいくつかあります。そういうのが有るというのだけ知っておけば。

| 起動方法 | |
|:--|:--|
| `swift-format` | Swift ソースファイルの自動整形 |
| `swift-autolink-extract` | コンパイルした `.o` からリンカ用のフラグを生成[^autolink-extract] |
| `swift -modulewrap` | `.swiftmodule` のデータをそのまま `.o` に[^modulewrap] |
| `swift -apinotes` | `.apinotes`ファイル(C API マッピングヒント) の YAML ←→ バイナリ変換 |

各モードがコマンドラインオプション指定だったり、シンボリックリンクによるコマンド名変更だったりするのはどういう基準なんでしょうね。

[^autolink-extract]: macOS版では、Mach-O のリンクでは必要ないのでインストールされません（シンボリックリンクが張られません。）
[^modulewrap]: `swiftc -g` でコンパイルしたときに使用され、バイナリに埋め込まれてデバッガが使用します。

# フロントエンド (Frontend) の構成

`lib/FrontendTool/FrontendTool.cpp` にある [`swift::performFrontend`](https://github.com/apple/swift/blob/master/lib/FrontendTool/FrontendTool.cpp) がエントリポイントになります。大きな流れは下記の通りです。

1. フロントエンドの起動設定を保持するオブジェクトである `CompilerInvocation` を コマンドラインオプションなどから生成する。
1. `CompilerInstance` を生成し、`CompilerInvocation` によってそのセットアップを行う。
1. 同 `.cpp` の `performCompile` にてコンパイル実行。ここで下図パイプラインが走ります。各コンポーネントにおいてエラーを検知した場合にはそこで処理が終了します。

<img width="688" alt="SwiftCompiler.png" src="https://qiita-image-store.s3.amazonaws.com/0/55874/842aac26-3c29-bd62-aa05-1d79e7a16804.png">

## CompilerInstance

[`include/swift/Frontend/Frontend.h`](https://github.com/apple/swift/blob/master/include/swift/Frontend/Frontend.h) で定義されています。

図には示していませんが、コンパイル全体の状態や実行を管理する、フロントエンドにおいて重要な部分です。

`CompilerInstance` は下記のような、コンパイル中の主要なシングルトンのオーナーの役割を担っています。

* `SourceManager` : ソース管理
* `DiagnosticEngine` : 診断エンジン
* `ASTContext` : ASTのメモリ管理、外部モジュールの読み込みなど
* `ModuleDecl`: コンパイル中の ASTモジュール
* `SILModule` : SILモジュール

パイプライン中の Parse および Sema に関しては、このオブジェクトの
 [`CompilerInstance::performSema`](https://github.com/apple/swift/blob/master/lib/Frontend/Frontend.cpp) メソッドを通して実行されます。入力ファイルが複数の場合は、一回の `performSema` で、全ての入力ファイルの Parse と Sema を完了させてから、次のフェーズに進みます。

## ASTContext

もう一つ重要な要素に `ASTContext` という物があります。

[`include/swift/AST/ASTContext.h`](https://github.com/apple/swift/blob/master/include/swift/AST/ASTContext.h) で定義されています。

`CompilerInstance` によってインスタンス化され、LLVM IRの生成が完了するまでずっと生き続ける、非常にライフタイムが長いオブジェクトです。 AST ノードのメモリ管理がメインの仕事なのですが、その他にも

* stdlib含め、外部モジュールの読み込みとそのオーナー
* コンパイラ既知の stdlib APIの管理

などの役割を担っており、また、フロントエンドの各サブシステムは実行中に `FrontendTool` や `CompilerInstance` のことは意識しませんが、`ASTContext` はフロントエンドのほぼ全てのサブシステムから参照されます。

また `SourceManager` や `DiagnosticEngine` の参照を持っており、各サブシステムからこれらを利用する際の窓口ともなっています。全体から見えて欲しいものはとりあえずここに参照を突っ込んどけ、的なやつです。

## サブシステム

コンパイルのパイプライン上に現れる、主要なプロセッサです。 [swift.org](https://swift.org/compiler-stdlib/) にも説明があります。

正しい用語かどうかはわかりませんが、 [ソース上では "subsystems"](https://github.com/apple/swift/blob/master/include/swift/Subsystems.h) という書かれ方をされているのでここでは「サブシステム」と呼びます。[swift.org では components]( https://swift.org/compiler-stdlib/) と表記されています。

### Parse

ソースを [AST(抽象構文木)](https://ja.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E6%A7%8B%E6%96%87%E6%9C%A8) に変換します。割とシンプルな [再帰下降構文解析器(Recursive Descent Parser)](https://ja.wikipedia.org/wiki/%E5%86%8D%E5%B8%B0%E4%B8%8B%E9%99%8D%E6%A7%8B%E6%96%87%E8%A7%A3%E6%9E%90) で、 `lib/Parse/Lexer.cpp` によって[字句解析 (Lexical Analysis)](https://ja.wikipedia.org/wiki/%E5%AD%97%E5%8F%A5%E8%A7%A3%E6%9E%90) を行いつつ、Lexer から得たトークンの並びを判断して AST を構築していきます。型情報や、意味解析には関知しません[^typerepr]。例外的に、ローカル変数の使用など、文脈上明らかな部分だけこのタイミングで[名前束縛 (Name Binding)](https://ja.wikipedia.org/wiki/%E6%9D%9F%E7%B8%9B_(%E6%83%85%E5%A0%B1%E5%B7%A5%E5%AD%A6)#.E5.90.8D.E5.89.8D.E6.9D.9F.E7.B8.9B) が行われます。また文法エラーや文法に関するワーニングを発行するのも Parse の仕事です。
エントリポイントは `lib/ParseSIL/ParseSIL.cpp` の [`swift::parseIntoSourceFile`](https://github.com/apple/swift/blob/master/lib/ParseSIL/ParseSIL.cpp) で、そこで `lib/Parse` で実装されている `Parser` がインスタンス化され、`lib/Parse/ParseDecl.cpp` の [`Parser::parseTopLevel`](https://github.com/apple/swift/blob/master/lib/Parse/ParseDecl.cpp) が呼ばれます。

[^typerepr]: 型情報に関知しないといっても、タイプ名のパースはもちろん行います。ただ、それらパースしたタイプ名が実際には何者であるかということは Parse の時点ではわかりません。

### Sema

[意味解析(Semantic Analysis)](https://en.wikipedia.org/wiki/Semantic_analysis_(compilers)) フェーズです。Parseで生成された AST を受け取って、[型チェック(Type checking)](https://en.wikipedia.org/wiki/Type_system#Type_checking)された AST に変換します。使用している変数の定義が見つからないなど、解析時に問題が発生した場合はエラーやワーニングを発行します。このフェーズが成功すると、完全な type-checked AST が生成され、そこからコードジェネレートできることが保証されます。

エントリポイントは `lib/Sema/TypeChecker.cpp` の [`swift::performTypeChecking`](https://github.com/apple/swift/blob/master/lib/Sema/TypeChecker.cpp) です。
その前段に `lib/Sema/NameBinding.cpp` の [`swift::performNameBinding`](https://github.com/apple/swift/blob/master/lib/Sema/NameBinding.cpp) が実行されます。（歴史的に）この関数名ですが、実際にやっていることは `import` 文に従って外部モジュールを読み込むだけです。

また、 expression や pattern の[型推論](https://ja.wikipedia.org/wiki/%E5%9E%8B%E6%8E%A8%E8%AB%96)器として Sema の中に[`ConstraintSystem`](https://github.com/apple/swift/blob/master/lib/Sema/ConstraintSystem.cpp) というコンポーネントがあります。各 expression の型チェック毎にインスタンス化され、型推論をします。

[docs/TypeChecker.rst](https://github.com/apple/swift/blob/master/docs/TypeChecker.rst) を一部抜粋して意訳すると:

> Swiftは伝統的な [Hindley–Milner 型システム](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system) を彷彿とさせる「制約」を基にしたタイプチェッカーを使用し、双方向の型推論を実装している。この宣言的な制約システムの採用は、実際の型解決の実装を気にせず、言語中での意味を率直に表現することを可能とする。

> Swift言語には、( Generics などの)多態型や、オーバーロードなど、いくつか Hindley–Milner 型システムには無い機能があり、実装がある程度複雑になっている。その一方、一回の型推論の範囲を一つの式(expression)または文(statement)に限定することにより、パフォーマンスを確保し、またエラー診断をより的確に行うことができる。

### SILGen

Swift 独自の[中間言語](https://en.wikipedia.org/wiki/Intermediate_representation#Intermediate_language) である SIL (Swift Intermediate Language) を生成します。 SIL はプログラムの [フロー解析](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E3%83%95%E3%83%AD%E3%83%BC%E8%A7%A3%E6%9E%90) に適した言語で、 Swift の型情報などを利用した高レベルの最適化に適しています。 このフェーズでは、タイプチェック済みの AST を raw SIL と呼ばれる SIL に変換します。ここでも診断エラーが発生することがあります。

エントリポイントは `lib/SILGen/SILGen.cpp` の [`swift::performSILGeneration`](https://github.com/apple/swift/blob/master/lib/SILGen/SILGen.cpp) です。

### SILOptimizer

このフェーズでは、SILGen で生成された raw SIL のデータフロー解析を行い、例えば未初期化の変数を使用しようとする等のプログラムエラーを検知します。結果的に canonical SIL と呼ばれる SIL を生成し、必要に応じて最適化を行います。また、このフェーズでエラー解析はすべて終了し、これ以降のフェーズではユーザーに対するエラー報告はしません。もしこれ以降に予期しない状態が発生したらコンパイラはクラッシュします。

最適化オプション (`-Onone`、`-O` など) によって処理が異なります。最適化する場合には、ARC の最適化や、インライン化、Generics の特殊化など Swift 独自の型情報などを利用した最適化がこのフェーズで行われます。

エントリポイントは [`lib/SILOptimizer/PassManager/Passes.cpp`](https://github.com/apple/swift/blob/master/lib/SILOptimizer/PassManager/Passes.cpp) で、最適化オプションにより:

* `-Onone`
  * `swift::runSILPassesForOnone` 
* `-O`, `-Ounchecked`
  * `swift::runSILOptPreparePasses` ; した後に 
  * `swift::runSILOptimizationPasses`

となります。また、IRGen の直前に [`swift::runSILLoweringPasses`](https://github.com/apple/swift/blob/master/lib/SILOptimizer/PassManager/Passes.cpp) も実行されます。

`run***Passes` という名称から分かるとおり、この中で Pass パイプラインが構成され、実行されます。

### IRGen

SwiftではバックエンドとしてLLVMを使用しているので、LLVM が処理できるように Swift の SIL を LLVM の IR に変換します。この時点で Swift の型情報は失われ、LLVMがサポートする[プリミティブな型](http://llvm.org/docs/LangRef.html#type-system)と関数のみの世界になります。

エントリポイントは `lib/IRGen/IRGen.cpp` の [`swift::performIRGeneration`](https://github.com/apple/swift/blob/master/lib/IRGen/IRGen.cpp) です。

### LLVM

[LLVM](http://llvm.org) です。 IR に必要に応じて最適化を行い、( `-target` オプションなどで)指定されたアーキテクチャ向けの `.o` オブジェクトファイルを出力します。いわゆる[バックエンド](https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9#.E3.83.90.E3.83.83.E3.82.AF.E3.82.A8.E3.83.B3.E3.83.89)です。

エントリポイントは `lib/IRGen/IRGen.cpp` の [`swift::performLLVM`](https://github.com/apple/swift/blob/master/lib/IRGen/IRGen.cpp) です。基本的にはライブラリとしての LLVM を呼び出しているだけです。

### モジュール関連

メインのパイプラインは上記の通りなのですが、その他に外部モジュール関連の登場人物がいます。 `import` で指定されたモジュールを読み込んだり、逆に他のモジュールから `import` できるようにするための機構です。

#### ClangImporter

[Clang モジュール](https://clang.llvm.org/docs/Modules.html) (C か Objective-C)を読み込んで、 Swift の API にマッピングし、Swift から使用できるようにします。AST を生成します。これによって、 Sema が C の APIを参照できるようになります。

* 関数、クラスおよびメソッド、プロトコルなどの宣言
* struct 定義
* enum の定義
* typedef の定義
* 定数マクロ

などが Swift の AST として構築されます。当然関数などは最終的には C, ObjC の ABI(呼出規約) でコールする必要があるので、その旨の情報も AST 上に保持されます。

#### SerializedModuleLoader

Swiftのモジュールファイルである `.swiftmodule`, `.swiftdoc` を読みます。このファイルにはモジュールの API 宣言が保存されており、Sema が外部モジュールの API を参照できるようにします。 ClangImporter の Swift 版。 

#### SerializedSILLoader

`.swiftmodule` には SILの情報も含まれており、これを読み込みます。標準ライブラリなど、モジュールによっては全てのSILの情報が入っており、その情報をインライン化することで高レベルな最適化が可能になったりします。

#### Serializer, SILSerializer

現在コンパイル中のプログラムを外部モジュールとして使用できるように `.swiftmodule`, `.swiftdoc` を書き出します。

#### PrintAsObjC

モジュールとは少し違いますが、Swift の API を Objective-C から使用できるようにするための仕組みです。ASTを受け取って、その中の Objective-C 互換の宣言 (`@objc`) を Objective-C のヘッダーファイル(`.h`) の形で出力します。 Xcode で Objective-C/Swift 混在のプロジェクトを扱っているときに、 Objective-C から `#import` するアレです。

## エンティティ

ここでいう「エンティティ」とは、各コンポーネント間で受け渡しされるデータの事を指します。正式な用語は知りませぬ。

### AST (抽象構文木)

[include/swift/AST](https://github.com/apple/swift/tree/master/include/swift/AST)

Parse が作って Sema が加工して、SILGen が消費します。基本的には ソースの文字列をツリー構造に変換したものです。`ModuleDecl` がルートのオブジェクトで、`ASTContext` によってメモリ管理されます。

```swift
func foo(x: Int, y: String) -> Bar {
   return Bar(a: x, b: y)
}
```

であれば Parse は（正確ではないですが）だいたいこのようなツリーを生成します。

<img width="810" alt="AST.png" src="https://qiita-image-store.s3.amazonaws.com/0/55874/320a6d9e-e335-a676-cf9e-6668b4c90ec1.png">

### SIL (Swift Intermediate Language)

[include/swift/SIL](https://github.com/apple/swift/tree/master/include/swift/SIL)

SIL は Swift が最適化やフロー診断を容易にするために使用している高レベルな中間言語です。コンパイル中は当然メモリ上のオブジェクトですが、言語なので文字列表現も可能です。 SILGen によって作られ、 SILOptimizer で加工されて、 IRGen によって消費されます。

`SILModule` がルートのオブジェクトになります。

主要な要素は関数リストです。[SSA(静的単一代入)](https://ja.wikipedia.org/wiki/%E9%9D%99%E7%9A%84%E5%8D%98%E4%B8%80%E4%BB%A3%E5%85%A5) で構成された [CFG(制御フローグラフ)](https://ja.wikipedia.org/wiki/%E5%88%B6%E5%BE%A1%E3%83%95%E3%83%AD%E3%83%BC%E3%82%B0%E3%83%A9%E3%83%95) で表現される関数のリスト、と言えばよいでしょうか。SILでは、グローバル関数も インスタンスメソッドも `init` や `subscript` も 一つの名前空間 (SILModule) にフラットな関数群として展開され、ASTの様な木構造ではなくなっています。

他にも、VTable、 グローバル変数、 Witness Table、Default Witness Table などの情報を持ちます。詳しくは [`docs/SIL.rst`](https://github.com/apple/swift/blob/master/docs/SIL.rst) を参考にしてください。

## フロントエンドアクション一覧

`swift -frontend <action>` で指定するフロントエンドのアクションの一覧です。フロントエンドモードでは必ず何らかのアクションを指定する必要があります。前述したように、フロントエンドモードはパブリックなインターフェイスではなく、追加やインターフェイスの変更が普通に発生するので、このリストは 下記の日付現在のものです。コンパイラのデバッグ用途だけに使われるものもあります。

2017/07/13 現在

| コマンドラインオプション | |
|:---|:--|
| `-parse` | Parse まで実行。メイン出力は無し。終了ステータスで成否判断 |
| `-dump-parse` | Parse まで実行し、その時点での AST をダンプ出力 |
| `-typecheck` | Sema まで実行。メイン出力は無し。終了ステータスで成否判断 |
| `-dump-ast` | Sema まで実行し、 AST をダンプ出力 |
| `-print-ast` | Sema まで実行し、 AST をSwiftソースの形で出力（いろいろ足りてないけど） |
| `-dump-interface-hash` | Sema まで実行し、APIのインターフェイスのハッシュ値を出力 |
| `-dump-scope-maps` | Sema まで実行し、変数スコープ一覧をダンプ |
| `-dump-type-refinement-contexts` | Sema まで実行し、 type refinement context ？ をダンプ |
| `-emit-tbd` | Sema まで実行し TBD を出力。どうもモジュールのパブリックなシンボルの一覧ぽい |
| `-emit-imported-modules` | Sema まで実行し `import` されるモジュールの一覧を出力 |
| `-emit-silgen` | SILGen まで実行し、raw SIL をテキスト出力 |
| `-emit-sibgen` | SILGen まで実行し、raw SIL をバイナリ出力 |
| `-emit-sil` | SILOptimizer まで実行し、canonical SIL をテキスト出力 |
| `-emit-sib` | SILOptimizer まで実行し、canonical SIL をバイナリ出力 |
| `-emit-module`[^emit-module] | SILOptimizer まで実行し、 `.swiftmodule`, `.swiftdoc` を出力 |
| `-immediate` | IRGen まで実行し、 `llvm::ExecutionEngine` 上で即実行 |
| `-emit-ir` | LLVM に IR のテキスト出力を依頼 |
| `-emit-bc` | LLVM に Bitcode の出力を依頼 |
| `-emit-assembly` | LLVM に target ネイティブなアセンブリ言語の出力を依頼 |
| `-emit-object` | LLVM にオブジェクトファイル `.o` の出力を依頼 |
| `-emit-pch` | C,Obj-C の ヘッダファイルを入力として、ブリッジング用のプリコンパイルヘッダーを出力 |
| `-repl` | フロントエンド組み込みの REPL を実行 |

[^emit-module]: `-emit-module` は他のアクションとも組み合わせられるのですが、他のアクションが指定されていない場合にはプライマリのアクションとして実行されます。

# ソース構成
| ライブラリソース | |
|:--|:---|
| `include/swift/Subsystems.h`  | サブシステムのエントリポイントを宣言しているヘッダー |
| `include/swift/ABI` | ABI関連 |
| `include/swift/AST`<br>`lib/AST` | AST |
| `include/swift/ASTSectionImporter`<br>`lib/ASTSectionImporter` | `swift -modulewrap` で実行バイナリに埋め込まれた ASTモジュール を読み込むライブラリ。 `lldb` から利用 |
| `include/swift/Basic`<br>`lib/Basic` | いろいろ基礎的なライブラリ。基礎だけにいろいろなところで使われてて重要 |
| `include/swift/ClangImporter`<br>`lib/ClangImporter` | ClangImporter |
| `include/swift/Demangling`<br>`lib/Demangling` | [Name Mangling](https://ja.wikipedia.org/wiki/%E5%90%8D%E5%89%8D%E4%BF%AE%E9%A3%BE) された文字列の Demangle |
| `include/swift/Driver`<br>`lib/Driver` | ドライバーの実装 (tools/driver から利用される) |
| `include/swift/Frontend`<br>`lib/Frontend` | フロントエンド |
| `include/swift/FrontendTool`<br>`lib/FrontendTool` | `swift -frontend` の実装 |
| `include/swift/IDE`<br>`lib/IDE` | コード補完やシンタックスハイライトなど。主に SourceKit が利用 |
| `include/swift/IRGen`<br>`lib/IRGen` | IRGen |
| `include/swift/Immediate`<br>`lib/Immediate` | 即実行モードの実装 |
| `include/swift/Index`<br>`lib/Index` | インデックサー。 SourceKit が利用 |
| `include/swift/LLVMPasses`<br>`lib/LLVMPasses` | Swift 独自の LLVM Pass |
| `include/swift/Markup`<br>`lib/Markup` | Markdown 関連 DocComment の処理など |
| `include/swift/Migrator`<br>`lib/Migrator` | Swift3 → Swift4 マイグレーター実装 |
| `include/swift/Option`<br>`lib/Option` | コマンドラインオプション定義 |
| `include/swift/Parse`<br>`lib/Parse` | Parse |
| `lib/ParseSIL` | SILパーサー |
| `include/swift/PrintAsObjC`<br>`lib/PrintAsObjC` | PrintAsObjC |
| `include/swift/Reflection`<br>`stdlib/public/Reflection` |  |
| `include/swift/Remote` | |
| `include/swift/RemoteAST`<br>`lib/RemoteAST` | 実行中のプログラムから ASTを復元する。lldbが使用 |
| `include/swift/SIL`<br>`lib/SIL` | SIL |
| `lib/SILGen` | SILGen |
| `include/swift/SILOptimizer`<br>`lib/SILOptimizer` | SILOptimizer |
| `include/swift/Sema`<br>`lib/Sema` | Sema |
| `include/swift/Serialization`<br>`lib/Serialization` | ModulerLoader, SILModuleLoader,  |
| `include/swift/SwiftDemangle`<br>`lib/SwiftDemangle` | 外部プログラム用 Demangle インターフェイス |
| `include/swift/SwiftRemoteMirror`<br/>`stdlib/public/SwiftRemoteMirror` | `Reflection` の C ラッパー |
| `include/swift/Syntax`<br>`lib/Syntax` | 空白なども保持する構文木モデル。 Refactoringツールなどが使用してるっぽい |
| `include/swift/TBDGen`<br>`lib/TBDGen` | `-emit-tbd` 実装 |

各ライブラリの依存関係を説明しようと思ったのですが、[循環依存ありありで大変な状況](https://twitter.com/rintaro/status/887122701227139072)なので（略


# おわりに

Swift コンパイラの各サブシステム概要でした。各々の詳しい処理については触れませんでしたが、すべてのサブシステムの内容を完全に理解している必要はありません。むしろ全てを把握している人なんていない、はず。興味ある分野のコードからぜひ覗いてみてください。

レッツ エンジョイ コードリーディング！