From d32f97238c903765dec4e9a9f3cbfa5fd12cded6 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 10 Aug 2026 11:11:18 -0700 Subject: Chapter 25: Modules, Separate Compilation, and SSA Construction Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: fuhsnn <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: Symious <14933944+symious@users.noreply.github.com> Co-authored-by: Jun Kawasaki Co-authored-by: Claude Opus 5 --- docs/chapter25/README.ja.md | 123 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 docs/chapter25/README.ja.md (limited to 'docs/chapter25/README.ja.md') diff --git a/docs/chapter25/README.ja.md b/docs/chapter25/README.ja.md new file mode 100644 index 00000000..427fc1c7 --- /dev/null +++ b/docs/chapter25/README.ja.md @@ -0,0 +1,123 @@ +# 第25章: モジュール、分割コンパイル、SSA 構築 + +[English](README.md) | 日本語 + +この文書は [原文](README.md) の日本語訳です。 + +[前の章: 第24章](../chapter24/README.ja.md) | +[章の一覧](../../README.ja.md#各章) + +この章では Simple のソースファイルを再利用可能なオブジェクトファイルへコンパイルし、その型と理想 IR を後のコンパイルに読み込み、別に構築したシステムライブラリとネイティブプログラムをリンクします。また、不完全な情報を扱うため、パーサー、型、メモリ SSA を大幅に再設計します。 + +これらが現在のスナップショットの内容です。独立した正しさの修正を先に以前の章へ移します。大きな SSA 再設計を以前へ移すことや、この章の分割は延期します。[バックポート待ち一覧](../chapter-backports.md) を参照してください。 + +第21〜24章のメモリ処理はここにも引き継ぎます。Load 検索は読み取りをループ外へ移す前にマージの全枝を証明し、Phi の因数分解はメモリ破壊を確認し、スケジューリングはメモリ集合体を通じてエイリアスをたどります。検索は `EscapeNode` から非公開または公開メモリへ進み、未解決の Store エイリアスを待ちます。配列長の読み取りには要素の境界検査がなく、配列要素の読み取りは制御を保持します。整数値の Phi は、既存の型付き変換機構で、ループの拡大を通じてもロード幅を保持します。New は引き続き非公開のコンストラクタメモリを生成し、公開は Escape が扱います。以前の章の割り当て入力設計は、これを置き換えません。 + +[直線的な履歴](https://github.com/SeaOfNodes/Simple/tree/linear) で [この章](https://github.com/SeaOfNodes/Simple/tree/linear-chapter25) を読み、[第24章と比較](https://github.com/SeaOfNodes/Simple/compare/linear-chapter24...linear-chapter25) することもできます。 + +この章の[完全な言語文法](25-grammar.ja.md)はこちらです。 + +## コンパイル単位と名前 + +`CompUnit` はソースまたはオブジェクトファイルを表します。`ParseAll` は依存関係を発見し、必要なソースを解析し、以前コンパイルした単位を読み込みます。ソースツリーとビルドツリーは対応する相対パスを使い、クラス名はドット区切りのパスを使います。たとえば `a/b/foo.smp` は名前空間 `a.b.foo` を供給します。 + +各単位は Start/Stop ノードを持ちます。関数がコンパイル単位に所有されることと、未知の外部呼び出し側を表す辺とは別です。出力のためにコードを保持することが、任意の呼び出し側から到達できることを意味してはいけません。 + +ドライバは、プロジェクトルートの `--root`、出力の `-o`、外部 Simple オブジェクト検索パスの `-L` を受け付けます。検索パスにはオブジェクトファイルやディレクトリを指定できます。コンパイラはネイティブリンク用の外部 C シンボルも解決します。`_` で始まる名前は非公開性を制御し、公開到達性は外側の名前にも依存します。 + +明示的な数値型の C 宣言は、可変のネイティブ記憶領域へ直接束縛します。 + +```java +i32 counter = "C"; +counter += 1; +return counter; +``` + +ネイティブリンカが `counter` を解決します。読み書きはその C 変数にアクセスし、宣言はコピーも初期化もしません。繰り返した宣言とモジュールインポートは同じ記憶領域エイリアスを共有します。整数と浮動小数点データの束縛をサポートし、ポインタと集合体のデータ束縛はまだサポートしません。外部フィールドは記憶領域フラグを持ち、宣言元クラス内でバイトを占めません。配置はフィールドオフセットを `ExternOffset` シンボルへ解決し、命令選択はクラス先頭+オフセットをネイティブシンボルアドレスへ置き換えます。ネイティブオブジェクト出力は既存の AMD64 ELF ライタを使い、ARM と RISC-V はメモリ内リンカを通じてこれらのアドレスをサポートします。スレッドローカル変数と C マクロにはアクセサ関数が必要です。システムライブラリは小さなネイティブランタイムアクセサを通じ、`libc.errno()` を公開します。 + +## オブジェクトファイルは理想 IR を含む + +ELF ライタは、ネイティブコードと、正規化された型、理想グラフノード、依存関係を含む `.simple` セクションを保存します。リーダはそのグラフを再構築し、インポートした関数をインライン化などの最適化に参加させます。インライン化せず残った呼び出しは、ネイティブリンクで解決します。 + +`GlobalBits` はファイルの同一性とファイルごとのインデックスを、エイリアス、関数対象、戻り位置の局所的な密なインデックスへ対応付けます。独立したコンパイルの等しい局所番号を、等しい同一性と取り違えてはいけません。読み込み後に型を閉じて更新し、単位をまたぐ循環参照も扱います。 + +シリアライズは、宣言型を精密化されたフロー型とは別に保持します。意味を持つすべてのノード/型のフィールドには、対応する読み書きサポートが必要です。ソースにある高コストなシリアライズの全単射検査は現在無効で、より大きな増分再ビルドテスト `testModule0` は無視されています。どちらも有効な検証保証ではありません。 + +外部フィールドのフラグと記号的オフセットは、シリアライズされた配置を変更します。マジックは `C0DE` のままで、独立した形式バージョンはまだありません。このコンパイラへインポートする前に、すべての Simple オブジェクトファイルを再ビルドしてください。 + +## 型が完成する前の SSA 構築 + +Simple は引き続き AST を介さず直接 SSA に解析します。前方参照により、解析時点では式の最終的な型が利用できない場合があります。そのため構文と解決済みの字句的束縛でトポロジーを選び、後から型でグラフを精密化、最適化、検証します。 + +- 算術ノードは整数モードか浮動小数点モードかの選択を延期し、SCCP 後の再帰的グラフ成分を通じた解決も扱います。 +- Call は呼び出し先の種類が決まる前に、構文上のレシーバスロットを保持します。記号的なフィールド情報は配置依存の判断を延期します。 +- Load と通常の Phi は、パーサーが供給した下限型を持たなくなります。 +- `TypeScalar` は整数、浮動小数点、メモリポインタ、関数ポインタ値を、大域的な制御/メモリのボトムと区別して表します。 +- `TypeStruct._open` は不完全なフィールド集合を記述し、`_fref` は権威ある定義の欠如を記録します。フィールドを発見したことは、型を定義したことではありません。 +- ガードは入力の種類がわかる前に、分岐が証明したゼロ/非ゼロの事実を運びます。`FunPtrNode` は関数の戻りグラフへの明示的な辺を保持します。 + +ドライバはシリアライズとマシン選択の前に、解析、悲観的反復、SCCP、最終型検査を行います。単純でないインライン化は、常に即時のピープホール最適化として行うのではなく、反復と調整します。 + +## メモリと構築 + +パーサーは通常のバルクメモリを保持します。最適化器は `MemMerge`、`MemPhi`、`BulkMemPhi` で正確なエイリアスを復元します。バルク Phi は、並列の正確な Phi で表す除外分以外のすべてのエイリアスを覆います。各スライスはちょうど1回だけ覆われなければなりません。 + +ユーザーコンストラクタは次のように宣言し、呼び出します。 + +```java +struct Box { + i64[] values; + new Box = { i64[] initial -> values = initial; }; +}; +return new Box(new i64[1]); +``` + +宣言で割り当て補助関数を生成します。これは割り当てを行い、隠れた `` とユーザーコンストラクタを順に呼び、`EscapeNode` を通じて初期化済みの非公開メモリを公開します。パーサーの `Var` メタデータは、早すぎるフィールド読み取りやコンストラクタ出口での未初期化を検出します。Store の幅は保存する値ではなく、対象の宣言から得ます。 + +ファイルレベルのコードは、インスタンス初期化とは異なるクラス初期化子(``)で表します。[遅延初期化の設計(英語)](initialization.md) は、一度だけ実行するためのチェック、モジュール間の非循環な依存関係、シリアライズの対応を提案しています。現在の実装すべてを記述する仕様ではありません。[ロードマップ](ROADMAP.ja.md) にも追加の提案があります。 + +## システムライブラリと例 + +以前の単一の `sys.smp` ライブラリは、libc 束縛、I/O、文字、スキャナ、配列、伸長可能なバッファ、ビット集合の単位に整理されました。ネイティブドライバは実際のプログラム引数をサポートします。`examples` の例には Bubble Sort、Capitalize、Dijkstra、FileIO があります。 + +`Chapter25Test` は、意図的にインライン化せず残す Hello World 呼び出しを含め、ライブラリ読み込みとネイティブリンクを検証します。そのテストは `sys.o` とリンクする前に、クライアントの外部シンボルを確認します。ほかのテストは前方コンストラクタ、呼び出し経由のフィールド更新、リテラルのエスケープ、縮小したコンパイラ失敗を検証します。独立した回帰テストは以前の章へ移す候補です。 + +## ビルドと確認 + +このディレクトリで `make lib` は Java テスト依存関係を用意し、`make tests` は章の生のスイート、独立スイート、システムテスト、ファザー回帰テストを実行します。`make release` はコンパイラ jar とネイティブライブラリ成果物を構築し、`make tags` はエディタ用タグを構築します。ネイティブツールと選択した CPU/ABI は環境と一致する必要があります。Makefile は現在、既定で x86-64/win64 を使います。 + +シリアライズ IR は `C0DE` ヘッダを使います。ポインタ型は独立した読み取り専用アクセスビットを含みます。形式にはまだバージョン番号がないため、形式を変更したらオブジェクトファイルを再ビルドしてください。現在、後方互換性は保証していません。 + +コンパイラ変更は `sys.o` のシリアライズ IR とネイティブコードの両方を無効にする場合があります。リンクしたプログラムのテスト結果を解釈する前に再ビルドしてください。ソースだけの部分集合は、この章の完全な `make tests` と同等ではありません。 + +## RegAlloc の改良: 生存区間の面積と分割コスト + +第24章はループ Phi の高頻度辺を分割する前に、低頻度のコピーを試しました。この章ではさらに、スピルがスケジュール済みコードのどれだけをレジスタ圧力から解放するかを推定し、新しいコピーの推定コストで割ります。callee-save 区間は関数全体を覆います。複製可能な定数は使用の近くで再構築できます。ループ内のコピーは高コストなので、`8^loopDepth` で重み付けします。特に多数の使用を持つ値については、低コストな近似です。 + +複数の固定レジスタ使用を直接分割する規則や、一部の複数定義区間をより深く分割する規則など、第25章のほかの衝突処理はここに残します。サイズのしきい値はヒューリスティックであり、最初の割り当て器へバックポートすべき一般的不変条件ではありません。共有される合法性修正は、引き続き最も早い該当章から始めます。最終監査は第20〜25章の固定隣接ノードの色バイアス、第20〜21章の狭いストアマスク、第21〜25章の ARM レジスタバンク/浮動小数点メモリエンコーディングを修正しました。 + +第21章の隣接コピー転送も引き継ぎます。次の命令だけで使うコピーは、オペランドがコピー元レジスタを受け入れ、命令の結果に結び付けられていなければ除去します。 + +以下は、必須の `cs` フィールドに明示的なコンストラクタを与えて保存済み String ソース3件を修正した後の、完全な2026-10-02再実行です。過去の212項目すべてが成功します。これはフィクスチャ調整と最近のコンパイラ修正後の新たな基準値を確立します。以前の監査との割り当て器だけの比較ではありません。[バックポート記録](../chapter-backports.md) に古い部分比較を残しています。 + +`make spill-stats` を実行してください。各行は **第25章のコンパイラ** を使います。最初の5行は以前の212のプログラム/対象項目を、この章の構文とライブラリ構成に適応して保持しています。[フィクスチャノート](../../src/test/java/com/seaofnodes/simple/spill/README.ja.md) にその調整と測定の制限を記載しています。最適化器のシードは123です。最後の行には、既存シードで記録した `Chapter25Test` の13割り当てと、ドライバのシード456での新規システムライブラリコンパイルを含みます。`sys.o` を再利用して、この大きな処理対象を測定から消してはいけません。この結果は Windows x86-64 のものです。以前の群には RISC-V/ARM SystemV と x86 SystemV も含みます。報告器は対象ごとの合計も表示します。 + +| プログラム群 | コンパイル数 | 分割/移動数 | ループ重み付き数 | +|---|---:|---:|---:| +| 第20章 | 39 | 375 | 606 | +| 第21章 | 52 | 479 | 1,172 | +| 第22章 | 24 | 103 | 103 | +| 第23章 | 30 | 129 | 353 | +| 第24章 | 67 | 696 | 1,410 | +| 第25章 | 14 | 786 | 1,815 | +| **合計** | **226** | **2,568** | **5,459** | + +`_spills` はレジスタ間移動を含む残存 SplitNode を数え、`_spillScaled` はループ重みを適用します。どちらもメモリアクセスだけを測るものではありません。古い群はレジスタ合法性確認を伴う割り当ての再実行で、ネイティブハーネスの再実行ではありません。`Chapter25Test` の23テストすべてが、ネイティブ/結果確認を含め、スピル期待値の失敗なしに成功します。継承したエミュレータテストを含む章全体には `make -j 4 tests` を使ってください。 + +### 測定についてのコメント + +以前の割り当て器監査では、一様な改善は見つかりませんでした。そのコンパイラのほかの部分を変えず、第24章の順位付けに置き換えると、221のクライアントコンパイルで5移動減りました(2,211/4,724に対し2,206/4,719)。しかしシステムライブラリを8ラウンド以内に割り当てられませんでした。したがって不完全な比較であり、有効なスイート全体の低い合計ではありません。既存の面積/コスト順位付けを保持し、ラウンド上限と正しさの確認も変えません。その監査でシステムライブラリ自体は386移動/855重み付き移動で、現在の再実行は373/828です。 + +複数使用を持つすべての複製可能定数を優先する試行は、それらのクライアントで以前の順位付けより1移動減りましたが、やはり新規ライブラリビルドに失敗し、却下されました。これが、集計統計と完全なコンパイル・実行確認の両方が重要な理由です。有利な小計だけでは変更を正当化できません。 + +その以前の監査では、過去の群の合計が第24章の1,332/2,956から、第25章の1,814/3,753へ増えました。第25章はクラス初期化子、モジュール所有権、異なる脱出解析、構文/ライブラリの調整を追加します。これらは異なるマシングラフなので、増加を割り当て器の品質だけに帰することはできません。章の表から結論を出す前に、1つのコンパイラと固定した入力集合でヒューリスティックを比較してください。 -- cgit v1.2.3