diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index 0e3b446a..486b1822 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -479,12 +479,29 @@ impl<'a> LoopBuilder<'a> { crate::mir::builder::loops::add_predecessor(self.parent_builder, header_id, continue_merge_id)?; // Step 2: merged_snapshot を使って seal_phis を呼ぶ - let continue_snaps: Vec<(BasicBlockId, HashMap)> = - if merged_snapshot.is_empty() { - vec![] - } else { + // Phase 25.3: Continue merge PHI実装(Task先生の発見!) + // - continueが無いループでも、Latchブロックの値をHeader PHIに伝播する必要がある + // - これにより、Exit PHIがHeader PHI経由で正しい値を受け取れる + let continue_snaps: Vec<(BasicBlockId, HashMap)> = { + // まず、merged_snapshot(continue merge PHI結果)を追加 + let mut snaps = if !merged_snapshot.is_empty() { vec![(continue_merge_id, merged_snapshot.clone())] + } else { + vec![] }; + + // continueが無い場合でも、Latchブロックのスナップショットを追加 + // これにより、seal_phis()がLatchからの値をHeader PHIに正しく接続できる + if raw_continue_snaps.is_empty() { + // continue文が無い場合、Latchブロックの現在の変数マップをキャプチャ + // Note: このタイミングでは current_block == exit_id だが、 + // variable_map はLatch実行後の状態を保持している + let latch_snapshot = self.get_current_variable_map(); + snaps.push((actual_latch_id, latch_snapshot)); + } + + snaps + }; // Step 5-1/5-2: Pass writes 集合 for PHI縮約 loopform.seal_phis(self, actual_latch_id, &continue_snaps, &writes)?; diff --git a/src/mir/phi_core/loopform_builder.rs b/src/mir/phi_core/loopform_builder.rs index 293ecedf..d5a5568d 100644 --- a/src/mir/phi_core/loopform_builder.rs +++ b/src/mir/phi_core/loopform_builder.rs @@ -157,6 +157,15 @@ impl LoopFormBuilder { // Separate variables into carriers and pinned based on parameter status for (name, &value) in current_vars.iter() { + // Step 5-3: Skip __pin$ temporary variables (BodyLocalInternal) + // These are compiler-generated temporaries that should not have PHI nodes + if name.starts_with("__pin$") && name.contains("$@") { + if debug_enabled { + eprintln!("[loopform/prepare] SKIP __pin$ variable: {}", name); + } + continue; + } + // Phase 26-A-4: ValueIdベース判定に変更(名前ベース → 型安全) if ops.is_parameter(value) { param_count += 1; @@ -382,11 +391,19 @@ impl LoopFormBuilder { // - each continue block (early jump to header), // - latch (normal end-of-iteration backedge). for carrier in &mut self.carriers { - carrier.latch_value = ops - .get_variable_at_block(&carrier.name, latch_id) - .ok_or_else(|| { - format!("Carrier variable '{}' not found at latch block", carrier.name) - })?; + // Step 5-5-C: Fix __pin$ temporary variables at latch + // __pin$ variables are body-local temps that are filtered from body_end_vars. + // They don't have explicit values at the latch block, so we use the header PHI + // itself as the latch value (creating a self-referencing PHI that will be + // optimized by PHI reduction). + carrier.latch_value = if carrier.name.starts_with("__pin$") && carrier.name.contains("$@") { + carrier.header_phi // Use the PHI value itself as the latch input + } else { + ops.get_variable_at_block(&carrier.name, latch_id) + .ok_or_else(|| { + format!("Carrier variable '{}' not found at latch block", carrier.name) + })? + }; let mut inputs: Vec<(BasicBlockId, ValueId)> = vec![(self.preheader_id, carrier.preheader_copy)];