Files
hakorune/docs/development/current/main/phases/phase-272/README.md

167 lines
7.9 KiB
Markdown
Raw Normal View History

feat(llvm/phi): Phase 277 P1 - fail-fast validation for PHI strict mode ## Summary Implemented fail-fast validation for PHI ordering and value resolution in strict mode. ## Changes ### P1-1: Strict mode for "PHI after terminator" - File: `src/llvm_py/phi_wiring/wiring.py::ensure_phi` - Behavior: `NYASH_LLVM_PHI_STRICT=1` → RuntimeError if PHI created after terminator - Default: Warning only (no regression) ### P1-2: Strict mode for "fallback 0" - File: `src/llvm_py/phi_wiring/wiring.py::wire_incomings` - Behavior: Strict mode forbids silent fallback to 0 (2 locations) - Location 1: Unresolvable incoming value - Location 2: Type coercion failure - Error messages point to next debug file: `llvm_builder.py::_value_at_end_i64` ### P1-3: Connect verify_phi_ordering() to execution path - File: `src/llvm_py/builders/function_lower.py` - Behavior: Verify PHI ordering after all instructions emitted - Debug mode: Shows "✅ All N blocks have correct PHI ordering" - Strict mode: Raises RuntimeError with block list if violations found ## Testing ✅ Test 1: strict=OFF - passes without errors ✅ Test 2: strict=ON - passes without errors (no violations in test fixtures) ✅ Test 3: debug mode - verify_phi_ordering() connected and running ## Scope - LLVM harness (Python) changes only - No new environment variables (uses existing 3 from Phase 277 P2) - No JoinIR/Rust changes (root fix is Phase 279) - Default behavior unchanged (strict mode opt-in) ## Next Steps - Phase 278: Remove deprecated env var support - Phase 279: Root fix - unify "2本のコンパイラ" pipelines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 14:48:37 +09:00
Status: Active
Date: 2025-12-22
Scope: Pattern6/7 を `Frag + emit_frag()` へ段階吸収pattern列挙の増殖を止める
Related:
- Design SSOT: `docs/development/current/main/design/edgecfg-fragments.md`
- Phase 269Pattern8 Frag: `docs/development/current/main/phases/phase-269/README.md`
- Phase 270Pattern9 bridge: `docs/development/current/main/phases/phase-270/README.md`
# Phase 272P0: Pattern6/7 を Frag+emit_frag へ吸収(段階適用)
## ステータス
- **P0.1Pattern6**: ✅ 完了Frag+emit_frag 経路へ移行)
- **P0.2Pattern7**: ✅ 完了Frag+emit_frag 経路へ移行)
## 目的
- Pattern6/7scan系の CFG 構築を “pattern番号ごとの推測分岐” から外し、**EdgeCFG Frag 合成ExitKind/wires/branches**に収束させる。
- terminator emission を SSOT`emit_frag()`へ集約し、block の successors/preds 同期漏れを構造で防ぐ。
## スコープ境界
### ✅ 触る
- `src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs`
- `src/mir/builder/control_flow/joinir/patterns/pattern7_split_scan.rs`
- `src/mir/builder/emission/`Pattern8 と同じ “薄い入口” の追加)
### ❌ 触らない
- merge/EdgeCFG plumbingPhase 260-268 の SSOT は維持)
- cf_loop の非JoinIR経路追加JoinIR-only hard-freeze 維持)
- by-name ハードコードBox名/Pattern名文字列での分岐増殖など
## 入口SSOTfixture/smoke
### Pattern6index_of
- fixture: `apps/tests/phase254_p0_index_of_min.hako`exit=1
- smoke (VM): `tools/smokes/v2/profiles/integration/apps/phase254_p0_index_of_vm.sh`
### Pattern7split
- fixture: `apps/tests/phase256_p0_split_min.hako`exit=3
- smoke (VM): `tools/smokes/v2/profiles/integration/apps/phase256_p0_split_vm.sh`
## 方針P0
P0 は “両方一気に” ではなく、以下の順で段階適用する。
1. Pattern6 を `Frag + emit_frag()` に切り替えwiring を SSOT 化)
2. Pattern7 を `Frag + emit_frag()` に切り替え(副作用 push を含む)
3. 旧 JoinIR 経路の撤去条件が満たせた時点で削除本READMEに明記
## 実装ガイド(共通)
- PHI は block 先頭after existing phisへ挿入し、入力を `[(pred_bb, val)]` の形で固定する:
- `crate::mir::ssot::cf_common::insert_phi_at_head_spanned`
- terminator emission は `crate::mir::builder::control_flow::edgecfg::api::emit_frag` に集約する。
- Pattern8 の構造(参考):
- emission 入口: `src/mir/builder/emission/loop_predicate_scan.rs`
## P0.1: Pattern6index_of— Frag 化
### 狙い
- loop 骨格header/body/step/after + early returnを Frag に落とし、Jump/Branch/Return を `emit_frag()` に集約する。
### 実装結果(✅ 完了)
- emission 入口を新設し、Pattern6 の terminator emission を `emit_frag()`SSOTへ集約
- 新規: `src/mir/builder/emission/loop_scan_with_init.rs`
- 更新: `src/mir/builder/emission/mod.rs`
- Pattern6 の JoinIRConversionPipeline 経路を撤去し、Frag 経路へ切り替え
- 更新: `src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs`
- P0 スコープ:
- forward scan`step=1`)のみ適用
- reverse/dynamic needle 等は `Ok(None)` で不適用(既定挙動不変)
- 旧 DCE 対策exit PHI 用の post-loop guardを撤去Frag が Return を直接 emit するため)
### 最小 CFG 形forward scan
- blocks: `header`, `body`, `step`, `after`, `ret_found`
- header:
- `i_current = phi [i_init, preheader], [i_next, step_bb]`
- `cond_loop = (i_current < len)`
- branch: true→body, false→after
- body:
- `ch = s.substring(i_current, i_current+1)`
- `cond_match = (ch == needle)`
- branch: true→ret_found, false→step
- step:
- `i_next = i_current + 1`
- jump: →header
- ret_found:
- wire: `Return(i_current)`
- after:
- P0 では `return -1` を既存 AST lowering に任せてもよいafter を current_block にする)
### 受け入れ
- `cargo test -p nyash-rust --lib --release`
- `HAKORUNE_BIN=./target/release/hakorune bash tools/smokes/v2/profiles/integration/apps/phase254_p0_index_of_vm.sh`
### 追加の検証(推奨)
- `NYASH_VM_DUMP_MIR=1 ./target/release/hakorune --backend vm apps/tests/phase254_p0_index_of_min.hako` で PHI/terminator を確認(任意)
## P0.2: Pattern7split— Frag 化
### 狙い
- Pattern7 の terminator 配線if/loop の遷移)を Frag に集約し、副作用(`result.push`)を含む形でも CFG を壊さない。
### 注意点Fail-Fast
- carriers が複数(`i`, `start`なので、header の PHI を 2 本(以上)で SSA を閉じる必要がある。
- `result.push` は副作用なので、block 配置評価順を壊さないP0は固定形のみ受理
### 実装結果(✅ 完了)
- Pattern7 の JoinIRConversionPipeline 経路を撤去し、Frag+emit_frag 経路へ切り替え
- 更新: `src/mir/builder/control_flow/joinir/patterns/pattern7_split_scan.rs`
- emission 入口を新設し、terminator emission を `emit_frag()`SSOTへ集約
- 新規: `src/mir/builder/emission/loop_split_scan.rs`
- 更新: `src/mir/builder/emission/mod.rs`
- CFG 形P0:
- blocks: `header`, `body`, `then`, `else`, `step`, `after`+ 入口 preheader
- header: PHI`i_current`, `start_current` + loop condition
- body: delimiter match check
- then: `result.push(segment)` + `start_next_then` 計算dominance 安全)
- else: `i_next_else = i_current + 1`
- step: PHI`i_next`, `start_next` + jump header
- Compare は `CompareOp::Le``i <= limit`)を使用(固定形)
### リファクタ結果共通SSOT
Phase 272 P0.2 完了後、Pattern6/7/8 の重複を以下へ収束した(仕様不変):
- PHI 挿入の薄いラッパ: `src/mir/builder/emission/phi.rs`
- variable_map の fail-fast 取得: `src/mir/builder/variable_context.rs``require(name, ctx)`
- can_lower の戦略メモ: `src/mir/builder/control_flow/joinir/patterns/router.rs``CanLowerStrategy`
### 受け入れ
- `HAKORUNE_BIN=./target/release/hakorune bash tools/smokes/v2/profiles/integration/apps/phase256_p0_split_vm.sh`
- PASSexit=3
- MIR 形PHI/Branch/Jump/BoxCall(push))を目視確認できること(任意)
## Nextplanned: Phase 273design-first— Pattern を Plan Extractor に降格して裾広がりを止める
Phase 272P0で “terminator SSOTemit_fragへ寄せる” を完了したら、次は上流の収束compiler flow の一本化)を行う。
- 相談メモ(外部レビュー用): `docs/development/current/main/investigations/phase-272-frag-plan-architecture-consult.md`
- ねらい:
- Pattern = **Plan 抽出pure** に降格builder を触らない)
- Plan = `seq/if/loop/exit/effect/let` の固定語彙(増殖しない)
- PlanLowerer が block/value/phi を作る唯一の箱emit_frag は SSOT のまま)
- 受け入れ(最小):
- extractor が `next_block_id/next_value_id/insert_phi_*` を呼ばない(純関数)
- Plan→Frag→emit_frag の本線が 1 本になるpattern番号列挙を中心にしない
## 旧 JoinIR 経路の撤去条件SSOT
`JoinIRConversionPipeline` 系の経路を削るのは、以下を満たした後に行う。
1. Pattern6/7 の fixture/smoke が Frag 経路で PASS
2. `tools/smokes/v2/run.sh --profile quick` が悪化しない
3. router から該当 pattern の “旧経路” が消せる(最小差分で削除可能)
## テスト手順(固定)
1. `cargo build --release`
2. `cargo test -p nyash-rust --lib --release`
3. `HAKORUNE_BIN=./target/release/hakorune bash tools/smokes/v2/profiles/integration/apps/phase254_p0_index_of_vm.sh`
4. `HAKORUNE_BIN=./target/release/hakorune bash tools/smokes/v2/profiles/integration/apps/phase256_p0_split_vm.sh`