diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index d9722b42..7208da9e 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -70,7 +70,7 @@ - `src/tests/mir_stageb_loop_break_continue_verifies` - Stage‑B 風の `loop + break/continue` パターンで MirVerifier 緑。 - `src/tests/mir_stage1_using_resolver_verify.rs::mir_stage1_using_resolver_full_collect_entries_verifies` - - `NYASH_LOOPFORM_PHI_V2=1` で Stage‑1 UsingResolver フル版が LoopForm v2/PHI v2 経路で MirVerifier 緑。 + - LoopForm v2/PHI v2 経路(現在は既定実装)で Stage‑1 UsingResolver フル版が MirVerifier 緑。 - 実行観測: - 開発用 Hako `loop_continue_fixed.hako`: - 期待 `RC=3` / 実測 `RC=3`、PHI pred mismatch なし。 diff --git a/docs/development/analysis/LOOPFORM_PHI_NEXT_STEPS.md b/docs/development/analysis/LOOPFORM_PHI_NEXT_STEPS.md index 9b540135..5a337cdd 100644 --- a/docs/development/analysis/LOOPFORM_PHI_NEXT_STEPS.md +++ b/docs/development/analysis/LOOPFORM_PHI_NEXT_STEPS.md @@ -89,16 +89,9 @@ pub fn build_loop( condition: &ASTNode, body: &Vec, ) -> Result { - // Check feature flag - let use_loopform_v2 = std::env::var("NYASH_LOOPFORM_PHI_V2") - .map(|v| v == "1" || v.to_lowercase() == "true") - .unwrap_or(false); - - if use_loopform_v2 { - self.build_loop_with_loopform(condition, body) - } else { - self.build_loop_legacy(condition, body) - } + // 設計当初は feature flag(NYASH_LOOPFORM_PHI_V2)で切り替える案だったが、 + // 現在は LoopForm v2 が既定実装なので常に build_loop_with_loopform を使う。 + self.build_loop_with_loopform(condition, body) } fn build_loop_with_loopform( @@ -177,8 +170,7 @@ fn build_loop_legacy( # Build with new implementation cargo build --release -# Test fibonacci -export NYASH_LOOPFORM_PHI_V2=1 +# Test fibonacci(現在はフラグ不要) ./target/release/nyash local_tests/fib_multi_carrier.hako # Expected output: 8 @@ -186,8 +178,7 @@ export NYASH_LOOPFORM_PHI_V2=1 **Debugging**: ```bash -# Enable MIR dump -export NYASH_LOOPFORM_PHI_V2=1 +# Enable MIR dump(現在はフラグ不要) ./target/release/nyash --dump-mir local_tests/fib_multi_carrier.hako # Check for: @@ -202,9 +193,7 @@ export NYASH_LOOPFORM_PHI_V2=1 **Run existing tests**: ```bash -export NYASH_LOOPFORM_PHI_V2=1 - -# Simple loops +# Simple loops(LoopForm v2 は既定 ON) tools/smokes/v2/run.sh --profile quick --filter "loop_simple" # Multi-carrier loops diff --git a/docs/development/analysis/LOOPFORM_PHI_SOLUTION_SUMMARY.md b/docs/development/analysis/LOOPFORM_PHI_SOLUTION_SUMMARY.md index 166d67b3..58aa79f8 100644 --- a/docs/development/analysis/LOOPFORM_PHI_SOLUTION_SUMMARY.md +++ b/docs/development/analysis/LOOPFORM_PHI_SOLUTION_SUMMARY.md @@ -100,11 +100,13 @@ preheader → header (PHI nodes) → body → latch → header ### Integration Points -**Feature Flag**: `NYASH_LOOPFORM_PHI_V2=1` (environment variable) +**Status**: 当初は `NYASH_LOOPFORM_PHI_V2=1` で opt-in する Feature Flag 案だったが、 +現在は LoopFormBuilder を用いた PHI 生成が **常に既定実装** になっている。 + +過去の段階的移行案(参考・設計メモとして残す): -**Migration Strategy**: ```rust -// In mir/loop_builder.rs +// In mir/loop_builder.rs (設計当初の案。現在は v2 が常時有効) if std::env::var("NYASH_LOOPFORM_PHI_V2").is_ok() { // Use new LoopFormBuilder let mut loopform = LoopFormBuilder::new(preheader_id, header_id); @@ -148,38 +150,10 @@ if std::env::var("NYASH_LOOPFORM_PHI_V2").is_ok() { ## Testing Strategy -### Phase 1: Smoke Tests -```bash -# Enable new implementation -export NYASH_LOOPFORM_PHI_V2=1 +### Phase 1–3: 現在の運用メモ -# Test fibonacci multi-carrier -cargo build --release -./target/release/nyash local_tests/fib_multi_carrier.hako -# Expected: 8 (correct fibonacci(6)) - -# Run all loop tests -tools/smokes/v2/run.sh --profile quick --filter "loop" -``` - -### Phase 2: Regression Testing -```bash -# Compare output with/without new implementation -for test in local_tests/loop_*.hako; do - echo "Testing $test" - NYASH_LOOPFORM_PHI_V2=0 ./target/release/nyash "$test" > /tmp/old.out - NYASH_LOOPFORM_PHI_V2=1 ./target/release/nyash "$test" > /tmp/new.out - diff /tmp/old.out /tmp/new.out || echo "MISMATCH: $test" -done -``` - -### Phase 3: Performance Validation -```bash -# Ensure no performance regression -hyperfine \ - 'NYASH_LOOPFORM_PHI_V2=0 ./target/release/nyash bench/loop_heavy.hako' \ - 'NYASH_LOOPFORM_PHI_V2=1 ./target/release/nyash bench/loop_heavy.hako' -``` +- 実装が LoopForm v2 に一本化されたため、`NYASH_LOOPFORM_PHI_V2` による A/B 比較フェーズは既に完了済み。 +- 以降の性能比較や回帰テストでは、単に `./target/release/nyash` を直接叩けばよい(フラグ不要)。 --- diff --git a/docs/development/roadmap/phases/phase-25.1/README.md b/docs/development/roadmap/phases/phase-25.1/README.md index d8e6b229..f1fa4a11 100644 --- a/docs/development/roadmap/phases/phase-25.1/README.md +++ b/docs/development/roadmap/phases/phase-25.1/README.md @@ -18,7 +18,7 @@ Status: design+partial implementation(Stage1 ビルド導線の初期版まで - 担当: Stage‑B/Stage‑1/selfhost で見えている Undefined Value / non‑dominating use を、まず Rust 階層だけで止血する。 - **25.1e — LoopForm PHI v2 Migration(Rust)** - ねらい: ループの PHI 生成の「SSOT」を LoopForm v2 + `phi_core` に寄せ、Legacy LoopBuilder 経路との二重管理を解消する。 - - 担当: `NYASH_LOOPFORM_PHI_V2=1` を使って Stage‑1 / Stage‑B 代表ループ(`_find_from` や stageb_min)を通し、`phi pred mismatch` / ValueId 二重定義を構造的に解消する。 + - 担当: 当初は `NYASH_LOOPFORM_PHI_V2=1` を使って Stage‑1 / Stage‑B 代表ループ(`_find_from` や stageb_min)を通し、`phi pred mismatch` / ValueId 二重定義を構造的に解消する計画だったが、現在は LoopForm v2 が既定実装となっており、フラグは不要(互換目的のみ)。 ざっくりとした進行順は「25.1a/c で配線と箱分割 → 25.1d/e で Rust MIR/LoopForm を根治 → その結果を踏まえて 25.1b(selfhost MirBuilder/LoopSSA)側に寄せていく」というイメージだよ。 diff --git a/docs/development/roadmap/phases/phase-25.1e/README.md b/docs/development/roadmap/phases/phase-25.1e/README.md index 6d3e2a35..95fa5c0d 100644 --- a/docs/development/roadmap/phases/phase-25.1e/README.md +++ b/docs/development/roadmap/phases/phase-25.1e/README.md @@ -30,9 +30,10 @@ Status: planning(LoopForm/PHI 正規化フェーズ・挙動は変えない/ - **SSOT を決める**: - ループの PHI 生成の「正」は LoopForm v2 (`LoopFormBuilder` + `LoopFormOps` + `phi_core::loop_phi/if_phi`) に置く。 - `build_loop_legacy` + `prepare_loop_variables_with` は「互換レイヤ/移行レイヤ」と位置づけ、最終的には LoopForm v2 の薄いラッパに縮退させる。 -- **Feature Flag で段階導入**: - - `NYASH_LOOPFORM_PHI_V2=1` のときだけ LoopForm v2 経路を使い、当面は Stage‑B / Stage‑1 / selfhost 用テストの中でピンポイントに有効化する。 - - デフォルト挙動は変えない(フラグ未設定時はこれまでどおり legacy 経路)。 +- **Feature Flag で段階導入(※この段階の設計メモ)**: + - 当初は `NYASH_LOOPFORM_PHI_V2=1` のときだけ LoopForm v2 経路を使う案だったが、 + 現在は LoopForm v2 が既定実装となっており、legacy 経路は撤去済み。 + - `NYASH_LOOPFORM_PHI_V2` は互換性のために残っているが、挙動切り替えには使われない。 - **1 バグ 1 パターンで前進**: - `mir_stage1_using_resolver_full_collect_entries_verifies` や Stage‑B 最小ハーネスで見えている赤ログは、それぞれ最小 Hako に絞って LoopForm v2 側で再現・修正する。 - 同時に legacy 側からは同じ責務(PHI 生成ロジック)を抜いていき、二重管理を減らす。 @@ -41,9 +42,9 @@ Status: planning(LoopForm/PHI 正規化フェーズ・挙動は変えない/ ### 1. LoopForm v2 の足場をテストで固める -1.1 LoopForm v2 専用テストモードの追加 -- `mir_stage1_using_resolver_full_collect_entries_verifies` をベースに、`NYASH_LOOPFORM_PHI_V2=1` を立てた状態でのみ走るサブテストを追加。 -- 目的: v2 経路で `_find_from` ループの SSA/PHI が整合していることを検証する足場を作る(まだ赤でもよい)。 +1.1 LoopForm v2 専用テストモードの追加(→ 現在は「LoopForm v2 が既定」の前提で完了) +- `mir_stage1_using_resolver_full_collect_entries_verifies` は LoopForm v2 前提で緑になっており、 + もはやフラグは不要(テスト内の `NYASH_LOOPFORM_PHI_V2` 設定も削除済み)。 1.2 Stage‑B 最小ハーネス用ループ抜き出しテスト - `lang/src/compiler/tests/stageb_min_sample.hako` から、代表的なループだけを抜き出した Hako を作り、LoopForm v2 経路(`NYASH_LOOPFORM_PHI_V2=1`)で `MirVerifier` を通すテストを追加。 diff --git a/lang/src/compiler/builder/ssa/exit_phi/README.md b/lang/src/compiler/builder/ssa/exit_phi/README.md index 3ddabc2d..441e96ac 100644 --- a/lang/src/compiler/builder/ssa/exit_phi/README.md +++ b/lang/src/compiler/builder/ssa/exit_phi/README.md @@ -98,7 +98,9 @@ The .hako implementation in this directory is **architecturally correct** but op - `HAKO_LOOPSSA_EXIT_PHI=1`: Enable .hako EXIT PHI (disabled by default) - `HAKO_COMPILER_BUILDER_TRACE=1`: Show compilation pass trace - `NYASH_LOOPFORM_DEBUG=1`: Debug Rust loopform builder -- `NYASH_LOOPFORM_PHI_V2=1`: Enable Rust EXIT PHI generation +- `NYASH_LOOPFORM_PHI_V2`: + - 以前は Rust 側 LoopForm PHI v2 の切り替えフラグだったが、 + - 現在は **LoopForm PHI v2 が常に既定実装**のため、設定不要(存在しても挙動は変わらない)。 ## File Sizes diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index d1bf7567..83c8b997 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -17,6 +17,15 @@ use super::utils::{ capture_actual_predecessor_and_jump, }; +/// ループ脱出の種類(箱化・共通化のための型) +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum LoopExitKind { + /// break文(exit blockへジャンプ) + Break, + /// continue文(header blockへジャンプ) + Continue, +} + /// ループビルダー - SSA形式でのループ構築を管理 pub struct LoopBuilder<'a> { /// 親のMIRビルダーへの参照 @@ -67,34 +76,64 @@ impl<'a> LoopBuilder<'a> { Ok(void_id) } - /// Handle a `break` statement: jump to loop exit and continue in a fresh unreachable block. - fn do_break(&mut self) -> Result { - // Snapshot variables at break point for exit PHI generation + /// 【箱化】ループ脱出の共通処理(break/continue統一化) + /// + /// Phase 25.1o: break と continue の共通パターンを抽出し、 + /// LoopExitKind で振る舞いを切り替える統一メソッド。 + /// + /// # 処理フロー + /// 1. 現在の変数マップをスナップショット + /// 2. 適切なスナップショットリストに追加(Break → exit_snapshots, Continue → continue_snapshots) + /// 3. ターゲットブロックへジャンプ(Break → exit, Continue → header) + /// 4. unreachable ブロックに切り替え + fn do_loop_exit(&mut self, kind: LoopExitKind) -> Result { + // 1. スナップショット取得(共通処理) let snapshot = self.get_current_variable_map(); let cur_block = self.current_block()?; - eprintln!("[DEBUG/do_break] Saved snapshot from block {:?}, vars: {:?}", - cur_block, snapshot.keys().collect::>()); - self.exit_snapshots.push((cur_block, snapshot)); - if let Some(exit_bb) = crate::mir::builder::loops::current_exit(self.parent_builder) { - self.jump_with_pred(exit_bb)?; + // 2. スナップショット保存(kind別処理) + match kind { + LoopExitKind::Break => { + if std::env::var("NYASH_LOOPFORM_DEBUG").ok().as_deref() == Some("1") { + eprintln!("[DEBUG/do_break] Saved snapshot from block {:?}, vars: {:?}", + cur_block, snapshot.keys().collect::>()); + } + self.exit_snapshots.push((cur_block, snapshot)); + } + LoopExitKind::Continue => { + self.block_var_maps.insert(cur_block, snapshot.clone()); + self.continue_snapshots.push((cur_block, snapshot)); + } } + + // 3. ターゲットブロックへジャンプ(kind別処理) + match kind { + LoopExitKind::Break => { + if let Some(exit_bb) = crate::mir::builder::loops::current_exit(self.parent_builder) { + self.jump_with_pred(exit_bb)?; + } + } + LoopExitKind::Continue => { + if let Some(header) = self.loop_header { + self.jump_with_pred(header)?; + } + } + } + + // 4. unreachable ブロックに切り替え(共通処理) self.switch_to_unreachable_block_with_void() } + /// Handle a `break` statement: jump to loop exit and continue in a fresh unreachable block. + /// 【箱化】do_loop_exit() への thin wrapper + fn do_break(&mut self) -> Result { + self.do_loop_exit(LoopExitKind::Break) + } + /// Handle a `continue` statement: snapshot vars, jump to loop header, then continue in a fresh unreachable block. + /// 【箱化】do_loop_exit() への thin wrapper fn do_continue(&mut self) -> Result { - // Snapshot variables at current block to be considered as a predecessor input - let snapshot = self.get_current_variable_map(); - let cur_block = self.current_block()?; - self.block_var_maps.insert(cur_block, snapshot.clone()); - self.continue_snapshots.push((cur_block, snapshot)); - - if let Some(header) = self.loop_header { - self.jump_with_pred(header)?; - } - - self.switch_to_unreachable_block_with_void() + self.do_loop_exit(LoopExitKind::Continue) } // ============================================================= diff --git a/src/mir/phi_core/loopform_builder.rs b/src/mir/phi_core/loopform_builder.rs index 025b23c1..875aa53e 100644 --- a/src/mir/phi_core/loopform_builder.rs +++ b/src/mir/phi_core/loopform_builder.rs @@ -4,8 +4,8 @@ * Solves the ValueId circular dependency problem by treating loop structure * as a "Meta-Box" with explicit separation of carriers vs. pinned variables. * - * Phase: 25.1b prototype implementation - * Status: Feature-flagged (NYASH_LOOPFORM_PHI_V2=1) + * Phase: 25.1b prototype implementation → 25.1m で安定化 + * Status: Always-on(LoopForm PHI v2 は既定実装。NYASH_LOOPFORM_PHI_V2 は互換目的のみで、挙動切り替えには使われない) */ use crate::mir::{BasicBlockId, ValueId}; diff --git a/src/tests/mir_loopform_exit_phi.rs b/src/tests/mir_loopform_exit_phi.rs index 0eb3c5ac..268e81a3 100644 --- a/src/tests/mir_loopform_exit_phi.rs +++ b/src/tests/mir_loopform_exit_phi.rs @@ -10,8 +10,8 @@ use crate::mir::{MirCompiler, MirVerifier}; #[test] fn test_loopform_exit_phi_single_break() { - // Enable LoopForm PHI v2 and MIR verification - std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1"); + // LoopForm PHI v2 はデフォルト実装(フラグ不要) + // Enable MIR verification and debug traces std::env::set_var("NYASH_VM_VERIFY_MIR", "1"); std::env::set_var("NYASH_LOOPFORM_DEBUG", "1"); std::env::set_var("NYASH_PARSER_STAGE3", "1"); @@ -70,7 +70,7 @@ static box TestExitPhi { #[test] fn test_loopform_exit_phi_multiple_breaks() { - std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1"); + // LoopForm PHI v2 はデフォルト実装(フラグ不要) std::env::set_var("NYASH_VM_VERIFY_MIR", "1"); std::env::set_var("NYASH_LOOPFORM_DEBUG", "1"); std::env::set_var("NYASH_PARSER_STAGE3", "1"); @@ -108,7 +108,7 @@ static box TestMultiBreak { #[test] fn test_loopform_exit_phi_nested_if_break() { - std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1"); + // LoopForm PHI v2 はデフォルト実装(フラグ不要) std::env::set_var("NYASH_VM_VERIFY_MIR", "1"); std::env::set_var("NYASH_LOOPFORM_DEBUG", "1"); std::env::set_var("NYASH_PARSER_STAGE3", "1"); @@ -151,7 +151,7 @@ static box TestNestedBreak { #[test] fn test_loopform_exit_phi_multiple_vars() { - std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1"); + // LoopForm PHI v2 はデフォルト実装(フラグ不要) std::env::set_var("NYASH_VM_VERIFY_MIR", "1"); std::env::set_var("NYASH_LOOPFORM_DEBUG", "1"); std::env::set_var("NYASH_PARSER_STAGE3", "1"); diff --git a/src/tests/mir_stage1_using_resolver_verify.rs b/src/tests/mir_stage1_using_resolver_verify.rs index 141417eb..674e8a33 100644 --- a/src/tests/mir_stage1_using_resolver_verify.rs +++ b/src/tests/mir_stage1_using_resolver_verify.rs @@ -91,8 +91,7 @@ static box Stage1UsingResolverMini { #[test] fn mir_stage1_using_resolver_full_collect_entries_verifies() { ensure_stage3_env(); - // Use LoopForm PHI v2 for this test to exercise the new SSOT経路 - std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1"); + // LoopForm PHI v2 はデフォルト実装(フラグ不要) let src = r#" static box Stage1UsingResolverFull { // Simplified helper to find substring index (replaces JsonFragBox.index_of_from) diff --git a/tools/test_stageb_min.sh b/tools/test_stageb_min.sh index 58fed301..312dad5b 100644 --- a/tools/test_stageb_min.sh +++ b/tools/test_stageb_min.sh @@ -34,7 +34,6 @@ HAKO_STAGEB_FUNC_SCAN=1 \ NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ NYASH_PARSER_ALLOW_SEMICOLON=1 \ NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ -NYASH_LOOPFORM_PHI_V2=1 \ HAKO_LOOPSSA_EXIT_PHI="$HAKO_LOOPSSA_EXIT_PHI" \ HAKO_COMPILER_BUILDER_TRACE="$HAKO_COMPILER_BUILDER_TRACE" \ NYASH_VM_TRACE="$NYASH_VM_TRACE" \