From c8f1cea567c4a3fb82f65b773796df9ba888169f Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Thu, 20 Nov 2025 13:49:55 +0900 Subject: [PATCH] =?UTF-8?q?wip(phi):=20Step=205-5-A=20body-local=20PHI?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=AD=20-=20pred=20mismatch=E8=A7=A3?= =?UTF-8?q?=E6=B1=BA=E3=82=82=20undefined=20value=E7=99=BA=E7=94=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔧 **実装内容**: - 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生成ロジックの根本見直し検討 --- src/mir/loop_builder.rs | 105 +++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 56 deletions(-) diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index 51f48883..bd03ea80 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -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)?;