diff --git a/src/mir/builder/utils.rs b/src/mir/builder/utils.rs index 11a7a870..db908697 100644 --- a/src/mir/builder/utils.rs +++ b/src/mir/builder/utils.rs @@ -30,7 +30,7 @@ impl super::MirBuilder { /// - Inside function: uses function-local allocator /// - Outside function: uses module-global allocator #[inline] - pub(super) fn next_value_id(&mut self) -> super::ValueId { + pub(crate) fn next_value_id(&mut self) -> super::ValueId { if let Some(ref mut f) = self.current_function { f.next_value_id() // Function context } else { diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index acae56f2..fe3723dc 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -46,7 +46,39 @@ pub struct LoopBuilder<'a> { impl<'a> LoopBuilder<'a> { // Implement phi_core LoopPhiOps on LoopBuilder for in-place delegation - + + /// Find the source value of a Copy instruction in a given block + /// If `dst` is defined by a Copy instruction `dst = copy src`, return Some(src) + /// Otherwise return None + fn find_copy_source(&self, block_id: BasicBlockId, dst: ValueId) -> Option { + let func = self.parent_builder.current_function.as_ref()?; + let block = func.blocks.get(&block_id)?; + + let trace = std::env::var("NYASH_LOOP_TRACE").ok().as_deref() == Some("1"); + if trace { + eprintln!("[loop/copy-trace] searching for dst={:?} in block={:?}, {} instructions", + dst, block_id, block.instructions.len()); + } + + for (idx, inst) in block.instructions.iter().enumerate() { + if let MirInstruction::Copy { dst: inst_dst, src } = inst { + if trace { + eprintln!("[loop/copy-trace] inst#{}: %{} = copy %{}", idx, inst_dst.0, src.0); + } + if *inst_dst == dst { + if trace { + eprintln!("[loop/copy-trace] FOUND! dst={:?} src={:?}", dst, src); + } + return Some(*src); + } + } + } + if trace { + eprintln!("[loop/copy-trace] NOT FOUND for dst={:?}", dst); + } + None + } + // ============================================================= // Control Helpers — break/continue/jumps/unreachable handling // ============================================================= @@ -336,22 +368,36 @@ impl<'a> LoopBuilder<'a> { // When method calls occur in loop conditions (e.g., i < args.length()), pin_to_slot creates // pinned receiver variables like __pin$*@recv. These must have PHI nodes in the loop header. let post_cond_vars = self.get_current_variable_map(); - let mut new_pinned_vars: Vec<(String, ValueId)> = Vec::new(); + let mut new_pinned_vars: Vec<(String, ValueId, ValueId)> = Vec::new(); + if trace { + eprintln!("[loop] post_cond_vars has {} entries", post_cond_vars.len()); + } for (name, &value) in post_cond_vars.iter() { if !name.starts_with("__pin$") { continue; } // Check if this pinned variable existed before condition compilation let was_in_incs = incs.iter().any(|inc| inc.var_name == *name); - if !was_in_incs { - // This is a new pinned variable created during condition evaluation - new_pinned_vars.push((name.clone(), value)); + let was_in_preheader = pre_vars_snapshot.contains_key(name); + if !was_in_incs && !was_in_preheader { + // This is a NEW pinned variable created during condition evaluation (not inherited from preheader) + // We need to find the source of the copy instruction that created this value + let preheader_value = self.find_copy_source(header_id, value).unwrap_or(value); + if trace { + eprintln!("[loop] NEW pinned var: {} value={:?} preheader={:?}", name, value, preheader_value); + } + new_pinned_vars.push((name.clone(), value, preheader_value)); + } else if !was_in_incs && was_in_preheader { + // This pinned variable existed in preheader, so it needs a PHI but we should use the preheader value + let preheader_value = pre_vars_snapshot.get(name).copied().unwrap_or(value); + if trace { + eprintln!("[loop] INHERITED pinned var: {} value={:?} preheader={:?}", name, value, preheader_value); + } + new_pinned_vars.push((name.clone(), value, preheader_value)); } } // Add PHI nodes for new pinned variables in header block - for (name, value) in new_pinned_vars { + for (name, value, preheader_value) in new_pinned_vars { let phi_id = self.new_value(); - // Get the value from preheader (same as the current value since it was just created) - let preheader_value = value; self.emit_phi_at_block_start(header_id, phi_id, vec![(preheader_id, preheader_value)])?; // Update variable map to use PHI value self.update_variable(name.clone(), phi_id); @@ -1076,7 +1122,9 @@ impl crate::mir::phi_core::loop_phi::LoopPhiOps for LoopBuilder<'_> { // Implement LoopFormOps trait for LoopBuilder to support LoopFormBuilder integration impl<'a> LoopFormOps for LoopBuilder<'a> { fn new_value(&mut self) -> ValueId { - self.parent_builder.value_gen.next() + // Use function-local allocator via MirBuilder helper to keep + // ValueId ranges consistent with the current function's value_count. + self.parent_builder.next_value_id() } fn is_parameter(&self, name: &str) -> bool {