Files
hakorune/docs/development/roadmap/phases/phase-25.1/README.md
nyash-codex 8750186e55 chore: Phase 26-H セッション完了 - 全ドキュメント更新
Phase 26-H 完了内容:
 JoinIR 型定義実装(src/mir/join_ir.rs)
 MIR → JoinIR 自動変換実装(lower_min_loop_to_joinir)
 自動変換テスト実装(mir_joinir_min_auto_lowering)
 PHI/Loop箱 → JoinIR 移行対応表追加(loopform_ssot.md)

ドキュメント更新:
- Phase 27 JoinIR タスク計画追加
- Phase 26-H タスク完了記録
- 各種 README 更新(進捗反映)
- CURRENT_TASK.md 更新

コミット統計: $(git status --short | wc -l) files changed

次のステップ: Phase 27 一般化 MIR → JoinIR 変換
2025-11-23 05:53:27 +09:00

260 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 25.1 — Stage0/Stage1 Bootstrap & Binary Layout
Status: design+partial implementationStage1 ビルド導線の初期版まで)
## 25.1 サブフェーズの整理a〜e 概要)
- **25.1a — Stage1 Build Hotfix配線**
- ねらい: `.hako → Program(JSON v0) → MIR(JSON)` の Rust/provider 経路をまず安定させる。
- 担当: `compiler_stageb.hako` `tools/hakorune_emit_mir.sh` 系の導線修復StageB emit を「実際に動く状態」に戻す)。
- **25.1b — Selfhost MirBuilder Parityselfhost-first 設計)**
- ねらい: Rust の `env.mirbuilder.emit` を「オラクル」として、Hakorune 側 `MirBuilderBox` を同じ意味論まで引き上げる。
- 担当: `.hako → Program(JSON v0) → MIR(JSON)` のうち「Program→MIR」を selfhost builder だけでも成立させる準備。
- **25.1c — Env/Extern/StageB 構造整理**
- ねらい: `env.*` / `hostbridge.*` / `env.box_introspect.*` の責務と StageB Main を箱単位で整理し、入口を一つに揃える。
- 担当: StageB を `StageBArgsBox` / `StageBBodyExtractorBox` / `StageBDriverBox` / `Stage1UsingResolverBox` に分解しつつ、挙動は変えない構造リファクタ。
- **25.1d — Rust MIR SSA/PHI Smokes**
- ねらい: Rust 側 `MirBuilder + LoopBuilder + IfForm` の SSA/PHI バグを、小さな Rust テストHako→AST→MirCompiler→MirVerifierで炙り出して潰す。
- 担当: StageB/Stage1/selfhost で見えている Undefined Value / nondominating use を、まず Rust 階層だけで止血する。
- **25.1e — LoopForm PHI v2 MigrationRust**
- ねらい: ループの PHI 生成の「SSOT」を LoopForm v2 + `phi_core` に寄せ、Legacy LoopBuilder 経路との二重管理を解消する。
- 担当: 当初は `NYASH_LOOPFORM_PHI_V2=1` を使って Stage1 / StageB 代表ループ(`_find_from` や stageb_minを通し、`phi pred mismatch` / ValueId 二重定義を構造的に解消する計画だったが、現在は LoopForm v2 が既定実装となっており、フラグは不要(互換目的のみ)。
ざっくりとした進行順は「25.1a/c で配線と箱分割 → 25.1d/e で Rust MIR/LoopForm を根治 → その結果を踏まえて 25.1bselfhost MirBuilder/LoopSSA側に寄せていく」というイメージだよ。
## Legacy Loop/PHI 経路と削除方針Phase 25.1 時点の整理)
### 正系統SSOTとして見るべき箱
- ループまわりの SSOT:
- `src/mir/loop_builder.rs` … LoopForm v2 の構造的 loweringheader/body/latch/continue_merge/exit
- `src/mir/phi_core/header_phi_builder.rs` … header PHIPinned/Carrierの宣言と seal 用メタデータ。
- `src/mir/phi_core/loop_snapshot_manager.rs` … continue/exit スナップショット管理と LoopSnapshotMerge への導線。
- `src/mir/phi_core/loop_snapshot_merge.rs` … preheader + continue_merge + latch + exit の snapshot を LoopForm 単位でマージする箱。
- if/merge まわりの SSOT:
- `src/mir/builder/if_form.rs` … IfForm を用いた構造化 if lowering。
- `src/mir/phi_core/if_phi.rs` … if merge ブロックでの PHI 生成ControlForm ベースのラッパを含む)。
- 今後: `BodyLocalPhiBuilder` を if-merge 側にも拡張して、BodyLocal 変数の PHI 判定を exit だけでなく body 内 if にも適用する予定Phase 25.x/26.x で対応)。
### Legacy 経路(新規利用禁止・将来削除予定)
- `src/mir/phi_core/loop_phi.rs`
- 冒頭コメントどおり、LoopForm v2 + LoopSnapshotMergeBox への移行後は「legacy scaffold」としてのみ残存している。
- 現在の役割:
- 一部の dev/分析用ドキュメントや smokes から参照される互換レイヤ。
- 旧 LoopBuilder 互換 API`prepare_loop_variables_with`, `seal_incomplete_phis_with`, `build_exit_phis_with` など)の受け皿。
- Phase 25.1 のポリシー:
- **新しいコードから `phi_core::loop_phi` を直接呼ばない**LoopForm v2 系の箱のみを使う)。
- Legacy テストsmoke のためにしばらく残すが、本線の PHI/SSA 設計の説明は LoopForm v2 系のファイルに寄せる。
- 削除条件Phase 31.x 以降で実施予定):
- すべての本線経路が `loopform_builder.rs` + `header_phi_builder.rs` + `loop_snapshot_merge.rs` に移行済みであること。
- `loop_phi.rs` を参照するのが「docsanalysislegacy-smoke」のみになっていること。
- `docs/private/roadmap/phases/phase-31.2/legacy-loop-deletion-plan.md` に記載の条件(参照 0対応テスト移行が満たされた時点で削除。
### HashMap 利用の線引き(決定性の観点)
- Phase 25.1 以降、**PHILoopFormIfForm の決定性に関わるマップ**は次のルールに従う:
- 変数スナップショットや PHI 入力候補のように「順序が意味を持つ」構造:
- `BTreeMap` / `BTreeSet` / `Vec + sort_by_key` のいずれかを使用して、イテレーション順を決定的にする。
- 例:
- `MirBuilder::variable_map` / `value_types` / `value_origin_newbox``BTreeMap` 化済み。
- `phi_core::if_phi::compute_modified_names``BTreeSet` で変数名を収集したうえで決定的順序でマージ。
- メタ情報やインデックス(型とは無関係なキャッシュ・診断用データ構造など):
- HashMap 維持可とし、「決定性には影響しない」ことをコメントで明記する。
- 例:
- `MirBuilder::weak_fields_by_box`, `property_getters_by_box`, `plugin_method_sigs` など。
- 例外: `phi_core::loop_phi::sanitize_phi_inputs`
- 現在も内部で一度 `HashMap<BasicBlockId, ValueId>` に詰め替えた後 `Vec` に戻して `sort_by_key` しているため、出力順自体は決定的になっている。
- ただし、このユーティリティは **legacy 経路専用** と位置付けており、新しい LoopForm v2 系のコードでは `PhiInputCollector`BTree ベース)側を SSOT として扱う。
## ゴール
- Rust 製 `hakorune` を **Stage0 ブートストラップ**と位置付け、Hakorune コード(.hakoで構成された **Stage1 バイナリ**を明確に分離する。
- Rust 側の責務を「プロセス起動+最小 FFIVM/LLVM コア」に縮退し、それ以外の機能パーサ高レイヤ、StageB、MirBuilder、AotPrep、numeric core 等)は Stage1 に寄せる。
- 将来的に「Stage1 hakoruneHakorune 実装の EXE」を日常利用の標準とし、Rust Stage0 は非常用ランチャ/ブートシードとして保持する。
## レイヤ構成Stage0 / Stage1 / Runtime
### Stage0 — Rust Bootstrap Binary
**想定バイナリ:**
- 将来: `target/release/hakorune-bootstrap`
- 現在: `target/release/nyash`Rust 製 CLI。Stage0 ブートストラップとして扱う)
**責務:**
- OS エントリポイント(`main()`)とプロセス起動。
- 標準入出力・環境変数・argv の取得と最低限の整形。
- LLVM / OS FFI への極小ラッパ(`rt_mem_*` などの intrinsic の土台)。
- Rust VM/LLVM のコアMIR インタプリタ/コード生成)の提供。
- Stage1 で AOT されたコア関数(後述)を呼び出すランチャ。
**禁止/抑制(緩和版):**
- パーサ高レイヤStageBMirBuilderAotPrepnumeric core の**意味論そのもの**を Rust 側に新規実装しないSelfHost の責務)。
- 新しい Box 実装や高レベルランタイム機能を Rust に持ち込むのは原則避ける(ただし Stage1 ブリッジやエラーログ改善など、導線・可観測性に必要な最小限の変更は許可)。
### Stage1 — Hakorune Selfhost Binary
**想定バイナリ:**
- `target/selfhost/hakorune`Stage0 が AOT して生成する EXE; ファイル名で Stage1 を表し、配置ディレクトリで Stage0 と分離)
**構成要素(.hako 側で実装/AOT:**
- StageB コンパイラ(`lang/src/compiler/entry/compiler_stageb.hako` など)。
- MirBuilder / MIR v1→v0 アダプタ。
- AotPrep`selfhost.llvm.ir.aot_prep.*`、numeric core パスを含む)。
- Ring1 VMruntime の一部System Hakorune subset で書かれたコアロジック)。
**責務:**
- Source(.hako) → Program(JSON) → MIR → 実行LLVM AOT の全パイプラインを Hakorune コードで担う。
- Stage1 自身を再ビルドできる最小セット(自己ホストコア)を提供する。
**起動イメージ:**
- Stage0 `main()`:
- 環境・argv を集約。
- AOT 済み `hakorune_main(argc, argv_ptr)`Stage1 側関数)を呼び出すだけの薄い導線。
### Runtime Lines共通
- VM 実行エンジンと LLVM バックエンドは Stage0/Rust に残すRing0
- Ny 側からは `env.mirbuilder.emit` / `env.codegen.emit_object` / `env.codegen.link_object` といった extern 経由で利用する。
- Stage1 は Rust CLI`nyash`)を「バックエンド CLI」として前提にせず、C-ABI/extern 経由で Ring0 機能にアクセスする。
- その上で Stage1/Hakorune コードを AOT したものをリンクして「言語本体」を構成する。
- 長期的には、Stage1 からさらに Stage1' を再ビルドして差分が収束する自己ホストサイクルを目指す。
- 具体的には「Stage0→Stage1本バイナリ」に加えて「Stage1→Stage1'」を実行し、両者の挙動/インターフェース一致を確認するチェックを設ける。
## ディレクトリ/バイナリ配置案
### Rust Stage0Bootstrap
- ソース配置案:
- `src/bootstrap/` … Stage0 専用のエントリポイントFFIVM/LLVM コアの窓口。
- 既存の Rust コードは徐々にここへ整理(広域リファクタは別フェーズで慎重に)。
- バイナリ:
- 現在: `target/release/nyash` … Stage0 実行ファイルRust 製 hakorune 相当)。
- 将来: `target/release/hakorune-bootstrap` … Stage0 専用バイナリ(名称を分離予定)。
### Hakorune Stage1Selfhost
- ソース:
- 既存どおり `lang/src/**` に配置StageB / MirBuilder / AotPrep / VM など)。
- Stage1 としてビルドすべきモジュールセットを `tools/selfhost/` 以下のスクリプトで管理する。
- バイナリ:
- 現在Phase 25.1 初期実装):
- Dev line:
- `tools/selfhost/build_stage1.sh``apps/selfhost-runtime/runner.hako` を AOT し、`target/selfhost/hakorune` を生成する。
- 「Ny ExecutorMIR v0 ランタイムCLI 実験」の開発用 EXE最新版
- Stable line:
- `lang/build/build_runner.sh``lang/bin/hakorune` を生成pure-lang launcher / legacy bring-up
- 安定した `target/selfhost/hakorune``lang/bin/hakorune` に昇格させて配布基準とする運用を想定。
- 将来:
- `lang/bin/hakorune` を「標準 hakorune」として日常利用のメインバイナリに昇格させるdev line は常に先行する実験用バイナリ)。
- Stage0 は `hakorune-bootstrap` として非常用ランチャ/自己ホストの起点として残す。
## ビルド導線Phase 25.1 初期版)
このフェーズでは「Rust Stage0 バイナリ」と「Hakorune Stage1 バイナリ」を、ビルド導線レベルで分離するところまでを行う。
### Makefile ターゲット(開発用)
- `make stage0-release`
- 役割: Rust Stage0`target/release/nyash`)をビルドする。
- 実体: `cargo build --release`既定機能のみ、Rust CLI のみを対象)。
- `make stage1-selfhost`
- 役割: Stage0 を利用して Stage1 selfhost バイナリをビルドする。
- 実体:
- `make stage0-release`Stage0 準備)
- `tools/selfhost/build_stage1.sh`
- 出力: `target/selfhost/hakorune-selfhost`Ny Executor 最小 EXE
### Stage1 ビルドスクリプト
- `tools/selfhost/build_stage1.sh`
- 入力: `apps/selfhost-runtime/runner.hako`Ny Executor エントリ)。
- 経路:
1. `tools/hakorune_emit_mir.sh` で StageBMirBuilder を通し、MIR(JSON v1) を生成。
2. `tools/ny_mir_builder.sh --emit exe` で ny-llvmc 経由の EXE を生成。
- 出力: `target/selfhost/hakorune-selfhost`
- 備考:
- EXE のインターフェースは開発用MIR v0 ファイルを引数に取る Ny Executor。フル CLI 化は後続フェーズで行う。
- `NYASH_LLVM_SKIP_BUILD=1` を指定すると、既存の ny-llvmc / nyash_kernel ビルド成果物を再利用して高速化できる。
## フェーズ内タスク25.1 設計 TODO
### A. Stage0/Stage1 境界のドキュメント固定
- [x] 本ファイルphase-25.1/README.mdに Stage0/Stage1 の責務と禁止事項を明文化する。
- [x] Phase 25 README に Stage0/Stage1 の関係をリンクRing0/Ring1 の上位概念として扱う)。
- [x] CURRENT_TASK.md に「Stage0=Rust bootstrap / Stage1=Hakorune selfhost」の方針を追記。
### B. Stage1 コアセットの定義
- [ ] Stage1 で AOT すべきモジュール一覧をドラフトする(例: StageB / MirBuilder / AotPrep / numeric core
- [ ] それらのエントリポイント関数(例: `hakorune_main/argc,argv` 相当)を .hako 側で定義する設計メモを追加。
### C. ビルド/配置戦略(設計のみ)
### C. ビルド/配置戦略(設計 → 初期実装)
- [x] `tools/selfhost/` 以下に Stage1 ビルド用スクリプト名と役割を決める(`build_stage1.sh`)。
- [x] `target/selfhost/` ディレクトリに Stage1 バイナリを配置する方針を Cargo/Makefile コメントに記載。
- [x] Makefile に `stage0-release` / `stage1-selfhost` ターゲットを追加し、Stage0/Stage1 のビルド導線を分離。
### D. 将来の自己ホストサイクルの入口を定義
- [ ] Stage0→Stage1→Stage1' のビルドシーケンスを文章で定義(どの組み合わせで自己一致チェックを行うか)。
- [ ] 「普段使うのは Stage1」「問題発生時に Stage0 から再生成」という運用パターンを docs に記載。
### E. Stage1 UsingResolver / LoopForm v2 対応(設計)
- [x] 設計ドラフトを追加(`stage1-usingresolver-loopform.md`。Region+next_i 形ループと Carrier/Pinned 対応の指針を明文化。
- [x] Rust 側の観測結果を反映し、具体的なリライト手順とテスト項目を更新するJSON→LoopForm v2 導線StageB→Stage1 データフローのテキスト図を追記)。
## 実装チェックリスト25.1 実行順案)
### 1. バイナリ命名と役割の明確化
- [x] Cargo.toml に Stage0/Stage1 の bin ターゲット方針を書き出す(ドキュメントコメントレベル)。
- 現状: `[[bin]] name = "nyash"` を Stage0Rust bootstrapとして扱い、Stage1 は `tools/selfhost/build_stage1.sh` で生成される `target/selfhost/hakorune` として外部管理。
- [ ] CURRENT_TASK.md に「ユーザーが使うのは `hakorune` / Stage0 は `hakorune-rust`」という運用ポリシーを追記。
### 2. Stage1 ランチャーHako側 Mainの骨組み
- [ ] `lang/src/runner/launcher.hako` を Stage1 の論理エントリポイントとして固定し、コメントに責務(モード切り替え)を書く。
- [ ] ランチャーから呼ぶパイプラインインターフェースを設計する:
- [ ] `.hako → Program(JSON)` を呼ぶ関数StageB
- [ ] `Program(JSON) → MIR(JSON)` を呼ぶ関数MirBuilder
- [ ] `MIR(JSON) → PREP(MIR)` を呼ぶ関数AotPrep + numeric_core
- [ ] `MIR(JSON) → 実行/EXE` を呼ぶ関数VM/LLVM
- [ ] `launcher.hako``Main.main(args)` から、上記インターフェースを呼び分ける最小のモード分岐を定義する設計メモを追加(実装は後続フェーズでもよい)。
### 3. selfhost 用ビルドスクリプトの足場
- [ ] `tools/selfhost/` ディレクトリを作成(存在しない場合)。
- [ ] `tools/selfhost/build_stage1.sh`(仮称)の skeleton を追加:
- [ ] 必要な Hako モジュールセットStageB / MirBuilder / AotPrep / runtimeをコメントで列挙。
- [ ] 現時点では no-op または「未実装」のメッセージだけにして、呼び出し位置を固定。
- [ ] README本ファイルに build_stage1.sh の役割と将来の AOT 手順(.hako→MIR→ny-llvmc→EXEを文章で書いておく。
### 4. Stage0 ↔ Stage1 の切り替えポリシー
- [ ] docs に「普段は Stage1 の `hakorune` を使い、壊れたときだけ Stage0 の `hakorune-rust` を直接叩く」という運用例を追記。
- [ ] `tools/selfhost/` に便利ラッパの案をメモしておく:
- 例: `hako-vm.sh`Stage1 + `--backend vm`)、`hako-exe.sh`Stage1 + `--backend llvm --exe`)。
### 5. 将来の自己ホストルートへの接続
- [ ] Stage1 の `Main.main(args)` から「自分自身を再ビルドする」エントリポイント名だけ決めておく(例: `selfhost_build_main`)。
- [ ] Phase 26 以降で、このエントリポイントを `tools/selfhost/build_stage1.sh` から呼ぶ形にする想定を書き残す。
このチェックリストは「コードを書く前に何を決めておくか」と「どこから小さく実装を始めるか」の順序を示すだけで、実装自体は後続フェーズで少しずつ進める前提だよ。
## このフェーズでやらないこと
- Rust コードの削除や広域リファクタ(責務の再ラベリングとロードマップ策定に留める)。
- Stage1 バイナリを CI で標準に昇格させる変更(ローカル開発用の設計段階に留める)。
- Stage1 ランチャー(フル CLI モード切り替え)の実装本体(このフェーズでは Ny Executor 最小 EXE まで)。
Related docs:
- `docs/private/roadmap2/phases/phase-25/README.md` … Stage0/Ring0-Ring1 再編と numeric_core BoxCall→Call パスのまとめ。
- `docs/development/runtime/cli-hakorune-stage1.md` … Stage1 hakorune CLI のサブコマンド設計と Stage0 との役割分離。
- `docs/private/roadmap2/phases/phase-25.1a/README.md` … Stage1 build パイプラインProgram→MIR/selfhost AOTのホットフィックス計画。***