docs(joinir): L-2.2 Step-4 - Update JoinIR VM bridge documentation

Phase 32 README:
- Expand VM Bridge table with "JoinIR 利用範囲" column
- Add L-2.2 progress summary table (Step-1~5 status)
- Add developer notes for Stage-B JoinIR observation

environment-variables.md:
- Add detailed descriptions for NYASH_JOINIR_* variables
- Clarify scope and limitations (Stage-B = lowering only)
- Add Stage-B JoinIR observation example

CURRENT_TASK:
- Update L-2.2 status to Step-1~4 complete

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-26 11:55:04 +09:00
parent 1eea40454f
commit eddc4e6035
2 changed files with 142 additions and 5 deletions

View File

@ -1,4 +1,4 @@
# Current Task — Phase 21.8 / 25 / 25.1 / 25.2 / 25.4 / 26-F / 26-G Snapshot2025-11-22 時点)
# Current Task — Phase 21.8 / 25 / 25.1 / 25.2 / 25.4 / 26-F / 26-G / 30 / 32 Snapshot2025-11-26 時点)
> このファイルは「今どこまで終わっていて、次に何をやるか」を 1000 行以内でざっくり把握するためのスナップショットだよ。
> 詳細な履歴やログは `git log CURRENT_TASK.md` からいつでも参照できるようにしておくね。
@ -171,6 +171,118 @@ LoopScopeShape → CaseAContext::from_scope() → lower_case_a_X_core() → Join
---
### 1-00c. Phase 32 L-1/L-2 — JoinIR 汎用化と Stage-1/Stage-B Bridge 進捗2025-11-26 更新)
**目的**
- Phase 30〜31 で整えた LoopToJoinLowerer / LoopScopeShape / JoinIR VM Bridge を、「minimal 4 本」から **本線Stage1 / StageB / selfhostライン**に広げていくための足場を Phase 32 で固める。
- CaseA 汎用ループを構造ベースで検出し、JoinIR lowering → JoinIR→VM Bridge までを一貫して扱える状態に近づける。
**対応フェーズ**
- Phase 32 L-1.x: LoopToJoinLowerer 汎用化CaseA 拡張)
- Phase 32 L-2.1: Stage1 UsingResolver 本線ループの JoinIR 化
- Phase 32 L-2.2 Step-1/2: StageB FuncScanner / BodyExtractor の JoinIR loweringVM Bridge への配線
**成果物L-1: LoopToJoinLowerer 汎用化)**
1. **is_supported_case_a_loop_view 構造ベース化**
- `LoopShape::to_region_view()` / `to_control_view()` / `to_exit_edges()` で LoopRegion / LoopControlShape / ExitEdge view を取得し、CaseA 判定を view ベースに移行。
- 判定ロジック:
- 単一出口(`control.exits.len() == 1`)であること。
- header の succ が 2 本while(cond) 相当)であること。
- pinned/carriers が空でないこと(実質的に状態を運ぶループに限定)。
-`is_supported_case_a_loop` はレガシーとして温存しつつ、実際の判定は `*_view` 側に集約。
2. **汎用 CaseA フラグ `NYASH_JOINIR_LOWER_GENERIC` 導入**
- 既定: OFFminimal 4 本: skip_ws / trim / append_defs / Stage1 minimal のみ LoopToJoinLowerer 対象)。
- `NYASH_JOINIR_LOWER_GENERIC=1` のとき:
- 関数名フィルタを外し、「構造チェックを満たすループ全般」を CaseA 候補として扱う。
- `LoopToJoinLowerer::lower()` 内で構造条件+環境変数を見て汎用パスを有効化。
3. **minimal 専用メソッドの整理**
- `lower_minimal_*_case_a``lower_case_a_for_*` にリネームし、「CaseA 汎用 lowerer の薄いラッパ」として役割を明示。
- 呼び出し元skip_ws / trim / append_defs / Stage1 minimalをすべて新名称に統一。
4. **テスト/確認**
- `joinir_runner_standalone_skip_ws` / `joinir_runner_standalone_trim` / `joinir_vm_bridge_trim_*` / JSON v0 スナップショット系テストは全て PASS。
- Stage1 / StageB については、`NYASH_JOINIR_LOWER_GENERIC` 有効時も lowering 自体は通ることを確認(意味論は簡略版のままなので VM 実行はまだ有効化しない)。
**成果物L-2.1: Stage1 UsingResolver 本線ループ)**
1. **本線ループを LoopToJoinLowerer 対象に昇格**
- 対象: `Stage1UsingResolverBox.resolve_for_source/5` 内の entries ループ(`lang/src/compiler/entry/using_resolver_box.hako:46-91`)。
- CFG から `construct_simple_while_loopform(entry_is_preheader=false, has_break=false)` で LoopForm を構築し、CaseA 条件while(i < n), break なし, 単一出口を満たすことを確認
2. **MIR-based lowering hook**
- `lower_from_mir()` 内で:
- 軽量 CFG チェックentry `Const 0`ArrayBox.length の存在などを通過した場合に LoopForm を構築
- `LoopToJoinLowerer::lower_case_a_for_stage1_resolver` を呼び成功時は LoopToJoinLowerer 由来の JoinIR を優先採用
- 失敗時非対応時は `build_stage1_using_resolver_joinir()`handwritten JoinIRにフォールバック
3. **JoinIR lowering の現状(簡略版)**
- `build_stage1_using_resolver_joinir()` Phase 27.12 の最小版のまま:
- `entries.get(i)` `prefix + entry` の文字列連結に限定
- `should_emit` path 解決など UsingResolver 本来のロジックはまだ JoinIR 側に持ち込んでいない
- Phase 32 ではCaseA 構造PHI 形状が JoinIR 側で正しく表現できることを優先し意味論フル移植は L-2.x / Phase 29 L-3.x で段階的に進める前提
4. **テスト**
- JSON スナップショット: 8/8 PASS`joinir_json_v0_stage1_usingresolver_min_matches_fixture` 含む)。
- VM Bridge: Stage1 **JoinIR lowering 検証のみ**後述の VM bridge dispatch にて実行は VM フォールバック)。
**成果物L-2.2 Step-1〜3: StageB FuncScanner / BodyExtractor**
1. **Step-1 — StageB lowering を LoopToJoinLowerer 経由に統一commit 9d769e92**
- 対象関数:
- `StageBBodyExtractorBox.build_body_src/2`
- `StageBFuncScannerBox.scan_all_boxes/1`
- 既存の StageB ループを CaseA 前提で LoopForm + LoopScopeShape view に載せLoopToJoinLowerer から JoinIR を生成する経路を追加
- もともとの handwritten JoinIR がある場合もShared Builder Pattern`lower_from_mir` / `lower_handwritten` `build_*_joinir`に揃える方針は Stage1 と同じ
2. **Step-2 — StageB を VM bridge dispatch に追加commit e61e7a2b**
- `src/mir/join_ir_vm_bridge_dispatch.rs` StageB 向けエントリを追加:
- `try_run_stageb_body``StageBBodyExtractorBox.build_body_src/2`
- `try_run_stageb_funcscanner``StageBFuncScannerBox.scan_all_boxes/1`
- 挙動:
- JoinIR lowering を試みる`lower_stageb_body_to_joinir` / `lower_stageb_funcscanner_to_joinir`)。
- JoinIR モジュールが生成できた場合は関数数などをログ出力し、**実際の実行は行わず `false` を返して VM 経路にフォールバック**。
- Stage1 UsingResolver と同一パターンJoinIR lowering の健全性検証専用ブリッジとして運用
- テスト:
- JSON v0 スナップショット: 6/6 PASSStageB 関連を含む)。
- `cargo build`: 成功警告なし
3. **Step-3 — StageB JoinIR→MIR 構造テスト追加commit 1eea4045**
- `src/mir/join_ir_vm_bridge.rs` `convert_joinir_to_mir` `pub(crate)` 化しテストから直接呼び出し可能に
- StageB 向けの構造テストを追加ファイル名: `src/tests/joinir_json_min.rs` :
- `joinir_stageb_body_structure_test`
- `StageBBodyExtractorBox.build_body_src/2` について:
- Route A: 既存パイプラインで MirModuleBaselineを生成
- Route B: `lower_stageb_body_to_joinir` `convert_joinir_to_mir` JoinIRMIR Bridge の結果を取得
- 両者とも対象関数が存在しJoinIR 経由の MIR でも Block 数が 1 以上であることを確認
- JoinIR lowering JoinIRMIR 変換がエラーなく通ることを確認
- `joinir_stageb_funcscanner_structure_test`
- `StageBFuncScannerBox.scan_all_boxes/1` について同様のチェックを実施
- 現時点の検証範囲:
- **handwritten JoinIRMIR Bridge の健全性確認** が主目的`build_stageb_*_joinir()` 由来)。
- まだ `intake_loop_form` StageB ループ構造に非対応のため、「MIRJoinIR roundtripの完全 A/B ではなく、「handwritten JoinIR VM Bridge で安全に MIR に落とせているかをテストする位置付け
**VM Bridge 対応関数一覧Phase 32 時点のまとめ)**
- `Main.skip/1`:
- JoinIR lowering + JoinIRMIRVM 実行まで対応済み
- `NYASH_JOINIR_EXPERIMENT=1` / `NYASH_JOINIR_VM_BRIDGE=1` Route B を有効化trim と並ぶ最初期の A/B テスト対象)。
- `FuncScannerBox.trim/1`:
- JoinIR lowering + JoinIRVM 実行まで対応済み
- `NYASH_JOINIR_INPUT` で入力文字列を差し替え可能未指定時 `" abc "`)。
- `Stage1UsingResolverBox.resolve_for_source/5`:
- JoinIR lowering 検証のみArrayBox / MapBox の引数を JoinValue::BoxRef として橋渡しする部分がまだ未実装のため実行は VM にフォールバックする設計
- `StageBBodyExtractorBox.build_body_src/2`:
- NEW: JoinIR lowering 検証のみStage1 と同様JoinIR モジュール生成に成功しても実行は VM 経路に任せる
- `StageBFuncScannerBox.scan_all_boxes/1`:
- NEW: JoinIR lowering 検証のみ同上
**制限と今後のタスク(忘れないためのメモ)**
- JoinIR lowering の多くは Phase 27.x 時点の簡略版のままで本番ロジックshould_emit / path 解決 / JSON マージなどはまだ .hako MIR に残っている
- Phase 32 ではCaseA 構造PHI 形状の正規化を優先し意味論フル移植は L-2.2 Step-35 / L-2.3 / Phase 29 L-3.x で段階的に進める
- Stage1 / StageB について JoinIRVM 実行まで有効化するには:
- JoinValue::BoxRef VM Box インスタンスの橋渡し引数マーシャリングを明示的に実装する必要あり
- JoinIR lowering 簡略版からVM Route A と意味論一致する版に引き上げA/B テストJSON / MIR / JoinIR / VM の比較を整備する必要がある
- Phase 32 TASKS のステータス2025-11-26 時点:
- L-1.1L-1.3: 完了LoopToJoinLowerer 汎用化の足場は整った)。
- L-2.1: 完了Stage1 UsingResolver 本線ループの JoinIR lowering + スナップショットテスト)。
- L-2.2: Step-14 完了StageB lowering 統一 + VM bridge dispatch + JoinIRMIR 構造テスト + ドキュメント更新)。Step-5安定化確認は未着手
- Step-3: `convert_joinir_to_mir` pub(crate) Stage-B 構造テスト2本追加 (commit 1eea4045)
- Step-4: Phase 32 README / env リファレンスを更新しStageB JoinIR 利用範囲loweringBridgeのみと各トグルの役割を明文化
- L-2.3 / L-3 / L-4: これからPHI レガシー削除とJoinIRVM/LLVM 前提ランナー構造への仕上げ)。
---
### 1-00a. Phase 30 F-1.4 — LoopScopeShape API 確定(**完了** 2025-11-25
**目的**

