feat(llvm): Phase 131-11-H/12 - ループキャリアPHI型修正 & vmap snapshot SSOT

## Phase 131-11-H: ループキャリアPHI型修正
- PHI生成時に初期値(entry block)の型のみ使用
- backedge の値を型推論に使わない(循環依存回避)
- NYASH_CARRIER_PHI_DEBUG=1 でトレース

## Phase 131-12-P0: def_blocks 登録 & STRICT エラー化
- safe_vmap_write() で PHI 上書き保護
- resolver miss を STRICT でエラー化(フォールバック 0 禁止)
- def_blocks 自動登録

## Phase 131-12-P1: vmap_cur スナップショット実装
- DeferredTerminator 構造体(block, term_ops, vmap_snapshot)
- Pass A で vmap_cur をスナップショット
- Pass C でスナップショット復元(try-finally)
- STRICT モード assert

## 結果
-  MIR PHI型: Integer(正しい)
-  VM: Result: 3
-  vmap snapshot 機構: 動作確認
- ⚠️ LLVM: Result: 0(別のバグ、次Phase で調査)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-14 21:28:41 +09:00
parent 413504d6de
commit 7dfd6ff1d9
21 changed files with 1391 additions and 133 deletions

View File

@ -88,7 +88,20 @@ class Resolver:
Creates PHI at block start if needed, caches the result.
"""
cache_key = (current_block.name, value_id)
import os
if os.environ.get('NYASH_LLVM_PHI_DEBUG') == '1':
try:
bid = int(str(current_block.name).replace('bb',''))
in_def_blocks = value_id in self.def_blocks
if in_def_blocks:
def_in_blocks = list(self.def_blocks.get(value_id, set()))
else:
def_in_blocks = []
trace_phi(f"[resolve_i64/entry] bb{bid} v{value_id} in_def_blocks={in_def_blocks} def_in={def_in_blocks}")
except Exception as e:
trace_phi(f"[resolve_i64/entry] ERROR: {e}")
# Check cache
if cache_key in self.i64_cache:
return self.i64_cache[cache_key]
@ -158,10 +171,18 @@ class Resolver:
defined_here = False
if defined_here:
existing = vmap.get(value_id)
import os
if os.environ.get('NYASH_LLVM_PHI_DEBUG') == '1':
existing_type = type(existing).__name__ if existing is not None else "None"
trace_phi(f"[resolve/def_here] bb{bid} v{value_id} existing={existing_type} in vmap={value_id in vmap}")
if existing is not None and hasattr(existing, 'type') and isinstance(existing.type, ir.IntType) and existing.type.width == 64:
trace_values(f"[resolve] local reuse: bb{bid} v{value_id}")
self.i64_cache[cache_key] = existing
return existing
elif existing is not None:
if os.environ.get('NYASH_LLVM_PHI_DEBUG') == '1':
existing_llvm_type = str(existing.type) if hasattr(existing, 'type') else "no_type"
trace_phi(f"[resolve/def_here] bb{bid} v{value_id} existing has wrong type: {existing_llvm_type}")
else:
# Do NOT blindly reuse vmap across blocks: it may reference values defined
# in non-dominating predecessors (e.g., other branches). Only reuse when
@ -235,6 +256,24 @@ class Resolver:
result = placeholder if (placeholder is not None and hasattr(placeholder, 'add_incoming')) else ir.Constant(self.i64, 0)
else:
# No declared PHI and multi-pred: do not synthesize; fallback to zero
import os
if os.environ.get('NYASH_LLVM_STRICT') == '1':
# P0-2: STRICT mode - fail fast on undeclared PHI in multi-pred context
def_blocks_info = "not_in_def_blocks"
try:
if value_id in self.def_blocks:
def_blocks_info = f"def_blocks={sorted(list(self.def_blocks[value_id]))}"
except Exception:
pass
raise RuntimeError(
f"[LLVM_PY/STRICT] Undeclared PHI in multi-pred block:\n"
f" ValueId: {value_id}\n"
f" Block: bb{cur_bid}\n"
f" Predecessors: {pred_ids}\n"
f" {def_blocks_info}\n"
f" Hint: Value needs PHI but not declared in block_phi_incomings"
)
result = ir.Constant(self.i64, 0)
# Cache and return
@ -342,6 +381,31 @@ class Resolver:
preds_s = ','.join(str(x) for x in pred_ids)
trace_phi(f"[resolve] end_i64 miss: bb{block_id} v{value_id} preds=[{preds_s}] → 0")
# P0-2: STRICT mode - fail fast on resolution miss
import os
if os.environ.get('NYASH_LLVM_STRICT') == '1':
# Collect diagnostic information
def_blocks_info = "not_in_def_blocks"
try:
if value_id in self.def_blocks:
def_blocks_info = f"def_blocks={sorted(list(self.def_blocks[value_id]))}"
except Exception:
pass
# Build search path for diagnostics
search_path = [block_id] + pred_ids
raise RuntimeError(
f"[LLVM_PY/STRICT] PHI resolution miss:\n"
f" ValueId: {value_id}\n"
f" Target block: {block_id}\n"
f" Predecessors: [{preds_s}]\n"
f" Search path: {search_path}\n"
f" {def_blocks_info}\n"
f" Hint: PHI dst may not be registered in def_blocks, or dominance issue"
)
z = ir.Constant(self.i64, 0)
self._end_i64_cache[key] = z
return z