feat(llvm): Phase 131-4 P1 完了 - PHI ordering 修正(multi-pass architecture)

Phase 131-4 P1: PHI After Terminator Bug 修正

問題:
- LLVM IR で PHI が terminator の後に出現(LLVM invariant 違反)
- Case B (loop_min_while.hako) が TAG-EMIT で失敗

修正:
- Multi-pass block lowering architecture 実装:
  - Pass A: non-terminator instructions のみ emit
  - Pass B: PHI finalization(block head に確実に配置)
  - Pass C: deferred terminators を最後に emit

変更ファイル:
- src/llvm_py/builders/block_lower.py (~40行):
  - lower_blocks() で terminator を defer
  - lower_terminators() 新設(Pass C)
  - _deferred_terminators dict で管理
- src/llvm_py/builders/function_lower.py (3行):
  - Pass 順序更新: A→B→C
- src/llvm_py/instructions/ret.py (5行):
  - _disable_phi_synthesis flag で Pass C 中の PHI 生成を抑制

テスト結果:
- Case B EMIT:  (修正成功)
- Case B LINK:  (新 TAG-LINK: undefined nyash_console_log)
- Case A/B2:  (退行なし)

箱化モジュール化:
-  Multi-pass で責務分離
-  Flag mechanism で構造的制御
-  ハードコード禁止原則遵守

Next: Phase 131-5 (TAG-LINK 修正)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-14 06:12:31 +09:00
parent 5709026812
commit 73613dcef0
4 changed files with 138 additions and 30 deletions

View File

@ -111,7 +111,11 @@ def lower_return(
ret_val = ir.Constant(return_type, None)
# If still zero-like (typed zero) and we have predecessor snapshots, synthesize a minimal PHI at block head.
# Phase 131-4: Skip PHI synthesis if disabled (e.g., during Pass C terminator lowering)
try:
disable_phi = False
if resolver is not None and hasattr(resolver, '_disable_phi_synthesis'):
disable_phi = getattr(resolver, '_disable_phi_synthesis', False)
zero_like = False
if isinstance(ret_val, ir.Constant):
if isinstance(return_type, ir.IntType):
@ -121,7 +125,7 @@ def lower_return(
elif isinstance(return_type, ir.PointerType):
zero_like = (str(ret_val) == str(ir.Constant(return_type, None)))
# Synthesize a PHI for return at the BLOCK HEAD (grouped), not inline.
if zero_like and preds is not None and block_end_values is not None and bb_map is not None and isinstance(value_id, int):
if not disable_phi and zero_like and preds is not None and block_end_values is not None and bb_map is not None and isinstance(value_id, int):
# Derive current block id from name like 'bb3'
cur_bid = None
try: