Files
hakorune/src/tests/mir_phi_basic_verify.rs
nyash-codex f74b7d2b04 📦 Hotfix 1 & 2: Parameter ValueId Reservation + Exit PHI Validation (Box-First Theory)
**箱理論に基づく根治的修正**:

## 🎯 Hotfix 1: Parameter ValueId Reservation (パラメータ ValueId 予約)

### 根本原因
- MirFunction counter が params.len() を考慮していなかった
- local variables が parameter ValueIds を上書き

### 箱理論的解決
1. **LoopFormContext Box**
   - パラメータ予約を明示的に管理
   - 境界をはっきりさせる

2. **MirFunction::new() 改善**
   - `initial_counter = param_count.max(1)` でパラメータ予約
   - Parameters are %0, %1, ..., %N-1

3. **ensure_counter_after() 強化**
   - パラメータ数 + 既存 ValueIds 両方を考慮
   - `min_counter = param_count.max(max_id + 1)`

4. **reserve_parameter_value_ids() 追加**
   - 明示的な予約メソッド(Box-First)

## 🎯 Hotfix 2: Exit PHI Predecessor Validation (Exit PHI 検証)

### 根本原因
- LoopForm builder が存在しないブロックを PHI predecessor に追加
- 「幽霊ブロック」問題

### 箱理論的解決
1. **LoopFormOps.block_exists() 追加**
   - CFG 存在確認メソッド
   - 境界を明確化

2. **build_exit_phis() 検証**
   - 非存在ブロックをスキップ
   - デバッグログ付き

### 実装ファイル
- `src/mir/function.rs`: Parameter reservation
- `src/mir/phi_core/loopform_builder.rs`: Context + validation
- `src/mir/loop_builder.rs`: LoopFormOps impl
- `src/mir/builder/stmts.rs`: Local variable allocation

### 業界標準準拠
-  LLVM IR: Parameters are %0, %1, ...
-  SSA Form: PHI predecessors must exist in CFG
-  Cytron et al. (1991): Parameter reservation principle

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 06:39:45 +09:00

86 lines
2.6 KiB
Rust

use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
use crate::mir::{MirCompiler, MirVerifier};
fn lit_i(i: i64) -> ASTNode {
ASTNode::Literal {
value: LiteralValue::Integer(i),
span: Span::unknown(),
}
}
fn bin(op: BinaryOperator, l: ASTNode, r: ASTNode) -> ASTNode {
ASTNode::BinaryOp {
operator: op,
left: Box::new(l),
right: Box::new(r),
span: Span::unknown(),
}
}
/// Basic PHI/SSA sanity: simple counted loop must verify without Undefined value.
#[test]
fn mir_phi_basic_counted_loop_verifies() {
// i = 0;
// loop (i < 3) {
// i = i + 1;
// }
// return i;
let ast = ASTNode::Program {
statements: vec![
ASTNode::Assignment {
target: Box::new(ASTNode::Variable {
name: "i".into(),
span: Span::unknown(),
}),
value: Box::new(lit_i(0)),
span: Span::unknown(),
},
ASTNode::Loop {
condition: Box::new(bin(
BinaryOperator::LessThan,
ASTNode::Variable {
name: "i".into(),
span: Span::unknown(),
},
lit_i(3),
)),
body: vec![ASTNode::Assignment {
target: Box::new(ASTNode::Variable {
name: "i".into(),
span: Span::unknown(),
}),
value: Box::new(bin(
BinaryOperator::Add,
ASTNode::Variable {
name: "i".into(),
span: Span::unknown(),
},
lit_i(1),
)),
span: Span::unknown(),
}],
span: Span::unknown(),
},
ASTNode::Return {
value: Some(Box::new(ASTNode::Variable {
name: "i".into(),
span: Span::unknown(),
})),
span: Span::unknown(),
},
],
span: Span::unknown(),
};
let mut mc = MirCompiler::with_options(false);
let cr = mc.compile(ast).expect("compile");
let mut verifier = MirVerifier::new();
if let Err(errors) = verifier.verify_module(&cr.module) {
for e in &errors {
eprintln!("[rust-mir-verify] {}", e);
}
panic!("MIR verification failed for basic counted loop");
}
}