refactor(joinir): Phase 190 convert.rs modularization
- Created joinir_function_converter.rs (~133 lines): Function-level conversion - Created joinir_block_converter.rs (~691 lines): Block-level conversion - Reduced convert.rs from 943 → 120 lines (87% reduction) - Total: 944 lines (original 943 lines, minimal overhead) - Separation of concerns: Function vs Block responsibilities - All handlers moved to block_converter for better organization - Maintained backward compatibility with existing API - Build successful, simple tests passing
This commit is contained in:
@ -557,6 +557,8 @@ impl super::MirBuilder {
|
||||
) -> Result<(), String> {
|
||||
use crate::mir::{BasicBlock, BasicBlockId, MirInstruction, ValueId};
|
||||
use std::collections::HashMap;
|
||||
// Phase 189: Use new ID remapper Box
|
||||
use super::joinir_id_remapper::JoinIrIdRemapper;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
@ -565,11 +567,9 @@ impl super::MirBuilder {
|
||||
);
|
||||
}
|
||||
|
||||
// Phase 189: Global ID maps for ALL functions (not just first)
|
||||
// CRITICAL: Use composite keys (func_name, BasicBlockId) to avoid collisions!
|
||||
// Different functions can have blocks with same BasicBlockId (e.g., both have bb0)
|
||||
let mut block_map: HashMap<(String, BasicBlockId), BasicBlockId> = HashMap::new();
|
||||
let mut value_map: HashMap<ValueId, ValueId> = HashMap::new();
|
||||
// Phase 189: Create ID remapper for ValueId/BlockId translation
|
||||
let mut remapper = JoinIrIdRemapper::new();
|
||||
|
||||
// Phase 189: Map function names to their entry blocks (for Call→Jump conversion)
|
||||
let mut function_entry_map: HashMap<String, BasicBlockId> = HashMap::new();
|
||||
|
||||
@ -589,8 +589,8 @@ impl super::MirBuilder {
|
||||
blocks.sort_by_key(|(id, _)| id.0);
|
||||
for (old_block_id, _) in blocks {
|
||||
let new_block_id = self.block_gen.next();
|
||||
// Use composite key to avoid collision between functions
|
||||
block_map.insert((func_name.clone(), *old_block_id), new_block_id);
|
||||
// Use remapper to store composite key mapping
|
||||
remapper.set_block(func_name.clone(), *old_block_id, new_block_id);
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Block remap: {}:{:?} → {:?}",
|
||||
@ -599,7 +599,8 @@ impl super::MirBuilder {
|
||||
}
|
||||
}
|
||||
// Map function entry blocks for Call→Jump conversion
|
||||
let entry_block_new = block_map[&(func_name.clone(), func.entry_block)];
|
||||
let entry_block_new = remapper.get_block(func_name, func.entry_block)
|
||||
.ok_or_else(|| format!("Entry block not found for {}", func_name))?;
|
||||
function_entry_map.insert(func_name.clone(), entry_block_new);
|
||||
if debug {
|
||||
eprintln!(
|
||||
@ -631,7 +632,10 @@ impl super::MirBuilder {
|
||||
function_params.insert(func_name.clone(), func.params.clone());
|
||||
|
||||
for block in func.blocks.values() {
|
||||
Self::collect_values_in_block(block, &mut used_values);
|
||||
// Phase 189: Use remapper to collect values
|
||||
let block_values = remapper.collect_values_in_block(block);
|
||||
used_values.extend(block_values);
|
||||
|
||||
// Phase 189: Track Const String instructions that define function names
|
||||
for inst in &block.instructions {
|
||||
if let MirInstruction::Const { dst, value } = inst {
|
||||
@ -658,7 +662,7 @@ impl super::MirBuilder {
|
||||
// 4. Allocate new ValueIds for all collected values
|
||||
for old_value in used_values {
|
||||
let new_value = self.next_value_id();
|
||||
value_map.insert(old_value, new_value);
|
||||
remapper.set_value(old_value, new_value);
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Value remap: {:?} → {:?}",
|
||||
@ -688,7 +692,8 @@ impl super::MirBuilder {
|
||||
// Build a local block map for this function (for remap_instruction compatibility)
|
||||
let mut local_block_map: HashMap<BasicBlockId, BasicBlockId> = HashMap::new();
|
||||
for old_block_id in func.blocks.keys() {
|
||||
let new_block_id = block_map[&(func_name.clone(), *old_block_id)];
|
||||
let new_block_id = remapper.get_block(func_name, *old_block_id)
|
||||
.ok_or_else(|| format!("Block {:?} not found for {}", old_block_id, func_name))?;
|
||||
local_block_map.insert(*old_block_id, new_block_id);
|
||||
}
|
||||
|
||||
@ -697,8 +702,9 @@ impl super::MirBuilder {
|
||||
let mut blocks_merge: Vec<_> = func.blocks.iter().collect();
|
||||
blocks_merge.sort_by_key(|(id, _)| id.0);
|
||||
for (old_block_id, old_block) in blocks_merge {
|
||||
// Use composite key to get correct mapping for this function's block
|
||||
let new_block_id = block_map[&(func_name.clone(), *old_block_id)];
|
||||
// Use remapper to get correct mapping for this function's block
|
||||
let new_block_id = remapper.get_block(func_name, *old_block_id)
|
||||
.ok_or_else(|| format!("Block {:?} not found for {}", old_block_id, func_name))?;
|
||||
let mut new_block = BasicBlock::new(new_block_id);
|
||||
|
||||
// Remap instructions (Phase 189: Convert inter-function Calls to control flow)
|
||||
@ -726,7 +732,7 @@ impl super::MirBuilder {
|
||||
// This is a tail call - save info and skip the Call instruction itself
|
||||
let remapped_args: Vec<ValueId> = args
|
||||
.iter()
|
||||
.map(|&v| value_map.get(&v).copied().unwrap_or(v))
|
||||
.map(|&v| remapper.get_value(v).unwrap_or(v))
|
||||
.collect();
|
||||
tail_call_target = Some((target_block, remapped_args));
|
||||
found_tail_call = true;
|
||||
@ -742,15 +748,29 @@ impl super::MirBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// Process regular instructions
|
||||
let remapped = Self::remap_joinir_instruction(
|
||||
inst,
|
||||
&value_map,
|
||||
&local_block_map, // Use local map for this function
|
||||
&function_entry_map,
|
||||
&value_to_func_name,
|
||||
debug,
|
||||
);
|
||||
// Process regular instructions - Phase 189: Use remapper.remap_instruction() + manual block remapping
|
||||
let remapped = remapper.remap_instruction(inst);
|
||||
|
||||
// Phase 189 FIX: Manual block remapping for Branch/Phi (JoinIrIdRemapper doesn't know func_name)
|
||||
let remapped_with_blocks = match remapped {
|
||||
MirInstruction::Branch { condition, then_bb, else_bb } => {
|
||||
MirInstruction::Branch {
|
||||
condition,
|
||||
then_bb: local_block_map.get(&then_bb).copied().unwrap_or(then_bb),
|
||||
else_bb: local_block_map.get(&else_bb).copied().unwrap_or(else_bb),
|
||||
}
|
||||
}
|
||||
MirInstruction::Phi { dst, inputs, type_hint: None } => {
|
||||
MirInstruction::Phi {
|
||||
dst,
|
||||
inputs: inputs.iter().map(|(bb, val)| {
|
||||
(local_block_map.get(bb).copied().unwrap_or(*bb), *val)
|
||||
}).collect(),
|
||||
type_hint: None,
|
||||
}
|
||||
}
|
||||
other => other,
|
||||
};
|
||||
|
||||
if debug {
|
||||
match inst {
|
||||
@ -761,7 +781,7 @@ impl super::MirBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
new_block.instructions.push(remapped);
|
||||
new_block.instructions.push(remapped_with_blocks);
|
||||
}
|
||||
|
||||
// Second pass: Insert parameter bindings for tail calls
|
||||
@ -790,7 +810,7 @@ impl super::MirBuilder {
|
||||
for (i, arg_val_remapped) in args.iter().enumerate() {
|
||||
if i < target_params.len() {
|
||||
let param_val_original = target_params[i];
|
||||
if let Some(¶m_val_remapped) = value_map.get(¶m_val_original) {
|
||||
if let Some(param_val_remapped) = remapper.get_value(param_val_original) {
|
||||
new_block.instructions.push(MirInstruction::Copy {
|
||||
dst: param_val_remapped,
|
||||
src: *arg_val_remapped,
|
||||
@ -823,7 +843,7 @@ impl super::MirBuilder {
|
||||
// Convert Return to Jump to exit block
|
||||
// All functions return to same exit block (Phase 189)
|
||||
if let Some(ret_val) = value {
|
||||
let remapped_val = value_map.get(ret_val).copied().unwrap_or(*ret_val);
|
||||
let remapped_val = remapper.get_value(*ret_val).unwrap_or(*ret_val);
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Return({:?}) → Jump to exit",
|
||||
@ -835,14 +855,27 @@ impl super::MirBuilder {
|
||||
target: exit_block_id,
|
||||
}
|
||||
}
|
||||
_ => Self::remap_joinir_instruction(
|
||||
term,
|
||||
&value_map,
|
||||
&local_block_map, // Use local map for this function
|
||||
&function_entry_map,
|
||||
&value_to_func_name,
|
||||
debug,
|
||||
),
|
||||
MirInstruction::Jump { target } => {
|
||||
// Phase 189 FIX: Remap block ID for Jump
|
||||
MirInstruction::Jump {
|
||||
target: local_block_map.get(target).copied().unwrap_or(*target),
|
||||
}
|
||||
}
|
||||
MirInstruction::Branch { condition, then_bb, else_bb } => {
|
||||
// Phase 189 FIX: Remap block IDs for Branch
|
||||
let remapped = remapper.remap_instruction(term);
|
||||
match remapped {
|
||||
MirInstruction::Branch { condition, then_bb, else_bb } => {
|
||||
MirInstruction::Branch {
|
||||
condition,
|
||||
then_bb: local_block_map.get(&then_bb).copied().unwrap_or(then_bb),
|
||||
else_bb: local_block_map.get(&else_bb).copied().unwrap_or(else_bb),
|
||||
}
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
_ => remapper.remap_instruction(term),
|
||||
};
|
||||
new_block.terminator = Some(remapped_term);
|
||||
}
|
||||
@ -855,59 +888,36 @@ impl super::MirBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 188-Impl-3: Inject Copy instructions for boundary inputs
|
||||
// Phase 188-Impl-3: Inject Copy instructions for boundary inputs using BoundaryInjector
|
||||
if let Some(boundary) = boundary {
|
||||
use super::joinir_inline_boundary_injector::BoundaryInjector;
|
||||
|
||||
// Get entry function's entry block (first function by convention)
|
||||
let (entry_func_name, entry_func) = mir_module
|
||||
.functions
|
||||
.iter()
|
||||
.next()
|
||||
.ok_or("JoinIR module has no functions")?;
|
||||
let entry_block_remapped = block_map[&(entry_func_name.clone(), entry_func.entry_block)];
|
||||
let entry_block_remapped = remapper.get_block(entry_func_name, entry_func.entry_block)
|
||||
.ok_or_else(|| format!("Entry block not found for {}", entry_func_name))?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 188-Impl-3: Injecting {} Copy instructions at entry block {:?}",
|
||||
boundary.join_inputs.len(),
|
||||
entry_block_remapped
|
||||
);
|
||||
// Create HashMap from remapper for BoundaryInjector (temporary adapter)
|
||||
let mut value_map_for_injector = HashMap::new();
|
||||
for join_in in &boundary.join_inputs {
|
||||
if let Some(remapped) = remapper.get_value(*join_in) {
|
||||
value_map_for_injector.insert(*join_in, remapped);
|
||||
}
|
||||
}
|
||||
|
||||
// Inject Copy instructions: join_input_remapped = Copy host_input
|
||||
// Use BoundaryInjector to inject Copy instructions
|
||||
if let Some(ref mut current_func) = self.current_function {
|
||||
if let Some(entry_block) = current_func.get_block_mut(entry_block_remapped) {
|
||||
// Insert Copy instructions at the BEGINNING of the block
|
||||
let mut copy_instructions = Vec::new();
|
||||
for (join_in, host_in) in boundary.join_inputs.iter().zip(&boundary.host_inputs) {
|
||||
// join_in is JoinIR's local ValueId (e.g., ValueId(0))
|
||||
// host_in is host function's ValueId (e.g., ValueId(4))
|
||||
// We need to remap join_in to the merged space
|
||||
if let Some(&join_in_remapped) = value_map.get(join_in) {
|
||||
copy_instructions.push(MirInstruction::Copy {
|
||||
dst: join_in_remapped,
|
||||
src: *host_in,
|
||||
});
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Copy boundary: {:?} (host) → {:?} (join_remapped)",
|
||||
host_in, join_in_remapped
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] WARNING: join_input {:?} not found in value_map",
|
||||
join_in
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert at beginning (reverse order so they appear in correct order)
|
||||
for inst in copy_instructions.into_iter().rev() {
|
||||
entry_block.instructions.insert(0, inst);
|
||||
}
|
||||
}
|
||||
BoundaryInjector::inject_boundary_copies(
|
||||
current_func,
|
||||
entry_block_remapped,
|
||||
boundary,
|
||||
&value_map_for_injector,
|
||||
debug,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -924,8 +934,9 @@ impl super::MirBuilder {
|
||||
.iter()
|
||||
.next()
|
||||
.ok_or("JoinIR module has no functions")?;
|
||||
// Use composite key to get entry block mapping
|
||||
let entry_block = block_map[&(entry_func_name.clone(), entry_func.entry_block)];
|
||||
// Use remapper to get entry block mapping
|
||||
let entry_block = remapper.get_block(entry_func_name, entry_func.entry_block)
|
||||
.ok_or_else(|| format!("Entry block not found for {}", entry_func_name))?;
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Jumping to entry block: {:?}", entry_block);
|
||||
}
|
||||
@ -945,247 +956,11 @@ impl super::MirBuilder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Collect all ValueIds used in a block
|
||||
fn collect_values_in_block(
|
||||
block: &crate::mir::BasicBlock,
|
||||
values: &mut std::collections::BTreeSet<super::ValueId>,
|
||||
) {
|
||||
for inst in &block.instructions {
|
||||
Self::collect_values_in_instruction(inst, values);
|
||||
}
|
||||
if let Some(ref term) = block.terminator {
|
||||
Self::collect_values_in_instruction(term, values);
|
||||
}
|
||||
}
|
||||
// Phase 189: collect_values_in_block/collect_values_in_instruction removed
|
||||
// These functions are now provided by JoinIrIdRemapper::collect_values_in_block()
|
||||
|
||||
/// Collect all ValueIds used in an instruction
|
||||
fn collect_values_in_instruction(
|
||||
inst: &crate::mir::MirInstruction,
|
||||
values: &mut std::collections::BTreeSet<super::ValueId>,
|
||||
) {
|
||||
use crate::mir::MirInstruction;
|
||||
|
||||
match inst {
|
||||
MirInstruction::Const { dst, .. } => {
|
||||
values.insert(*dst);
|
||||
}
|
||||
MirInstruction::BinOp { dst, lhs, rhs, .. } => {
|
||||
values.insert(*dst);
|
||||
values.insert(*lhs);
|
||||
values.insert(*rhs);
|
||||
}
|
||||
MirInstruction::UnaryOp { dst, operand, .. } => {
|
||||
values.insert(*dst);
|
||||
values.insert(*operand);
|
||||
}
|
||||
MirInstruction::Compare { dst, lhs, rhs, .. } => {
|
||||
values.insert(*dst);
|
||||
values.insert(*lhs);
|
||||
values.insert(*rhs);
|
||||
}
|
||||
MirInstruction::Load { dst, ptr } => {
|
||||
values.insert(*dst);
|
||||
values.insert(*ptr);
|
||||
}
|
||||
MirInstruction::Store { value, ptr } => {
|
||||
values.insert(*value);
|
||||
values.insert(*ptr);
|
||||
}
|
||||
MirInstruction::Call {
|
||||
dst, func, args, ..
|
||||
} => {
|
||||
if let Some(d) = dst {
|
||||
values.insert(*d);
|
||||
}
|
||||
values.insert(*func);
|
||||
for arg in args {
|
||||
values.insert(*arg);
|
||||
}
|
||||
}
|
||||
MirInstruction::BoxCall {
|
||||
dst, box_val, args, ..
|
||||
} => {
|
||||
if let Some(d) = dst {
|
||||
values.insert(*d);
|
||||
}
|
||||
values.insert(*box_val);
|
||||
for arg in args {
|
||||
values.insert(*arg);
|
||||
}
|
||||
}
|
||||
MirInstruction::Branch { condition, .. } => {
|
||||
values.insert(*condition);
|
||||
}
|
||||
MirInstruction::Return { value } => {
|
||||
if let Some(v) = value {
|
||||
values.insert(*v);
|
||||
}
|
||||
}
|
||||
MirInstruction::Phi {
|
||||
dst,
|
||||
inputs,
|
||||
type_hint: None,
|
||||
} => {
|
||||
values.insert(*dst);
|
||||
for (_, val) in inputs {
|
||||
values.insert(*val);
|
||||
}
|
||||
}
|
||||
MirInstruction::Copy { dst, src } => {
|
||||
values.insert(*dst);
|
||||
values.insert(*src);
|
||||
}
|
||||
MirInstruction::NewBox { dst, args, .. } => {
|
||||
values.insert(*dst);
|
||||
for arg in args {
|
||||
values.insert(*arg);
|
||||
}
|
||||
}
|
||||
MirInstruction::Print { value, .. } => {
|
||||
values.insert(*value);
|
||||
}
|
||||
_ => {
|
||||
// Other instructions: skip for now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 189: Remap JoinIR-generated MIR instructions
|
||||
///
|
||||
/// For now, we use standard instruction remapping. Call instructions between
|
||||
/// merged functions are preserved as Call instructions, relying on VM support
|
||||
/// for handling these calls.
|
||||
///
|
||||
/// **Future Enhancement (Phase 189.1)**: Convert tail calls to jumps for optimization.
|
||||
fn remap_joinir_instruction(
|
||||
inst: &crate::mir::MirInstruction,
|
||||
value_map: &std::collections::HashMap<super::ValueId, super::ValueId>,
|
||||
block_map: &std::collections::HashMap<crate::mir::BasicBlockId, crate::mir::BasicBlockId>,
|
||||
_function_entry_map: &std::collections::HashMap<String, crate::mir::BasicBlockId>,
|
||||
_value_to_func_name: &std::collections::HashMap<super::ValueId, String>,
|
||||
_debug: bool,
|
||||
) -> crate::mir::MirInstruction {
|
||||
// Use standard remapping
|
||||
Self::remap_instruction(inst, value_map, block_map)
|
||||
}
|
||||
|
||||
/// Remap an instruction's ValueIds and BlockIds
|
||||
fn remap_instruction(
|
||||
inst: &crate::mir::MirInstruction,
|
||||
value_map: &std::collections::HashMap<super::ValueId, super::ValueId>,
|
||||
block_map: &std::collections::HashMap<crate::mir::BasicBlockId, crate::mir::BasicBlockId>,
|
||||
) -> crate::mir::MirInstruction {
|
||||
use crate::mir::MirInstruction;
|
||||
|
||||
let remap_value = |v: super::ValueId| value_map.get(&v).copied().unwrap_or(v);
|
||||
let remap_block = |b: crate::mir::BasicBlockId| block_map.get(&b).copied().unwrap_or(b);
|
||||
|
||||
match inst {
|
||||
MirInstruction::Const { dst, value } => MirInstruction::Const {
|
||||
dst: remap_value(*dst),
|
||||
value: value.clone(),
|
||||
},
|
||||
MirInstruction::BinOp { dst, op, lhs, rhs } => MirInstruction::BinOp {
|
||||
dst: remap_value(*dst),
|
||||
op: *op,
|
||||
lhs: remap_value(*lhs),
|
||||
rhs: remap_value(*rhs),
|
||||
},
|
||||
MirInstruction::UnaryOp { dst, op, operand } => MirInstruction::UnaryOp {
|
||||
dst: remap_value(*dst),
|
||||
op: *op,
|
||||
operand: remap_value(*operand),
|
||||
},
|
||||
MirInstruction::Compare { dst, op, lhs, rhs } => MirInstruction::Compare {
|
||||
dst: remap_value(*dst),
|
||||
op: *op,
|
||||
lhs: remap_value(*lhs),
|
||||
rhs: remap_value(*rhs),
|
||||
},
|
||||
MirInstruction::Load { dst, ptr } => MirInstruction::Load {
|
||||
dst: remap_value(*dst),
|
||||
ptr: remap_value(*ptr),
|
||||
},
|
||||
MirInstruction::Store { value, ptr } => MirInstruction::Store {
|
||||
value: remap_value(*value),
|
||||
ptr: remap_value(*ptr),
|
||||
},
|
||||
MirInstruction::Call {
|
||||
dst,
|
||||
func,
|
||||
callee,
|
||||
args,
|
||||
effects,
|
||||
} => MirInstruction::Call {
|
||||
dst: dst.map(remap_value),
|
||||
func: remap_value(*func),
|
||||
callee: callee.clone(),
|
||||
args: args.iter().map(|a| remap_value(*a)).collect(),
|
||||
effects: *effects,
|
||||
},
|
||||
MirInstruction::BoxCall {
|
||||
dst,
|
||||
box_val,
|
||||
method,
|
||||
method_id,
|
||||
args,
|
||||
effects,
|
||||
} => MirInstruction::BoxCall {
|
||||
dst: dst.map(remap_value),
|
||||
box_val: remap_value(*box_val),
|
||||
method: method.clone(),
|
||||
method_id: *method_id,
|
||||
args: args.iter().map(|a| remap_value(*a)).collect(),
|
||||
effects: *effects,
|
||||
},
|
||||
MirInstruction::Branch {
|
||||
condition,
|
||||
then_bb,
|
||||
else_bb,
|
||||
} => MirInstruction::Branch {
|
||||
condition: remap_value(*condition),
|
||||
then_bb: remap_block(*then_bb),
|
||||
else_bb: remap_block(*else_bb),
|
||||
},
|
||||
MirInstruction::Jump { target } => MirInstruction::Jump {
|
||||
target: remap_block(*target),
|
||||
},
|
||||
MirInstruction::Return { value } => MirInstruction::Return {
|
||||
value: value.map(remap_value),
|
||||
},
|
||||
MirInstruction::Phi {
|
||||
dst,
|
||||
inputs,
|
||||
type_hint: None,
|
||||
} => MirInstruction::Phi {
|
||||
dst: remap_value(*dst),
|
||||
inputs: inputs
|
||||
.iter()
|
||||
.map(|(bb, val)| (remap_block(*bb), remap_value(*val)))
|
||||
.collect(),
|
||||
type_hint: None, // Phase 63-6: Preserve no type hint during remapping
|
||||
},
|
||||
MirInstruction::Copy { dst, src } => MirInstruction::Copy {
|
||||
dst: remap_value(*dst),
|
||||
src: remap_value(*src),
|
||||
},
|
||||
MirInstruction::NewBox {
|
||||
dst,
|
||||
box_type,
|
||||
args,
|
||||
} => MirInstruction::NewBox {
|
||||
dst: remap_value(*dst),
|
||||
box_type: box_type.clone(),
|
||||
args: args.iter().map(|a| remap_value(*a)).collect(),
|
||||
},
|
||||
MirInstruction::Print { value, effects } => MirInstruction::Print {
|
||||
value: remap_value(*value),
|
||||
effects: *effects,
|
||||
},
|
||||
// Pass through other instructions unchanged
|
||||
other => other.clone(),
|
||||
}
|
||||
}
|
||||
// Phase 189: remap_joinir_instruction/remap_instruction removed
|
||||
// These functions are now provided by JoinIrIdRemapper::remap_instruction()
|
||||
|
||||
/// Control-flow: try/catch/finally
|
||||
pub(super) fn cf_try_catch(
|
||||
|
||||
Reference in New Issue
Block a user