View File

@ -149,19 +149,44 @@ JoinIR は制御構造を関数呼び出し + 継続に正規化する IR 層(
| `NYASH_JOINIR_HEADER_EXP=1` | OFF | Any | Header PHI bypass 有効化dev-only |
| `NYASH_JOINIR_EXIT_EXP=1` | OFF | Any | Exit PHI 実験dev-only |
| `NYASH_JOINIR_LOWER_FROM_MIR=1` | OFF | Any | MIRベース lowering 有効化dev-only |
| `NYASH_JOINIR_LOWER_GENERIC=1` | OFF | Any | 構造ベースのみで Case-A 判定(関数名フィルタを外す, Phase 32 L-1.2 |
| `NYASH_JOINIR_VM_BRIDGE=1` | OFF | Any | VM bridge テストdev-only |
| `NYASH_JOINIR_LOWER_GENERIC=1` | OFF | Any | 構造ベースのみで Case-A 判定(関数名フィルタを外す) |
| `NYASH_JOINIR_VM_BRIDGE=1` | OFF | Any | VM bridge 経路Route Bを有効化 |
### JoinIR 各変数の詳細
**`NYASH_JOINIR_EXPERIMENT`**
- 対象: skip / trim / Stage-1 UsingResolver / Stage-B BodyExtractor / Stage-B FuncScanner
- 役割: JoinIR runner / JoinIR VM bridge / 各種テストを有効化する dev トグル
**`NYASH_JOINIR_VM_BRIDGE`**
- 対象: 上記と同じ
- 役割: VM モードで Route BMIR→JoinIR→MIR→VMを試す経路を有効化
- 重要: **実際に「JoinIR→VM 実行」まで行くのは Phase 32 時点では skip / trim に限定**。Stage-1 / Stage-B は lowering + Bridge の健全性確認まで(実行は VM Route A
**`NYASH_JOINIR_LOWER_GENERIC`** (Phase 32 L-1.2)
- 既定 OFF: minimal 4 本skip_ws / trim / append_defs / Stage-1 minimalのみ LoopToJoinLowerer 対象
- ON: LoopRegion / LoopControlShape / LoopScopeShape の構造条件を満たすループ全般を Case-A 候補として扱う
- 注意: Phase 32 では Stage-B / Stage-1 本線については「構造テスト・JoinIR 構造観測」用途で使うトグルであり、「意味論の本番切り替え」ではない
### JoinIR 使用例
```bash
# JoinIR 実験モード有効化
# JoinIR 実験モード有効化(基本)
NYASH_JOINIR_EXPERIMENT=1 ./target/release/hakorune program.hako
# Header PHI bypass 併用
NYASH_JOINIR_EXPERIMENT=1 NYASH_JOINIR_HEADER_EXP=1 ./target/release/hakorune program.hako
# Stage-B JoinIR lowering を観測したい場合Phase 32 開発用)
# → JoinIR lowering + JoinIR→MIR Bridge が走り、ログで JoinIR 構造が確認できる
# → 実際の実行は VM Route A にフォールバック
NYASH_JOINIR_EXPERIMENT=1 \
NYASH_JOINIR_VM_BRIDGE=1 \
NYASH_JOINIR_LOWER_GENERIC=1 \
./target/release/hakorune --dump-mir apps/tests/stageb_case.hako
```
詳細: [ENV_INVENTORY.md](../private/roadmap2/phases/phase-29-longterm-joinir-full/ENV_INVENTORY.md)
詳細: [ENV_INVENTORY.md](../private/roadmap2/phases/phase-29-longterm-joinir-full/ENV_INVENTORY.md) / [Phase 32 README](../private/roadmap2/phases/phase-32-joinir-complete-migration/README.md)
---