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:
@ -5,6 +5,8 @@ Centralize policies like "prefer same-block SSA; otherwise resolve with dominanc
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
import llvmlite.ir as ir
|
||||
import sys
|
||||
import os
|
||||
|
||||
def resolve_i64_strict(
|
||||
resolver,
|
||||
@ -21,19 +23,87 @@ def resolve_i64_strict(
|
||||
- If prefer_local and vmap has a same-block definition, reuse it.
|
||||
- Otherwise, delegate to resolver to localize with PHI/casts as needed.
|
||||
"""
|
||||
import os
|
||||
debug = os.environ.get('NYASH_LLVM_PHI_DEBUG') == '1'
|
||||
|
||||
# Prefer current vmap SSA first (block-local map is passed in vmap)
|
||||
val = vmap.get(value_id)
|
||||
if debug:
|
||||
val_type = type(val).__name__ if val is not None else "None"
|
||||
from trace import phi as trace_phi
|
||||
trace_phi(f"[resolve_i64_strict] v{value_id} vmap={val_type}")
|
||||
if prefer_local and val is not None:
|
||||
if debug:
|
||||
trace_phi(f"[resolve_i64_strict] v{value_id} -> local vmap")
|
||||
return val
|
||||
# If local map misses, try builder-global vmap (e.g., predeclared PHIs)
|
||||
try:
|
||||
if hasattr(resolver, 'global_vmap') and isinstance(resolver.global_vmap, dict):
|
||||
gval = resolver.global_vmap.get(value_id)
|
||||
if gval is not None:
|
||||
if debug:
|
||||
trace_phi(f"[resolve_i64_strict] v{value_id} -> global_vmap")
|
||||
return gval
|
||||
except Exception:
|
||||
pass
|
||||
# Fallback to resolver
|
||||
if resolver is None:
|
||||
if debug:
|
||||
trace_phi(f"[resolve_i64_strict] v{value_id} -> 0 (no resolver)")
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
if debug:
|
||||
trace_phi(f"[resolve_i64_strict] v{value_id} -> resolver.resolve_i64")
|
||||
return resolver.resolve_i64(value_id, current_block, preds, block_end_values, vmap, bb_map)
|
||||
|
||||
def safe_vmap_write(vmap: Dict[int, Any], dst: int, value: Any, context: str = "", resolver=None, block_id: Optional[int] = None) -> None:
|
||||
"""
|
||||
PHI overwrite protection for vmap writes + def_blocks registration (P0-1 unified).
|
||||
|
||||
Implements fail-fast protection against ValueId namespace collisions.
|
||||
|
||||
Args:
|
||||
vmap: Value map to write to
|
||||
dst: Destination ValueId
|
||||
value: LLVM IR value to write
|
||||
context: Context string for error messages (e.g., "const", "binop")
|
||||
resolver: Optional resolver for def_blocks tracking (P0-1)
|
||||
block_id: Optional block ID for def_blocks registration (P0-1)
|
||||
|
||||
Behavior:
|
||||
- STRICT mode (NYASH_LLVM_STRICT=1): Raises error if overwriting PHI
|
||||
- TRACE mode (NYASH_LLVM_TRACE_VMAP=1): Logs warning but skips overwrite
|
||||
- Default: Silently skips PHI overwrite (SSOT: PHI defined once)
|
||||
- P0-1: If resolver and block_id provided, register in def_blocks
|
||||
"""
|
||||
existing = vmap.get(dst)
|
||||
if existing is not None and hasattr(existing, 'add_incoming'):
|
||||
# PHI node detected - overwrite forbidden (SSOT principle)
|
||||
if os.environ.get('NYASH_LLVM_STRICT') == '1':
|
||||
raise RuntimeError(
|
||||
f"[LLVM_PY/{context}] Cannot overwrite PHI dst={dst}. "
|
||||
f"ValueId namespace collision detected. "
|
||||
f"Existing: PHI node, Attempted: {type(value).__name__}"
|
||||
)
|
||||
# STRICT not enabled - warn and skip
|
||||
if os.environ.get('NYASH_LLVM_TRACE_VMAP') == '1':
|
||||
print(f"[vmap/warn] Skipping overwrite of PHI dst={dst} in context={context}", file=sys.stderr)
|
||||
return # Do not overwrite PHI
|
||||
|
||||
# Safe to write
|
||||
vmap[dst] = value
|
||||
|
||||
# Phase 131-12-P1: Trace successful write
|
||||
if os.environ.get('NYASH_LLVM_VMAP_TRACE') == '1':
|
||||
print(f"[vmap/write] dst={dst} written, vmap.keys()={sorted(vmap.keys())[:20]}", file=sys.stderr)
|
||||
|
||||
# P0-1: Register definition in def_blocks for dominance tracking (SSOT for all instructions)
|
||||
if resolver is not None and hasattr(resolver, 'def_blocks'):
|
||||
# Auto-detect block_id from resolver if not provided explicitly
|
||||
bid = block_id
|
||||
if bid is None and hasattr(resolver, 'current_block_id'):
|
||||
bid = resolver.current_block_id
|
||||
|
||||
if bid is not None:
|
||||
resolver.def_blocks.setdefault(dst, set()).add(bid)
|
||||
if os.environ.get('NYASH_LLVM_TRACE_VMAP') == '1':
|
||||
print(f"[vmap/def_blocks] Registered v{dst} in block {bid} (context={context})", file=sys.stderr)
|
||||
|
||||
Reference in New Issue
Block a user