Closed15

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

tanakotanako

https://www.youtube.com/live/BZmZbBwDuNo?feature=shared&t=2345

IRGenについての話

参考: https://qiita.com/rintaro/items/3ad640e3938207218c20#irgen

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

tanakotanako

その performIRGeneration が FrontendToolの generateIR から呼ばれる。
フロントエンド=swiftcコマンドなどコマンドとしてのトップレベルの振る舞いが記述されている場所。

https://github.com/apple/swift/blob/5f8466445afa18b3ac6d75bf96ed28663fb2e048/lib/FrontendTool/FrontendTool.cpp#L1508-L1525

その generateIRperformCompileStepsPostSILGen の後に呼ばれる。
generateIR が SIL → LLVM IR にする部分の根っこ。
https://github.com/apple/swift/blob/5f8466445afa18b3ac6d75bf96ed28663fb2e048/lib/FrontendTool/FrontendTool.cpp#L1691

performCompileStepsPostSILGengenerateIR の後にあるのが generateCode でこれが上で作ったLLVM IRをLLVMにかけてx86やarmのバイナリにするところ。
https://github.com/apple/swift/blob/5f8466445afa18b3ac6d75bf96ed28663fb2e048/lib/FrontendTool/FrontendTool.cpp#L1875

tanakotanako

https://www.youtube.com/live/BZmZbBwDuNo?feature=shared&t=2531

ここから performIRGeneration のシングルの冒頭から処理を追っていく
今はシングル部分は以下のようなコードになっているっぽい(中にJITの分岐もあるしあってそう)
https://github.com/apple/swift/blob/main/lib/IRGen/IRGen.cpp#L1108

IRGeneratorとIGM(IR Gen Module)の2つが重要。
IRGeneratorがコンパイラの実行に対して1つだけある神クラス。
IGMが並列実行できる分割単位みたいな感じ。IRGeneratorとIGMは1:n。
コンパイル時に1つに集約するものを管理しつつ、主役のモジュールと分割実行するモジュールに整理。
ソースファイルに吐いたり、リンクするライブラリを収集して追加したりの処理がある。

tanakotanako

LLVMはJITに対応している。
(Swift REPLもSwiftのソースコードを対話IFの中のプロセスで入力して、それがコンパイルされて関数として登録されてSwiftのバイナリがちょっとずつツギハギで入っていく)

コンパイラがJITモードの時は出力が少ない、実行時に必要になったらそれが生成される感じになっている。
https://github.com/apple/swift/blob/main/lib/IRGen/IRGen.cpp#L1175C21-L1175C21

bitcodeの埋め込みはこのあたり
https://github.com/apple/swift/blob/main/lib/IRGen/IRGen.cpp#L1230

tanakotanako

https://www.youtube.com/live/BZmZbBwDuNo?feature=shared&t=2875

emitSourceFileはここに定義されている。
https://github.com/apple/swift/blob/main/lib/IRGen/GenDecl.cpp

emitSourceFileはDeclを取り出してemitGlobalDeclを呼び出す
https://github.com/apple/swift/blob/main/lib/IRGen/GenDecl.cpp#L2560

emitGlobalDeclではemitStructDeclなどを呼び出す。
多分この中でstructに対応するメモリレイアウトをLLVM IRのstructとして吐く
https://github.com/apple/swift/blob/main/lib/IRGen/GenDecl.cpp#L2616

tanakotanako

次はここから
https://www.youtube.com/live/BZmZbBwDuNo?feature=shared&t=4012

これが 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?()
tanakotanako

Q: swiftcはXcodeのものと同じ?
A: swiftcは同じだがFoundationが違う、なのでLinuxだと動かないが出てくる。swiftcはmac, linux両対応で作られている。

Q: LLVM IRを理解しないとswiftcは使えない?
A: 使うという意味では使える。swiftcの内部(IR)に興味を持った場合はIRを知らないといけない。最適化も何段階かある。ブラックボックスだとしてParserだけみても面白いとのこと。

このスクラップは2023/10/05にクローズされました