わいわいswiftc #2(39分くらい〜)を見ながらメモ

IRGenについての話
参考: https://qiita.com/rintaro/items/3ad640e3938207218c20#irgen
SwiftではバックエンドとしてLLVMを使用しているので、LLVM が処理できるように Swift の SIL を LLVM の IR に変換します。この時点で Swift の型情報は失われ、LLVMがサポートするプリミティブな型と関数のみの世界になります。
エントリポイントは lib/IRGen/IRGen.cpp の swift::performIRGeneration です。

IRGenはこのあたり

IRGenのエントリーポイントは performIRGeneration
がわかりやすいそう。
コンパイラオプションでパラレルモードがついてると並列実行に入るパスがある。

その performIRGeneration
が FrontendToolの generateIR
から呼ばれる。
フロントエンド=swiftcコマンドなどコマンドとしてのトップレベルの振る舞いが記述されている場所。
その generateIR
は performCompileStepsPostSILGen
の後に呼ばれる。
generateIR
が SIL → LLVM IR にする部分の根っこ。
performCompileStepsPostSILGen
で generateIR
の後にあるのが generateCode
でこれが上で作ったLLVM IRをLLVMにかけてx86やarmのバイナリにするところ。

ここから performIRGeneration
のシングルの冒頭から処理を追っていく
今はシングル部分は以下のようなコードになっているっぽい(中にJITの分岐もあるしあってそう)
IRGeneratorとIGM(IR Gen Module)の2つが重要。
IRGeneratorがコンパイラの実行に対して1つだけある神クラス。
IGMが並列実行できる分割単位みたいな感じ。IRGeneratorとIGMは1:n。
コンパイル時に1つに集約するものを管理しつつ、主役のモジュールと分割実行するモジュールに整理。
ソースファイルに吐いたり、リンクするライブラリを収集して追加したりの処理がある。

LLVMはJITに対応している。
(Swift REPLもSwiftのソースコードを対話IFの中のプロセスで入力して、それがコンパイルされて関数として登録されてSwiftのバイナリがちょっとずつツギハギで入っていく)
コンパイラがJITモードの時は出力が少ない、実行時に必要になったらそれが生成される感じになっている。
bitcodeの埋め込みはこのあたり

IRGeneratorとIGMは1:nで、そのnの方がIRGenModuleだがヘッダだけで1300行(今は1900行..)
そのヘッダに対応する実装はIRGen配下にGen*.cppという形で分割されている。

emitSourceFileはここに定義されている。
emitSourceFileはDeclを取り出してemitGlobalDeclを呼び出す
emitGlobalDeclではemitStructDeclなどを呼び出す。
多分この中でstructに対応するメモリレイアウトをLLVM IRのstructとして吐く

LLVM自体のAPIがわからないとイマイチ分からないらしい。
チュートリアルがオススメらしい。
このチュートリアルをSwiftで書いているリポジトリ
LLVMをSwiftで書くリポジトリ
IRとは?→IRはLLVM IRというLLVMプロジェクトが勝手に作った仮想のCPU言語

1bitを明示的に指定する書き方(bit-field)の話
unsigned int dataSourceNumberOfRowsInSection : 1;
Delegateのメソッドをキャッシュする仕組みがあるらしい(知らなかった)
RxSwiftにもdelegateをセットし直す処理が入ってるらしい。

次はここから
これが UIWindow??
になるのは何故?
let w = UIApplication.shared.delegate?.window
UIApplicationDelegate側でこのように定義されているから
@MainActor public protocol UIApplicationDelegate : NSObjectProtocol {
...
optional var window: UIWindow? { get set }
...
こんな書き方できるのか(知らなかった)
import Foundation
@objc protocol AP {
@objc optional func a() -> Int
}
class Cat: AP {}
// a: Int?
let a = (Cat() as AP).a?()

Q: swiftcはXcodeのものと同じ?
A: swiftcは同じだがFoundationが違う、なのでLinuxだと動かないが出てくる。swiftcはmac, linux両対応で作られている。
Q: LLVM IRを理解しないとswiftcは使えない?
A: 使うという意味では使える。swiftcの内部(IR)に興味を持った場合はIRを知らないといけない。最適化も何段階かある。ブラックボックスだとしてParserだけみても面白いとのこと。

無限にメモリ食ってコンパイルが終わらないコードの話
SourceKitも暴走するのでXcodeにはコードを貼るだけで止まらなくらしい。

一旦ここまで