feat(phase276-p0): Quick Win improvements - type helper SSOT + debug cleanup
Phase 276 P0 post-Phase 275 robustness improvements: 1. Debug cleanup (wiring.py L100-103): - Remove traceback.format_stack() output - Cleaner debug logs after Phase 275 completion 2. box_from_f64 usage investigation: - Confirmed ZERO usage (Rust/Python/MIR) - Ready for deletion (Phase 275 unboxed double SSOT) - crates/nyash_kernel/src/lib.rs L244-252, L971-982 3. Type resolution SSOT (⭐ most important): - New file: src/llvm_py/phi_wiring/type_helper.py (72 lines) - Unified 3 duplicate logic sites: * tagging.py: inst.get("dst_type") → type_helper.get_phi_dst_type() * llvm_builder.py: 9 lines → 2 lines (-7) * wiring.py: 18 lines → 5 lines (-13) - Priority: MIR JSON dst_type > resolver.value_types - Benefits: SSOT principle, bug prevention, easy extension 4. Type mismatch warning enhancement (wiring.py L63-79): - CRITICAL warning for predeclared PHI type mismatch - PhiManager.invalidate_phi() notification - Early bug detection with ⚠️ marker Effects: - Type resolution logic: 3 sites → 1 SSOT (type_helper.py) - Code reduction: -20 lines duplicate logic - Robustness: SSOT principle, CRITICAL warnings, Fail-Fast - Debuggability: cleaner logs, prominent type mismatch alerts Testing: - LLVM harness: exit=3 verified (/tmp/test_p275_debug2.hako) - NYASH_PHI_TYPE_DEBUG=1: correct type resolution confirmed Docs: - Phase 276 P0 completion: docs/.../phase-276/P0-COMPLETION.md - 10-Now.md: Phase 276 P0 ✅, Phase 275 P0 completed section Next steps (Phase 277 P0 recommended): - Delete box_from_f64 (nyash.box.from_f64, nyash.float.box_from_f64) - Adopt dst_type_to_llvm_type() helper 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -652,15 +652,9 @@ class NyashLLVMBuilder:
|
||||
trace_phi_json({"phi": "finalize_dst", "block": int(block_id), "dst": int(dst_vid), "incoming": [(int(v), int(b)) for (b, v) in [(b, v) for (v, b) in (incoming or [])]]})
|
||||
except Exception:
|
||||
pass
|
||||
# Phase 275 P0: Get dst_type from resolver's value_types
|
||||
dst_type = None
|
||||
try:
|
||||
if hasattr(self, 'resolver') and hasattr(self.resolver, 'value_types'):
|
||||
vt = self.resolver.value_types.get(int(dst_vid))
|
||||
if vt == 'f64' or (isinstance(vt, dict) and vt.get('type') == 'f64'):
|
||||
dst_type = 'f64'
|
||||
except Exception:
|
||||
pass
|
||||
# Phase 275 P0: Get dst_type from resolver's value_types (SSOT)
|
||||
from phi_wiring.type_helper import get_phi_dst_type
|
||||
dst_type = get_phi_dst_type(self, dst_vid)
|
||||
# Ensure placeholder exists at block head with common helper
|
||||
phi = _ensure_phi(self, int(block_id), int(dst_vid), bb, dst_type=dst_type)
|
||||
self.vmap[int(dst_vid)] = phi
|
||||
|
||||
@ -76,8 +76,9 @@ def setup_phi_placeholders(builder, blocks: List[Dict[str, Any]]):
|
||||
# mid-block users (e.g., compare/branch) dominate correctly
|
||||
# and refer to the same SSA node that finalize_phis() will wire.
|
||||
try:
|
||||
# Phase 275 P0: Get dst_type from instruction JSON
|
||||
dst_type = inst.get("dst_type")
|
||||
# Phase 275 P0: Get dst_type from instruction JSON (SSOT)
|
||||
from .type_helper import get_phi_dst_type
|
||||
dst_type = get_phi_dst_type(builder, dst0, inst=inst)
|
||||
ph = ensure_phi(builder, bid0, dst0, bb0, dst_type=dst_type)
|
||||
# Keep a strong reference as a predeclared placeholder so
|
||||
# later ensure_phi calls during finalize re-use the same SSA node.
|
||||
|
||||
72
src/llvm_py/phi_wiring/type_helper.py
Normal file
72
src/llvm_py/phi_wiring/type_helper.py
Normal file
@ -0,0 +1,72 @@
|
||||
"""Phase 275 P0: PHI型取得のSSOT
|
||||
|
||||
PHI dst_type 取得ロジックを統一管理。
|
||||
- 優先度1: MIR JSON instruction の dst_type (最新)
|
||||
- 優先度2: resolver.value_types (型推論後)
|
||||
"""
|
||||
|
||||
def get_phi_dst_type(builder, dst_vid, inst=None):
|
||||
"""PHI destination type を取得
|
||||
|
||||
Args:
|
||||
builder: LLVM builder instance
|
||||
dst_vid: Destination ValueId (int)
|
||||
inst: MIR JSON instruction dict (optional, priority source)
|
||||
|
||||
Returns:
|
||||
str | None: 'f64', 'i64', 'void', etc. (MIR type string)
|
||||
|
||||
Example:
|
||||
>>> dst_type = get_phi_dst_type(builder, 36, inst)
|
||||
>>> if dst_type == 'f64':
|
||||
>>> phi_type = ir.DoubleType()
|
||||
"""
|
||||
# Priority 1: instruction JSON (最新、直接指定)
|
||||
if inst is not None:
|
||||
dst_type = inst.get("dst_type")
|
||||
if dst_type is not None:
|
||||
return dst_type
|
||||
|
||||
# Priority 2: resolver.value_types (型推論結果)
|
||||
try:
|
||||
if hasattr(builder, 'resolver') and hasattr(builder.resolver, 'value_types'):
|
||||
vt = builder.resolver.value_types.get(int(dst_vid))
|
||||
# f64 の場合
|
||||
if vt == 'f64' or (isinstance(vt, dict) and vt.get('type') == 'f64'):
|
||||
return 'f64'
|
||||
# i64 の場合(default)
|
||||
if vt == 'i64' or vt == 'Integer':
|
||||
return 'i64'
|
||||
# void の場合
|
||||
if vt == 'void' or vt == 'Void':
|
||||
return 'void'
|
||||
# Box型の場合
|
||||
if isinstance(vt, dict) and vt.get('kind') == 'handle':
|
||||
return 'handle'
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def dst_type_to_llvm_type(dst_type, builder):
|
||||
"""MIR dst_type を LLVM IR type に変換
|
||||
|
||||
Args:
|
||||
dst_type: str | None (from get_phi_dst_type)
|
||||
builder: LLVM builder (for builder.i64 access)
|
||||
|
||||
Returns:
|
||||
ir.Type: LLVM IR type (DoubleType, IntType, etc.)
|
||||
|
||||
Example:
|
||||
>>> dst_type = get_phi_dst_type(builder, 36, inst)
|
||||
>>> llvm_type = dst_type_to_llvm_type(dst_type, builder)
|
||||
>>> phi = b.phi(llvm_type, name=f"phi_{dst_vid}")
|
||||
"""
|
||||
import llvmlite.ir as ir
|
||||
|
||||
if dst_type == 'f64' or dst_type == 'double':
|
||||
return ir.DoubleType()
|
||||
# デフォルトは i64
|
||||
return builder.i64
|
||||
@ -61,8 +61,22 @@ def ensure_phi(builder, block_id: int, dst_vid: int, bb: ir.Block, dst_type=None
|
||||
print(f"[phi_wiring/reuse] v{dst_vid} predeclared PHI type matches: {phi.type}", file=sys.stderr)
|
||||
return phi
|
||||
else:
|
||||
# Phase 275 P0: 型不一致の古いPHIを発見 → CRITICAL警告
|
||||
import sys
|
||||
print(f"⚠️ [phi_wiring/CRITICAL] PHI type mismatch! "
|
||||
f"v{dst_vid}: predeclared={phi.type} expected={expected_type}",
|
||||
file=sys.stderr)
|
||||
|
||||
# PhiManager に古いPHI無効化を通知(あれば)
|
||||
try:
|
||||
if hasattr(builder, 'phi_manager'):
|
||||
builder.phi_manager.invalidate_phi(int(block_id), int(dst_vid))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 詳細デバッグ
|
||||
if os.environ.get('NYASH_PHI_TYPE_DEBUG') == '1':
|
||||
print(f"[phi_wiring/type_mismatch] v{dst_vid} predeclared PHI type {phi.type} != expected {expected_type}, creating new", file=sys.stderr)
|
||||
print(f"[phi_wiring/type_mismatch] Creating new PHI with correct type", file=sys.stderr)
|
||||
|
||||
# Phase 132 Critical Fix: Check if block already has a terminator
|
||||
# If so, we're trying to add PHI too late - this is a bug
|
||||
@ -106,10 +120,7 @@ def ensure_phi(builder, block_id: int, dst_vid: int, bb: ir.Block, dst_type=None
|
||||
|
||||
import os, sys
|
||||
if os.environ.get('NYASH_PHI_TYPE_DEBUG') == '1':
|
||||
import traceback
|
||||
stack = ''.join(traceback.format_stack()[-4:-1]) # Last 3 frames before ensure_phi
|
||||
print(f"[phi_wiring/create] v{dst_vid} dst_type={dst_type} -> phi_type={phi_type}", file=sys.stderr)
|
||||
print(f"[phi_wiring/stack]\n{stack}", file=sys.stderr)
|
||||
|
||||
ph = b.phi(phi_type, name=f"phi_{dst_vid}")
|
||||
# Phase 132 Debug: Check if basic_block is set correctly
|
||||
@ -224,22 +235,12 @@ def wire_incomings(builder, block_id: int, dst_vid: int, incoming: List[Tuple[in
|
||||
except Exception:
|
||||
phi = None
|
||||
if phi is None:
|
||||
# Phase 275 P0: Get dst_type from resolver's value_types
|
||||
dst_type = None
|
||||
try:
|
||||
if hasattr(builder, 'resolver') and hasattr(builder.resolver, 'value_types'):
|
||||
vt = builder.resolver.value_types.get(int(dst_vid))
|
||||
import os, sys
|
||||
if os.environ.get('NYASH_PHI_TYPE_DEBUG') == '1':
|
||||
print(f"[phi_wiring] v{dst_vid} value_types: {vt}", file=sys.stderr)
|
||||
if vt == 'f64' or (isinstance(vt, dict) and vt.get('type') == 'f64'):
|
||||
dst_type = 'f64'
|
||||
if os.environ.get('NYASH_PHI_TYPE_DEBUG') == '1':
|
||||
print(f"[phi_wiring] v{dst_vid} -> dst_type='f64'", file=sys.stderr)
|
||||
except Exception as e:
|
||||
import os, sys
|
||||
if os.environ.get('NYASH_PHI_TYPE_DEBUG') == '1':
|
||||
print(f"[phi_wiring] v{dst_vid} exception: {e}", file=sys.stderr)
|
||||
# Phase 275 P0: Get dst_type from resolver's value_types (SSOT)
|
||||
from .type_helper import get_phi_dst_type
|
||||
dst_type = get_phi_dst_type(builder, dst_vid)
|
||||
import os, sys
|
||||
if os.environ.get('NYASH_PHI_TYPE_DEBUG') == '1':
|
||||
print(f"[phi_wiring] v{dst_vid} -> dst_type='{dst_type}'", file=sys.stderr)
|
||||
phi = ensure_phi(builder, block_id, dst_vid, bb, dst_type=dst_type)
|
||||
preds_raw = [p for p in builder.preds.get(block_id, []) if p != block_id]
|
||||
seen = set()
|
||||
|
||||
Reference in New Issue
Block a user