Phase 33 NORM canon test: enforce normalized dev route for P1/P2/JP mini

This commit is contained in:
nyash-codex
2025-12-11 20:54:33 +09:00
parent 59a985b7fa
commit af6f95cd4b
170 changed files with 4423 additions and 1897 deletions

View File

@ -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: