feat(llvm/phi): Phase 277 P1.5 - structured error handling + import organization
## Changes - P1.5.1: import整理 - debug_helper imports をモジュールトップへ移動 - P1.5.2: PhiStrictError 箱化 - エラーハンドリング構造化 (error_helpers.py新規) - P1.5.3: wiring.py で PhiStrictError を使用 - 3箇所のエラーパターン統一 ## Benefits - ✅ エラーメッセージ生成の一元化(SSOT化) - ✅ Python import 慣習準拠(関数内import削除) - ✅ エラーコンテキスト構造化(block_id/dst_vid/next_file) ## Testing ✅ strict=OFF - passes without errors ✅ strict=ON - passes without errors ✅ debug mode - verification connected and running 🤖 Generated with Claude Code Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -2,9 +2,6 @@
|
||||
|
||||
## Current Focus (next)
|
||||
|
||||
- Phase 277 P0/P1(docs+validation): `docs/development/current/main/phases/phase-277/README.md`
|
||||
- PHI型推論の導線/責務/SSOT を docs に固定(Phase 275/276 の実装を「読める形」にする)
|
||||
- PHI順序(PHI → non-PHI → terminator)検証の fail-fast を強化
|
||||
- Phase 278(cleanup): `docs/development/current/main/phases/phase-278/README.md`
|
||||
- Phase 277 P2 の後方互換(旧PHI env var)を撤去して、1セットに収束させる
|
||||
- Phase 279(impl): `docs/development/current/main/phases/phase-279/README.md`
|
||||
@ -16,6 +13,7 @@
|
||||
|
||||
- Phase 275 P0(A1/B2/C2 coercion SSOT): `docs/development/current/main/phases/phase-275/README.md`
|
||||
- Phase 276 P0(quick wins / type_helper SSOT): `docs/development/current/main/phases/phase-276/README.md`
|
||||
- Phase 277 P1(PHI strict fail-fast): `docs/development/current/main/phases/phase-277/README.md`
|
||||
- Phase 277 P2(PHI env var 統合): `docs/development/current/main/phases/phase-277/README.md`
|
||||
|
||||
---
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
# Phase 277 P1: PHI順序検証強化(fail-fast)— 完了報告
|
||||
|
||||
Status: ✅ completed (2025-12-22)
|
||||
|
||||
Goal:
|
||||
- strict mode(`NYASH_LLVM_PHI_STRICT=1`)で、PHI順序/配線失敗を “原因箇所で止める” ようにする。
|
||||
|
||||
Scope:
|
||||
- LLVM harness(Python)側のみ
|
||||
- 新しい環境変数は追加しない(Phase 277 P2 で統合した3つのみ)
|
||||
- JoinIR/Rust側のパイプライン統一は対象外(根治は Phase 279)
|
||||
|
||||
---
|
||||
|
||||
## Changes
|
||||
|
||||
### 1) PHI created after terminator を strict で fail-fast
|
||||
|
||||
Target:
|
||||
- `src/llvm_py/phi_wiring/wiring.py`(`ensure_phi`)
|
||||
|
||||
Behavior:
|
||||
- strict=ON: RuntimeError(block_id/dst_vid を含む)
|
||||
- strict=OFF: warning のみ(既定挙動維持)
|
||||
|
||||
### 2) PHI incoming 解決の “silent fallback 0” を strict で禁止
|
||||
|
||||
Target:
|
||||
- `src/llvm_py/phi_wiring/wiring.py`(`wire_incomings`)
|
||||
|
||||
Behavior:
|
||||
- strict=ON: “incoming unresolved / type coercion failed” を RuntimeError
|
||||
- strict=OFF: 従来どおり 0 fallback(互換維持)
|
||||
|
||||
### 3) PHI ordering verifier を実行導線に接続
|
||||
|
||||
Target:
|
||||
- `src/llvm_py/builders/function_lower.py`
|
||||
- `src/llvm_py/phi_placement.py::verify_phi_ordering`
|
||||
|
||||
Behavior:
|
||||
- strict=ON: ordering NG を RuntimeError(block list を含む)
|
||||
- debug=ON: ordering のサマリを stderr に出力
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
- strict=OFF: 既存 fixture が退行しないことを確認
|
||||
- strict=ON: 既存 fixture が正常系として PASS(違反がないことを確認)
|
||||
- debug=ON: verify の接続がログで確認できることを確認
|
||||
|
||||
---
|
||||
|
||||
## Notes / Next
|
||||
|
||||
- 旧 env var の後方互換性削除は Phase 278。
|
||||
- “2本のコンパイラ(型伝播パイプライン差)” 根治は Phase 279。
|
||||
@ -29,7 +29,7 @@ Phase 275/276で完了したFloat型PHI対応・型取得SSOT化の後続改善
|
||||
- 指示書(Claude Code):
|
||||
- `docs/development/current/main/phases/phase-277/P0-INSTRUCTIONS.md`
|
||||
|
||||
### Phase 277 P1: PHI順序検証強化(予定)
|
||||
### Phase 277 P1: PHI順序検証強化(fail-fast) ✅
|
||||
|
||||
- 目的: PHI命令の配置順序検証を強化
|
||||
- 内容:
|
||||
@ -40,6 +40,8 @@ Phase 275/276で完了したFloat型PHI対応・型取得SSOT化の後続改善
|
||||
- `docs/development/current/main/phases/phase-277/P1-VALIDATION.md`
|
||||
- 指示書(Claude Code):
|
||||
- `docs/development/current/main/phases/phase-277/P1-INSTRUCTIONS.md`
|
||||
- 完了報告:
|
||||
- `docs/development/current/main/phases/phase-277/P1-COMPLETION.md`
|
||||
|
||||
### Phase 277 P2: PHI関連環境変数の統合・整理 ✅
|
||||
|
||||
@ -91,9 +93,12 @@ NYASH_LLVM_PHI_STRICT=1
|
||||
```
|
||||
phase-277/
|
||||
├── README.md # 本ファイル(Phase 277概要)
|
||||
├── P0-INSTRUCTIONS.md # P0指示書(Claude Code)
|
||||
├── P2-COMPLETION.md # P2完了報告
|
||||
├── P0-DESIGN.md # P0設計ドキュメント(docs)
|
||||
└── P1-VALIDATION.md # P1検証強化ドキュメント(validation)
|
||||
├── P1-INSTRUCTIONS.md # P1指示書(Claude Code)
|
||||
├── P1-VALIDATION.md # P1検証強化ドキュメント(validation)
|
||||
└── P1-COMPLETION.md # P1完了報告
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
61
src/llvm_py/phi_wiring/error_helpers.py
Normal file
61
src/llvm_py/phi_wiring/error_helpers.py
Normal file
@ -0,0 +1,61 @@
|
||||
# Phase 277 P1.5: Structured error handling for PHI strict mode
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class PhiStrictError:
|
||||
"""Structured error for PHI strict mode violations.
|
||||
|
||||
Phase 277 P1.5: Central error handling for all PHI strict violations.
|
||||
"""
|
||||
message: str
|
||||
next_file: str
|
||||
block_id: Optional[int] = None
|
||||
dst_vid: Optional[int] = None
|
||||
context: Optional[str] = None
|
||||
|
||||
def raise_if_strict(self):
|
||||
"""Raise RuntimeError if strict mode enabled."""
|
||||
from .debug_helper import is_phi_strict_enabled
|
||||
import sys
|
||||
|
||||
if is_phi_strict_enabled():
|
||||
print(f"[CRITICAL] {self.message}", file=sys.stderr)
|
||||
if self.context:
|
||||
print(f" Context: {self.context}", file=sys.stderr)
|
||||
print(f" → Next file: {self.next_file}", file=sys.stderr)
|
||||
raise RuntimeError(self.message)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PhiDebugMessage:
|
||||
"""Structured debug message for PHI operations.
|
||||
|
||||
Phase 277 P1.5: Centralize debug output formatting.
|
||||
"""
|
||||
level: str # "DEBUG", "WARNING", "INFO"
|
||||
component: str # e.g., "phi_wiring", "ensure_phi"
|
||||
message: str
|
||||
block_id: Optional[int] = None
|
||||
dst_vid: Optional[int] = None
|
||||
|
||||
def print_if_enabled(self):
|
||||
"""Print if appropriate debug mode enabled."""
|
||||
from .debug_helper import is_phi_debug_enabled
|
||||
import sys
|
||||
|
||||
if is_phi_debug_enabled():
|
||||
prefix = f"[{self.component}]" if self.component else "[phi]"
|
||||
full_msg = f"{prefix} {self.message}"
|
||||
if self.block_id is not None or self.dst_vid is not None:
|
||||
context = ""
|
||||
if self.block_id is not None:
|
||||
context += f"bb{self.block_id}"
|
||||
if self.dst_vid is not None:
|
||||
if context:
|
||||
context += " "
|
||||
context += f"v{self.dst_vid}"
|
||||
full_msg += f" ({context})"
|
||||
print(f"{full_msg}", file=sys.stderr)
|
||||
@ -4,7 +4,12 @@ from typing import Dict, List, Any, Optional, Tuple
|
||||
import llvmlite.ir as ir
|
||||
|
||||
from .common import trace
|
||||
from .debug_helper import is_phi_debug_enabled, is_phi_trace_enabled
|
||||
from .debug_helper import (
|
||||
is_phi_debug_enabled,
|
||||
is_phi_strict_enabled,
|
||||
is_phi_trace_enabled,
|
||||
)
|
||||
from .error_helpers import PhiStrictError, PhiDebugMessage
|
||||
|
||||
def _const_i64(builder, n: int) -> ir.Constant:
|
||||
try:
|
||||
@ -22,9 +27,6 @@ def ensure_phi(builder, block_id: int, dst_vid: int, bb: ir.Block, dst_type=None
|
||||
|
||||
Phase 275 P0: Support Float type PHIs (double) based on dst_type from MIR JSON.
|
||||
"""
|
||||
# Phase 277 P1: Import debug helpers at function scope
|
||||
from .debug_helper import is_phi_debug_enabled, is_phi_strict_enabled, is_phi_trace_enabled
|
||||
|
||||
# Always place PHI at block start to keep LLVM invariant "PHI nodes at top"
|
||||
|
||||
# Check if PHI already exists in vmap for this block
|
||||
@ -92,19 +94,18 @@ def ensure_phi(builder, block_id: int, dst_vid: int, bb: ir.Block, dst_type=None
|
||||
|
||||
if block_has_terminator:
|
||||
# This should not happen - PHIs must be created before terminators
|
||||
import sys
|
||||
msg = (f"[phi_wiring/CRITICAL] PHI v{dst_vid} created after terminator in bb{block_id}! "
|
||||
f"This violates LLVM IR PHI-first invariant.")
|
||||
|
||||
# Phase 277 P1: Fail-fast in strict mode
|
||||
if is_phi_strict_enabled():
|
||||
print(msg, file=sys.stderr)
|
||||
print(f" → Next file to check: phi_placement.py::verify_phi_ordering", file=sys.stderr)
|
||||
raise RuntimeError(msg)
|
||||
error = PhiStrictError(
|
||||
message=f"PHI v{dst_vid} created after terminator in bb{block_id}! This violates LLVM IR PHI-first invariant.",
|
||||
next_file="phi_placement.py::verify_phi_ordering",
|
||||
block_id=block_id,
|
||||
dst_vid=dst_vid,
|
||||
)
|
||||
error.raise_if_strict()
|
||||
|
||||
# Default: warning only (preserve existing behavior)
|
||||
if is_phi_debug_enabled():
|
||||
print(f"[phi_wiring] WARNING: {msg}", file=sys.stderr)
|
||||
import sys
|
||||
print(f"[phi_wiring] WARNING: {error.message}", file=sys.stderr)
|
||||
# Try to create PHI anyway at the start, but log the issue
|
||||
|
||||
# Create PHI at block start
|
||||
@ -306,15 +307,14 @@ def wire_incomings(builder, block_id: int, dst_vid: int, incoming: List[Tuple[in
|
||||
resolved_ok = val is not None
|
||||
# Phase 277 P1: Strict mode forbids silent fallback to 0
|
||||
if val is None:
|
||||
from .debug_helper import is_phi_strict_enabled
|
||||
if is_phi_strict_enabled():
|
||||
import sys
|
||||
msg = (f"[phi_wiring/CRITICAL] PHI v{dst_vid} incoming from bb{pred_match} "
|
||||
f"could not be resolved (vs={vs}). "
|
||||
f"Silent fallback to 0 is forbidden in strict mode.")
|
||||
print(msg, file=sys.stderr)
|
||||
print(f" → Next file: llvm_builder.py::_value_at_end_i64 (value resolution)", file=sys.stderr)
|
||||
raise RuntimeError(msg)
|
||||
error = PhiStrictError(
|
||||
message=f"PHI v{dst_vid} incoming from bb{pred_match} could not be resolved (vs={vs}). Silent fallback to 0 is forbidden in strict mode.",
|
||||
next_file="llvm_builder.py::_value_at_end_i64",
|
||||
block_id=block_id,
|
||||
dst_vid=dst_vid,
|
||||
context=f"pred={pred_match}",
|
||||
)
|
||||
error.raise_if_strict()
|
||||
# Default: silent fallback (existing behavior)
|
||||
val = _const_i64(builder, 0)
|
||||
else:
|
||||
@ -323,13 +323,13 @@ def wire_incomings(builder, block_id: int, dst_vid: int, incoming: List[Tuple[in
|
||||
if not hasattr(val, 'type'):
|
||||
val = _const_i64(builder, int(val))
|
||||
except Exception as e:
|
||||
from .debug_helper import is_phi_strict_enabled
|
||||
if is_phi_strict_enabled():
|
||||
import sys
|
||||
msg = (f"[phi_wiring/CRITICAL] PHI v{dst_vid} incoming type coercion failed "
|
||||
f"(vs={vs}, pred={pred_match}): {e}")
|
||||
print(msg, file=sys.stderr)
|
||||
raise RuntimeError(msg)
|
||||
error = PhiStrictError(
|
||||
message=f"PHI v{dst_vid} incoming type coercion failed (vs={vs}, pred={pred_match}): {e}",
|
||||
next_file="phi_wiring.py::get_phi_operand_type",
|
||||
block_id=block_id,
|
||||
dst_vid=dst_vid,
|
||||
)
|
||||
error.raise_if_strict()
|
||||
# Default: silent fallback (existing behavior)
|
||||
val = _const_i64(builder, 0)
|
||||
# SSOT for ambiguous PHI incoming (same pred_match multiple times):
|
||||
|
||||
Reference in New Issue
Block a user