Phase 33 NORM canon test: enforce normalized dev route for P1/P2/JP mini
This commit is contained in:
@ -13,24 +13,24 @@
|
||||
//! Phase 4 Refactoring: Breaking down 714-line merge_joinir_mir_blocks() into focused modules
|
||||
|
||||
mod block_allocator;
|
||||
mod value_collector;
|
||||
mod instruction_rewriter;
|
||||
mod exit_phi_builder;
|
||||
pub mod exit_line;
|
||||
mod loop_header_phi_info;
|
||||
mod loop_header_phi_builder;
|
||||
mod tail_call_classifier;
|
||||
mod merge_result;
|
||||
mod expr_result_resolver;
|
||||
#[cfg(debug_assertions)]
|
||||
mod contract_checks;
|
||||
pub mod exit_line;
|
||||
mod exit_phi_builder;
|
||||
mod expr_result_resolver;
|
||||
mod instruction_rewriter;
|
||||
mod loop_header_phi_builder;
|
||||
mod loop_header_phi_info;
|
||||
mod merge_result;
|
||||
mod tail_call_classifier;
|
||||
mod value_collector;
|
||||
|
||||
// Phase 33-17: Re-export for use by other modules
|
||||
pub use loop_header_phi_info::LoopHeaderPhiInfo;
|
||||
pub use loop_header_phi_builder::LoopHeaderPhiBuilder;
|
||||
pub use loop_header_phi_info::LoopHeaderPhiInfo;
|
||||
|
||||
use crate::mir::{MirModule, ValueId};
|
||||
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
|
||||
use crate::mir::{MirModule, ValueId};
|
||||
|
||||
/// Phase 49-3.2: Merge JoinIR-generated MIR blocks into current_function
|
||||
///
|
||||
@ -100,7 +100,12 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
let cond_summary: Vec<String> = boundary
|
||||
.condition_bindings
|
||||
.iter()
|
||||
.map(|b| format!("{}: host {:?} → join {:?}", b.name, b.host_value, b.join_value))
|
||||
.map(|b| {
|
||||
format!(
|
||||
"{}: host {:?} → join {:?}",
|
||||
b.name, b.host_value, b.join_value
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
eprintln!(
|
||||
@ -123,8 +128,7 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
let carriers: Vec<String> = ci.carriers.iter().map(|c| c.name.clone()).collect();
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Boundary carrier_info: loop_var='{}', carriers={:?}",
|
||||
ci.loop_var_name,
|
||||
carriers
|
||||
ci.loop_var_name, carriers
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -134,7 +138,8 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
|
||||
// Phase 1: Allocate block IDs for all functions
|
||||
// Phase 177-3: block_allocator now returns exit_block_id to avoid conflicts
|
||||
let (mut remapper, exit_block_id) = block_allocator::allocate_blocks(builder, mir_module, debug)?;
|
||||
let (mut remapper, exit_block_id) =
|
||||
block_allocator::allocate_blocks(builder, mir_module, debug)?;
|
||||
|
||||
// Phase 2: Collect values from all functions
|
||||
let (mut used_values, value_to_func_name, function_params) =
|
||||
@ -181,35 +186,55 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
.ok_or("JoinIR module has no functions (Phase 201-A)")?;
|
||||
let entry_block_remapped = remapper
|
||||
.get_block(entry_func_name, entry_func.entry_block)
|
||||
.ok_or_else(|| format!("Entry block not found for {} (Phase 201-A)", entry_func_name))?;
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"Entry block not found for {} (Phase 201-A)",
|
||||
entry_func_name
|
||||
)
|
||||
})?;
|
||||
|
||||
// Get host's current block as the entry edge
|
||||
let host_entry_block = builder.current_block.ok_or(
|
||||
"Phase 201-A: No current block when building header PHIs"
|
||||
)?;
|
||||
let host_entry_block = builder
|
||||
.current_block
|
||||
.ok_or("Phase 201-A: No current block when building header PHIs")?;
|
||||
|
||||
// Get loop variable's initial value from HOST
|
||||
let loop_var_init = boundary.host_inputs.first().copied().ok_or(
|
||||
"Phase 201-A: No host_inputs in boundary for loop_var_init"
|
||||
)?;
|
||||
let loop_var_init = boundary
|
||||
.host_inputs
|
||||
.first()
|
||||
.copied()
|
||||
.ok_or("Phase 201-A: No host_inputs in boundary for loop_var_init")?;
|
||||
|
||||
// Phase 228-4: Extract carriers with their initialization strategy
|
||||
let other_carriers: Vec<(String, ValueId, crate::mir::join_ir::lowering::carrier_info::CarrierInit, crate::mir::join_ir::lowering::carrier_info::CarrierRole)> =
|
||||
if let Some(ref carrier_info) = boundary.carrier_info {
|
||||
// Use carrier_info if available (Phase 228)
|
||||
carrier_info.carriers
|
||||
.iter()
|
||||
.filter(|c| c.name != *loop_var_name)
|
||||
.map(|c| (c.name.clone(), c.host_id, c.init, c.role))
|
||||
.collect()
|
||||
} else {
|
||||
// Fallback: exit_bindings から取得(既存動作)
|
||||
boundary.exit_bindings
|
||||
.iter()
|
||||
.filter(|b| b.carrier_name != *loop_var_name)
|
||||
.map(|b| (b.carrier_name.clone(), b.host_slot, crate::mir::join_ir::lowering::carrier_info::CarrierInit::FromHost, crate::mir::join_ir::lowering::carrier_info::CarrierRole::LoopState))
|
||||
.collect()
|
||||
};
|
||||
let other_carriers: Vec<(
|
||||
String,
|
||||
ValueId,
|
||||
crate::mir::join_ir::lowering::carrier_info::CarrierInit,
|
||||
crate::mir::join_ir::lowering::carrier_info::CarrierRole,
|
||||
)> = if let Some(ref carrier_info) = boundary.carrier_info {
|
||||
// Use carrier_info if available (Phase 228)
|
||||
carrier_info
|
||||
.carriers
|
||||
.iter()
|
||||
.filter(|c| c.name != *loop_var_name)
|
||||
.map(|c| (c.name.clone(), c.host_id, c.init, c.role))
|
||||
.collect()
|
||||
} else {
|
||||
// Fallback: exit_bindings から取得(既存動作)
|
||||
boundary
|
||||
.exit_bindings
|
||||
.iter()
|
||||
.filter(|b| b.carrier_name != *loop_var_name)
|
||||
.map(|b| {
|
||||
(
|
||||
b.carrier_name.clone(),
|
||||
b.host_slot,
|
||||
crate::mir::join_ir::lowering::carrier_info::CarrierInit::FromHost,
|
||||
crate::mir::join_ir::lowering::carrier_info::CarrierRole::LoopState,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
@ -219,7 +244,10 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] loop_var_init={:?}, carriers={:?}",
|
||||
loop_var_init,
|
||||
other_carriers.iter().map(|(n, _, _, _)| n.as_str()).collect::<Vec<_>>()
|
||||
other_carriers
|
||||
.iter()
|
||||
.map(|(n, _, _, _)| n.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
@ -235,33 +263,53 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
debug,
|
||||
)?
|
||||
} else {
|
||||
LoopHeaderPhiInfo::empty(remapper.get_block(
|
||||
mir_module.functions.iter().next().unwrap().0,
|
||||
mir_module.functions.iter().next().unwrap().1.entry_block
|
||||
).unwrap())
|
||||
LoopHeaderPhiInfo::empty(
|
||||
remapper
|
||||
.get_block(
|
||||
mir_module.functions.iter().next().unwrap().0,
|
||||
mir_module.functions.iter().next().unwrap().1.entry_block,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
LoopHeaderPhiInfo::empty(remapper.get_block(
|
||||
mir_module.functions.iter().next().unwrap().0,
|
||||
mir_module.functions.iter().next().unwrap().1.entry_block
|
||||
).unwrap())
|
||||
LoopHeaderPhiInfo::empty(
|
||||
remapper
|
||||
.get_block(
|
||||
mir_module.functions.iter().next().unwrap().0,
|
||||
mir_module.functions.iter().next().unwrap().1.entry_block,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
|
||||
// Phase 201-A: Get reserved PHI dst ValueIds and set in MirBuilder
|
||||
let reserved_phi_dsts = loop_header_phi_info.reserved_value_ids();
|
||||
if debug && !reserved_phi_dsts.is_empty() {
|
||||
eprintln!("[cf_loop/joinir] Phase 201-A: Reserved PHI dsts: {:?}", reserved_phi_dsts);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 201-A: Reserved PHI dsts: {:?}",
|
||||
reserved_phi_dsts
|
||||
);
|
||||
}
|
||||
|
||||
// Phase 201-A: Set reserved IDs in MirBuilder so next_value_id() skips them
|
||||
// This protects against carrier corruption when break conditions emit Const instructions
|
||||
builder.reserved_value_ids = reserved_phi_dsts.clone();
|
||||
if debug && !builder.reserved_value_ids.is_empty() {
|
||||
eprintln!("[cf_loop/joinir] Phase 201-A: Set builder.reserved_value_ids = {:?}", builder.reserved_value_ids);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 201-A: Set builder.reserved_value_ids = {:?}",
|
||||
builder.reserved_value_ids
|
||||
);
|
||||
}
|
||||
|
||||
// Phase 3: Remap ValueIds (with reserved PHI dsts protection)
|
||||
remap_values(builder, &used_values, &mut remapper, &reserved_phi_dsts, debug)?;
|
||||
remap_values(
|
||||
builder,
|
||||
&used_values,
|
||||
&mut remapper,
|
||||
&reserved_phi_dsts,
|
||||
debug,
|
||||
)?;
|
||||
|
||||
// Phase 177-3 DEBUG: Verify remapper state after Phase 3
|
||||
eprintln!("[DEBUG-177] === Remapper state after Phase 3 ===");
|
||||
@ -372,12 +420,18 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 33-21: carrier_phis count: {}, names: {:?}",
|
||||
loop_header_phi_info.carrier_phis.len(),
|
||||
loop_header_phi_info.carrier_phis.iter().map(|(n, _)| n.as_str()).collect::<Vec<_>>()
|
||||
loop_header_phi_info
|
||||
.carrier_phis
|
||||
.iter()
|
||||
.map(|(n, _)| n.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
// Map main's parameters to header PHI dsts
|
||||
// main params: [i_init, carrier1_init, ...]
|
||||
// carrier_phis: [("i", entry), ("sum", entry), ...]
|
||||
for (idx, (carrier_name, entry)) in loop_header_phi_info.carrier_phis.iter().enumerate() {
|
||||
for (idx, (carrier_name, entry)) in
|
||||
loop_header_phi_info.carrier_phis.iter().enumerate()
|
||||
{
|
||||
if let Some(&main_param) = main_params.get(idx) {
|
||||
// Phase 177-3: Don't override condition_bindings
|
||||
if condition_binding_ids.contains(&main_param) {
|
||||
@ -401,7 +455,11 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// They appear in condition_bindings (added by Phase 176-5) but need PHI remapping.
|
||||
for (carrier_name, entry) in &loop_header_phi_info.carrier_phis {
|
||||
// Check if this carrier has a condition_binding
|
||||
if let Some(binding) = boundary.condition_bindings.iter().find(|cb| cb.name == *carrier_name) {
|
||||
if let Some(binding) = boundary
|
||||
.condition_bindings
|
||||
.iter()
|
||||
.find(|cb| cb.name == *carrier_name)
|
||||
{
|
||||
// Skip if it's a true condition-only variable (already protected above)
|
||||
if condition_binding_ids.contains(&binding.join_value) {
|
||||
continue;
|
||||
@ -451,8 +509,11 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// Find which carrier this param belongs to by matching join_value
|
||||
// Check if this param was already handled by Phase 177-3-B
|
||||
let already_mapped = boundary.condition_bindings.iter().any(|cb| {
|
||||
cb.join_value == *loop_step_param &&
|
||||
loop_header_phi_info.carrier_phis.iter().any(|(name, _)| name == &cb.name)
|
||||
cb.join_value == *loop_step_param
|
||||
&& loop_header_phi_info
|
||||
.carrier_phis
|
||||
.iter()
|
||||
.any(|(name, _)| name == &cb.name)
|
||||
});
|
||||
if already_mapped {
|
||||
eprintln!(
|
||||
@ -467,7 +528,9 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// generates params in exit_bindings order.
|
||||
//
|
||||
// Solution: Use carrier_order (Vec<String>) which preserves insertion order.
|
||||
if let Some(param_idx) = loop_step_params.iter().position(|p| p == loop_step_param) {
|
||||
if let Some(param_idx) =
|
||||
loop_step_params.iter().position(|p| p == loop_step_param)
|
||||
{
|
||||
// Map params[i] to carrier_order[i]
|
||||
if let (Some(carrier_name), Some(entry)) = (
|
||||
loop_header_phi_info.get_carrier_at_index(param_idx),
|
||||
@ -483,7 +546,9 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
}
|
||||
}
|
||||
|
||||
if function_params.get(main_func_name).is_none() && function_params.get(loop_step_func_name).is_none() {
|
||||
if function_params.get(main_func_name).is_none()
|
||||
&& function_params.get(loop_step_func_name).is_none()
|
||||
{
|
||||
// Fallback: Use old behavior (ValueId(0), ValueId(1), ...)
|
||||
// This handles patterns that don't have loop_step function
|
||||
if let Some(phi_dst) = loop_header_phi_info.get_carrier_phi(loop_var_name) {
|
||||
@ -570,11 +635,7 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
loop_header_phi_info.carrier_phis.len()
|
||||
);
|
||||
}
|
||||
LoopHeaderPhiBuilder::finalize(
|
||||
builder,
|
||||
&loop_header_phi_info,
|
||||
debug,
|
||||
)?;
|
||||
LoopHeaderPhiBuilder::finalize(builder, &loop_header_phi_info, debug)?;
|
||||
}
|
||||
|
||||
// Phase 5: Build exit PHI (expr result only, not carrier PHIs)
|
||||
@ -633,12 +694,18 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
let entry_block = loop_header_phi_info.header_block;
|
||||
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Entry block (from loop_header_phi_info): {:?}", entry_block);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Entry block (from loop_header_phi_info): {:?}",
|
||||
entry_block
|
||||
);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Current block before emit_jump: {:?}",
|
||||
builder.current_block
|
||||
);
|
||||
eprintln!("[cf_loop/joinir] Jumping to entry block: {:?}", entry_block);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Jumping to entry block: {:?}",
|
||||
entry_block
|
||||
);
|
||||
}
|
||||
|
||||
crate::mir::builder::emission::branch::emit_jump(builder, entry_block)?;
|
||||
@ -684,7 +751,10 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// Future loops will set their own reserved IDs
|
||||
if !builder.reserved_value_ids.is_empty() {
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Phase 201-A: Clearing reserved_value_ids (was {:?})", builder.reserved_value_ids);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 201-A: Clearing reserved_value_ids (was {:?})",
|
||||
builder.reserved_value_ids
|
||||
);
|
||||
}
|
||||
builder.reserved_value_ids.clear();
|
||||
}
|
||||
@ -698,7 +768,9 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// Check if expr_result is the loop variable
|
||||
if let Some(loop_var_name) = &b.loop_var_name {
|
||||
// Find the exit binding for the loop variable
|
||||
let loop_var_binding = b.exit_bindings.iter()
|
||||
let loop_var_binding = b
|
||||
.exit_bindings
|
||||
.iter()
|
||||
.find(|binding| binding.carrier_name == *loop_var_name);
|
||||
|
||||
if let Some(binding) = loop_var_binding {
|
||||
@ -751,7 +823,10 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// Return expr_result if present, otherwise fall back to exit_phi_result_id
|
||||
if let Some(resolved) = expr_result_value {
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Phase 246-EX-FIX: Returning expr_result_value {:?}", resolved);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 246-EX-FIX: Returning expr_result_value {:?}",
|
||||
resolved
|
||||
);
|
||||
}
|
||||
Ok(Some(resolved))
|
||||
} else {
|
||||
@ -779,8 +854,11 @@ fn remap_values(
|
||||
debug: bool,
|
||||
) -> Result<(), String> {
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Phase 3: Remapping {} ValueIds (reserved: {})",
|
||||
used_values.len(), reserved_ids.len());
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 3: Remapping {} ValueIds (reserved: {})",
|
||||
used_values.len(),
|
||||
reserved_ids.len()
|
||||
);
|
||||
}
|
||||
|
||||
for old_value in used_values {
|
||||
@ -792,7 +870,10 @@ fn remap_values(
|
||||
}
|
||||
// Skip reserved ID - will try next one
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Phase 201-A: Skipping reserved PHI dst {:?}", candidate);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 201-A: Skipping reserved PHI dst {:?}",
|
||||
candidate
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -943,7 +1024,12 @@ fn verify_phi_inputs_defined(
|
||||
});
|
||||
|
||||
for instr in &header_block_data.instructions {
|
||||
if let crate::mir::MirInstruction::Phi { dst, inputs, type_hint: _ } = instr {
|
||||
if let crate::mir::MirInstruction::Phi {
|
||||
dst,
|
||||
inputs,
|
||||
type_hint: _,
|
||||
} = instr
|
||||
{
|
||||
for (value_id, pred_block) in inputs {
|
||||
// Conservative sanity check: ValueId should not be suspiciously large
|
||||
// Phase 201 JoinValueSpace uses regions:
|
||||
|
||||
Reference in New Issue
Block a user