Files
hakorune/docs/development/current/main/phase33-20-loop-exit-semantics.md
nyash-codex 4e32a803a7 feat(joinir): Phase 33-22 CommonPatternInitializer & JoinIRConversionPipeline integration
Unifies initialization and conversion logic across all 4 loop patterns,
eliminating code duplication and establishing single source of truth.

## Changes

### Infrastructure (New)
- CommonPatternInitializer (117 lines): Unified loop var extraction + CarrierInfo building
- JoinIRConversionPipeline (127 lines): Unified JoinIR→MIR→Merge flow

### Pattern Refactoring
- Pattern 1: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 2: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 3: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 4: Uses CommonPatternInitializer + JoinIRConversionPipeline (-40 lines)

### Code Reduction
- Total reduction: ~115 lines across all patterns
- Zero code duplication in initialization/conversion
- Pattern files: 806 lines total (down from ~920)

### Quality Improvements
- Single source of truth for initialization
- Consistent conversion flow across all patterns
- Guaranteed boundary.loop_var_name setting (prevents SSA-undef bugs)
- Improved maintainability and testability

### Testing
- All 4 patterns tested and passing:
  - Pattern 1 (Simple While): 
  - Pattern 2 (With Break): 
  - Pattern 3 (If-Else PHI): 
  - Pattern 4 (With Continue): 

### Documentation
- Phase 33-22 inventory and results document
- Updated joinir-architecture-overview.md with new infrastructure

## Breaking Changes
None - pure refactoring with no API changes

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-07 21:02:20 +09:00

144 lines
5.7 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.

今後は continue 系と JsonParserBox のような実アプリ側ロジックを順番に乗せていく段階に入る。**
# Phase 3320: Loop Exit Semantics Fix — Completion Summary
日付: 20251207
状態: ✅ 実装完了Pattern1/2/3/4 正常、複雑 continue パターンのみ残課題)
---
## 1. ゴール
LoopBuilder 完全削除後の JoinIR ループラインにおいて、
- loop header PHI
- ExitLineExitMeta/ExitBinding/ExitLineReconnector
- JoinInlineBoundary + BoundaryInjector
のあいだで「ループ出口値expr + carrier」の意味論を揃え、
- SSAundef を起こさない
- Pattern1/2/3/4 代表ケースでループ終了時の値が正しく戻ってくる
状態にすること。
---
## 2. 変更内容
### 2.1 BoundaryInjector の修正loop_var_name 対応)
ファイル: `src/mir/builder/joinir_inline_boundary_injector.rs`
問題:
- loop header PHI の `dst`ループ変数の現在値に対して、BoundaryInjector が entry block で Copy を挿し、
header PHI の意味を上書きしてしまうケースがあった。
修正:
- `JoinInlineBoundary.loop_var_name` が設定されている場合は、
**すべての `join_inputs` について entry block での Copy 挿入をスキップ**するように変更。
- これにより、header PHI で決まった `dst` が entry の Copy で壊されることがなくなり、
header PHI が「ループ変数の SSOT」として機能するようになった。
### 2.2 Pattern3(IfElse PHI) の Boundary 設定
ファイル: `src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs`
問題:
- Pattern3 lowerer が JoinInlineBoundary に `loop_var_name` を設定しておらず、
BoundaryInjector/InstructionRewriter が「このループに expr/キャリア出口がある」ことを認識できていなかった。
修正:
- Pattern2 と同様に、Pattern3 でも `boundary.loop_var_name = Some(..)` を設定。
- これにより、JoinIR merge 時に header PHI / exit PHI のラインが Pattern3 でも有効になる。
### 2.3 merge/mod.rs — LoopHeader PHI + carrier PHI の連携
ファイル: `src/mir/builder/control_flow/joinir/merge/mod.rs`
修正ポイント:
1. ExitLine 側から header PHI に必要な carrier 名一覧(`other_carriers`)を抽出し、
LoopHeaderPhiBuilder に渡すように変更。
2. LoopHeaderPhiBuilder が生成した header PHI の `dst`carrier_phisを、
LoopExitBinding/ExitLineReconnector が利用するように接続。
3. function_params のキーを `"join_func_0"`, `"join_func_1"` 等の実際の JoinIR 関数名に合わせるよう修正
(誤って `"main"`, `"loop_step"` を参照していたため Pattern4 で PHI が正しく構築されていなかった)。
これにより、
- header PHI `dst` を起点に、carrier 用の出口値が ExitLine へ正しく流れるようになった。
### 2.4 instruction_rewriter.rs — header PHI への Copy スキップlatch incoming 設定
ファイル: `src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs`
修正内容:
- LoopHeader PHI の `dst` に対して、余計な Copy が挿入されないようにするガードを追加。
- 複数キャリアのケースで、latch block からの incoming を header PHI の入力として正しく構成するよう調整。
これにより、
- Pattern1/2/3/4 のループ変数が header PHI → exit PHI → variable_map の順で一貫して伝播するようになった。
---
## 3. テスト結果
### 3.1 Pattern1: Simple While
- テスト: `apps/tests/loop_min_while.hako`
- 期待値: `0, 1, 2` を出力し、RC は 0。
- 結果: ✅ 期待どおり。
### 3.2 Pattern2: Loop with Breakexpr ループ)
- テスト: `apps/tests/joinir_min_loop.hako`
- 期待値: ループ終了時の `i` の値2が expr result として返る。
- 結果: ✅ RC: 2、SSAundef なし。
### 3.3 Pattern3: Loop with IfElse PHI
- テスト: `apps/tests/loop_if_phi.hako`
- 期待値: `sum = 9`1+3+5
- 結果: ✅ `sum = 9` を出力、RC も期待どおり。
### 3.4 Pattern4: Loop with Continue
- テスト: `apps/tests/loop_continue_pattern4.hako`
- 期待値: 251+3+5+7+9
- 結果: ✅ 出力は 25。
- `[joinir/freeze]` / SSAundef は発生しない。
- function_params キーの誤参照(`"main"/"loop_step"``"join_func_0"/"join_func_1"`) を修正したことで、
header PHI / ExitLine との結線が正しくなり、Pattern4 の単純 continue ケースでも期待どおりの値になった。
---
## 4. まとめと今後
### 達成点
- header PHI を起点とした Loop exit の意味論が Pattern1〜4 の代表ケースで一貫するようになった。
- ExitLinecarrierと expr PHI ラインが、LoopBuilder なしの JoinIR パイプラインで安全に動く。
- trim や JsonParser のような複雑なループに対しても、基盤として使える出口経路が整った。
### 残課題
- 「else 側 continue」を含む複雑な continue パターンPhase 3318 の Pattern Bはまだ JoinIR 側で正規化されていない。
- これらは BoolExprLowerer/ContinueBranchNormalizer で `if (!cond) { … }` 形に正規化し、
Pattern4 lowerer に統合する計画Phase 3319 以降)。
### 関連フェーズ
- Phase 3316: Loop header PHI SSOT 導入
- Phase 3319: Continue + if/else パターンの正規化(設計済み)
- Phase 170: JsonParserBox / trim の JoinIR 準備ライン
このフェーズで「LoopBuilder 無しの JoinIR ループ出口ラインの基礎」は固まったので、
今後は continue 系と JsonParserBox のような実アプリ側ロジックを順番に乗せていく段階に入る。**