wip(phi): Step 5-5-A body-local PHI修正中 - pred mismatch解決も undefined value発生

🔧 **実装内容**:
- Body-local PHI生成時にpreheader+latch両方の入力を追加
- レガシーsealingコード削除(PHI上書き防止)
- Latch値をvariable mapからlookup(正しいブロックの値使用)

 **成果**:
- PHI pred mismatch エラー解決!(ValueId(712) at BasicBlockId(125))
- 266/267テストPASS(ループ関連ユニットテスト全PASS)

 **新規課題**:
- InvalidValue: undefined ValueId(313)発生
- Body-local変数のHeader PHI生成そのものが誤りの可能性
- Option C設計: BodyLocal変数はHeader PHI不要、Exit PHIのみ

📋 **次のステップ**:
- Task先生に詳細調査依頼(body-local変数の正しい扱い)
- Header PHI生成ロジックの根本見直し検討
This commit is contained in:
nyash-codex
2025-11-20 13:49:55 +09:00
parent 2cdef5432a
commit c8f1cea567

View File

@ -383,6 +383,10 @@ impl<'a> LoopBuilder<'a> {
// Phase 25.1c/k: body-local 変数の PHI 生成
// BreakFinderBox / FuncScannerBox 等で、loop body 内で新規宣言された local 変数が
// loop header に戻った時に undefined になる問題を修正
//
// Step 5-5-A: PHI pred mismatch 根本修正
// - Preheader入力poisonとLatch入力の両方を即座に追加
// - 空PHI生成→後で埋める方式は不完全だったseal_phisが処理しない
let trace_loop_phi = std::env::var("HAKO_LOOP_PHI_TRACE").ok().as_deref() == Some("1");
if trace_loop_phi {
eprintln!("[loop-phi/body-local] Checking for body-local variables");
@ -401,15 +405,36 @@ impl<'a> LoopBuilder<'a> {
eprintln!("[loop-phi/body-local] Found {} body-local variables", body_local_vars.len());
}
// Add PHI nodes for body-local variables at header
for (var_name, _latch_value) in &body_local_vars {
// Step 5-5-A: Add PHI nodes with BOTH inputs (preheader + latch)
for (var_name, _body_value) in &body_local_vars {
if trace_loop_phi {
eprintln!("[loop-phi/body-local] Adding PHI for body-local var: {}", var_name);
}
let phi_id = self.new_value();
// Insert empty PHI at header (will be sealed by seal_phis or later)
// Step 5-5-A: Preheader input is poison (variable doesn't exist yet)
let preheader_poison = self.new_value();
// Emit Const::Poison instruction in preheader block
if let Some(ref mut func) = self.parent_builder.current_function {
if let Some(preheader_block) = func.blocks.get_mut(&preheader_id) {
preheader_block.add_instruction(MirInstruction::Const {
dst: preheader_poison,
value: crate::mir::ConstValue::Null, // Poison semantics
});
}
}
// Step 5-5-A FIX: Get latch value from current variable map
// The variable map was updated at line 374-377 with body_end_vars,
// so looking it up now gives us the correct ValueId for the latch block.
let latch_value = self.get_current_variable_map()
.get(var_name)
.copied()
.unwrap_or(phi_id); // Fallback to phi_id if not found
// Step 5-5-A: Insert PHI with BOTH inputs (preheader poison + latch value)
if let Some(ref mut func) = self.parent_builder.current_function {
if let Some(header_block) = func.blocks.get_mut(&header_id) {
// Find position after existing PHIs
@ -418,7 +443,10 @@ impl<'a> LoopBuilder<'a> {
phi_count,
MirInstruction::Phi {
dst: phi_id,
inputs: vec![], // Empty PHI, will be filled by seal_phis
inputs: vec![
(preheader_id, preheader_poison), // ← Preheader input (poison)
(latch_id, latch_value), // ← Latch input (from variable map)
],
},
);
}
@ -426,10 +454,17 @@ impl<'a> LoopBuilder<'a> {
// Rebind variable to PHI
self.update_variable(var_name.clone(), phi_id);
if trace_loop_phi {
eprintln!(
"[loop-phi/body-local] Created PHI {}: preheader={} (poison), latch={} ({})",
phi_id.0, preheader_poison.0, latch_id.0, latch_value.0
);
}
}
if trace_loop_phi {
eprintln!("[loop-phi/body-local] Added {} body-local PHIs", body_local_vars.len());
eprintln!("[loop-phi/body-local] Added {} body-local PHIs with complete inputs", body_local_vars.len());
}
}
@ -515,57 +550,15 @@ impl<'a> LoopBuilder<'a> {
loopform.seal_phis(self, actual_latch_id, &continue_snaps, &writes)?;
// Step 3: seal body-local PHIs (complete the inputs)
if !body_local_vars.is_empty() {
if trace_loop_phi {
eprintln!("[loop-phi/body-local] Sealing {} body-local PHIs", body_local_vars.len());
}
for (var_name, _) in &body_local_vars {
// Get the PHI we created earlier from current variable map
let current_map = self.get_current_variable_map();
let phi_id = current_map.get(var_name).copied()
.ok_or_else(|| format!("Body-local variable '{}' not found in variable map", var_name))?;
// Build inputs: no preheader input (variable doesn't exist there),
// add latch input and continue inputs
let mut inputs: Vec<(BasicBlockId, ValueId)> = vec![];
// Add latch input
let latch_value = self.get_variable_at_block(var_name, actual_latch_id)
.unwrap_or(phi_id); // Fallback to phi_id if not found
inputs.push((actual_latch_id, latch_value));
// Add continue inputs
for (cid, snapshot) in &continue_snaps {
if let Some(&value) = snapshot.get(var_name) {
inputs.push((*cid, value));
}
}
// Update PHI inputs
if let Some(ref mut func) = self.parent_builder.current_function {
if let Some(header_block) = func.blocks.get_mut(&header_id) {
// Find the PHI instruction for this variable
for instr in &mut header_block.instructions {
if let MirInstruction::Phi { dst, inputs: phi_inputs } = instr {
if *dst == phi_id {
*phi_inputs = inputs.clone();
if trace_loop_phi {
eprintln!("[loop-phi/body-local] Sealed '{}' phi={:?} inputs={:?}",
var_name, phi_id, inputs);
}
break;
}
}
}
}
}
}
if trace_loop_phi {
eprintln!("[loop-phi/body-local] Sealed {} body-local PHIs", body_local_vars.len());
}
}
// Step 5-5-A: REMOVED - PHIs now created complete with both inputs upfront
// Old sealing code was overwriting our preheader+latch inputs with latch-only,
// causing "phi pred mismatch" errors.
//
// Body-local PHIs are now created at line 408-456 with BOTH inputs:
// - preheader: poison value (variable doesn't exist yet)
// - latch: actual value from loop body
//
// No further sealing is needed!
// Exit block
self.set_current_block(exit_id)?;