diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index c021e71c..f0f81636 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -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` --- diff --git a/docs/development/current/main/phases/phase-277/P1-COMPLETION.md b/docs/development/current/main/phases/phase-277/P1-COMPLETION.md new file mode 100644 index 00000000..07dfe7f9 --- /dev/null +++ b/docs/development/current/main/phases/phase-277/P1-COMPLETION.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。 diff --git a/docs/development/current/main/phases/phase-277/README.md b/docs/development/current/main/phases/phase-277/README.md index 864d80d1..9d442d82 100644 --- a/docs/development/current/main/phases/phase-277/README.md +++ b/docs/development/current/main/phases/phase-277/README.md @@ -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完了報告 ``` --- diff --git a/src/llvm_py/phi_wiring/error_helpers.py b/src/llvm_py/phi_wiring/error_helpers.py new file mode 100644 index 00000000..76dae89e --- /dev/null +++ b/src/llvm_py/phi_wiring/error_helpers.py @@ -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) diff --git a/src/llvm_py/phi_wiring/wiring.py b/src/llvm_py/phi_wiring/wiring.py index dafe50b8..fca103ad 100644 --- a/src/llvm_py/phi_wiring/wiring.py +++ b/src/llvm_py/phi_wiring/wiring.py @@ -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):