refactor(joinir): Extract legacy binding path to routing_legacy_binding.rs

Phase 179-A Step 2: Separate LoopFrontendBinding JSON construction logic
into dedicated module for better organization.

Changes:
- New file: routing_legacy_binding.rs (223 lines)
- routing.rs: cf_loop_joinir_impl() simplified to 15 lines (delegates to legacy path)
- Routing now clearly separates pattern-based vs. legacy binding paths

Benefits:
- Clear separation of concerns (pattern router vs. legacy whitelist)
- routing.rs reduced from 364 to 146 lines (60% reduction)
- Legacy path isolated for future deprecation
This commit is contained in:
nyash-codex
2025-12-08 18:36:13 +09:00
parent 7a01ffe522
commit 95f3aa429e
25 changed files with 626 additions and 755 deletions

View File

@ -79,6 +79,13 @@ impl ExitLineReconnector {
carrier_phis: &BTreeMap<String, ValueId>,
debug: bool,
) -> Result<(), String> {
// Phase 177-STRUCT: Always log for debugging
eprintln!(
"[DEBUG-177/reconnect] ExitLineReconnector: {} exit bindings, {} carrier PHIs",
boundary.exit_bindings.len(),
carrier_phis.len()
);
// Early return for empty exit_bindings
if boundary.exit_bindings.is_empty() {
if debug {
@ -110,12 +117,11 @@ impl ExitLineReconnector {
// Update variable_map with PHI dst
if let Some(&phi_value) = phi_dst {
if let Some(var_vid) = builder.variable_map.get_mut(&binding.carrier_name) {
if debug {
eprintln!(
"[cf_loop/joinir/exit_line] ExitLineReconnector: Updated variable_map['{}'] {:?}{:?} (PHI dst)",
binding.carrier_name, var_vid, phi_value
);
}
// Phase 177-STRUCT: Always log for debugging
eprintln!(
"[DEBUG-177/reconnect] Updated variable_map['{}'] {:?}{:?}",
binding.carrier_name, *var_vid, phi_value
);
*var_vid = phi_value;
} else if debug {
eprintln!(

View File

@ -74,12 +74,11 @@ pub(super) fn build_exit_phi(
carrier_phis.insert(carrier_name.clone(), phi_dst);
if debug {
eprintln!(
"[cf_loop/joinir] Exit block PHI (carrier '{}'): {:?} = phi {:?}",
carrier_name, phi_dst, inputs
);
}
// DEBUG-177: Always log exit block PHI creation for carrier debugging
eprintln!(
"[DEBUG-177] Exit block PHI (carrier '{}'): {:?} = phi {:?}",
carrier_name, phi_dst, inputs
);
}
func.add_block(exit_block);

View File

@ -604,12 +604,11 @@ pub(super) fn merge_and_rewrite(
carrier_inputs.entry(binding.carrier_name.clone())
.or_insert_with(Vec::new)
.push((new_block_id, phi_dst));
if debug {
eprintln!(
"[cf_loop/joinir] Phase 33-16: Using header PHI dst {:?} for carrier '{}'",
phi_dst, binding.carrier_name
);
}
// DEBUG-177: Always log carrier collection
eprintln!(
"[DEBUG-177] Phase 33-16: Collecting carrier '{}': from {:?} using header PHI {:?}",
binding.carrier_name, new_block_id, phi_dst
);
}
}
}

View File

@ -84,6 +84,8 @@ impl LoopHeaderPhiBuilder {
latch_incoming: None,
},
);
// Phase 177-STRUCT-2: Record insertion order
info.carrier_order.push(loop_var_name.to_string());
if debug {
eprintln!(
@ -103,6 +105,8 @@ impl LoopHeaderPhiBuilder {
latch_incoming: None,
},
);
// Phase 177-STRUCT-2: Record insertion order
info.carrier_order.push(name.clone());
if debug {
eprintln!(

View File

@ -29,6 +29,14 @@ pub struct LoopHeaderPhiInfo {
/// of this carrier during loop iteration.
pub carrier_phis: BTreeMap<String, CarrierPhiEntry>,
/// Phase 177-STRUCT-2: Carrier names in insertion order
///
/// Preserves the order in which carriers were added (matches exit_bindings order).
/// Used for index-based matching with loop_step params.
///
/// Order: [loop_var, carrier1, carrier2, ...]
pub carrier_order: Vec<String>,
/// Expression result PHI dst (if loop is used as expression)
///
/// For Pattern 2 (joinir_min_loop), this is the same as the loop
@ -55,10 +63,25 @@ impl LoopHeaderPhiInfo {
Self {
header_block,
carrier_phis: BTreeMap::new(),
carrier_order: Vec::new(),
expr_result_phi: None,
}
}
/// Phase 177-STRUCT-2: Get carrier name at index (in insertion order)
///
/// Used for matching loop_step params by index.
pub fn get_carrier_at_index(&self, idx: usize) -> Option<&str> {
self.carrier_order.get(idx).map(|s| s.as_str())
}
/// Phase 177-STRUCT-2: Get PHI entry at index (in insertion order)
pub fn get_entry_at_index(&self, idx: usize) -> Option<&CarrierPhiEntry> {
self.carrier_order
.get(idx)
.and_then(|name| self.carrier_phis.get(name))
}
/// Get the PHI dst for a carrier variable
pub fn get_carrier_phi(&self, name: &str) -> Option<ValueId> {
self.carrier_phis.get(name).map(|e| e.phi_dst)

View File

@ -340,12 +340,11 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
}
// Map loop_step's parameters
if debug {
eprintln!(
"[cf_loop/joinir] Phase 33-21: function_params keys: {:?}",
function_params.keys().collect::<Vec<_>>()
);
}
// DEBUG-177: Always log function_params keys to diagnose multi-carrier issue
eprintln!(
"[DEBUG-177] Phase 33-21: function_params keys: {:?}",
function_params.keys().collect::<Vec<_>>()
);
if function_params.get(loop_step_func_name).is_none() {
eprintln!(
"[cf_loop/joinir] WARNING: function_params.get('{}') returned None. Available keys: {:?}",
@ -354,32 +353,56 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
);
}
if let Some(loop_step_params) = function_params.get(loop_step_func_name) {
if debug {
eprintln!(
"[cf_loop/joinir] Phase 33-21: loop_step ({}) params: {:?}",
loop_step_func_name, loop_step_params
);
}
// Map loop_step's parameters to header PHI dsts
// loop_step params: [i_param, carrier1_param, ...]
// carrier_phis: [("i", entry), ("sum", entry), ...]
for (idx, (carrier_name, entry)) in phi_info.carrier_phis.iter().enumerate() {
if let Some(&loop_step_param) = loop_step_params.get(idx) {
// Phase 177-3: Don't override condition_bindings
if condition_binding_ids.contains(&loop_step_param) {
// DEBUG-177: Always log loop_step params
eprintln!(
"[DEBUG-177] Phase 33-21: loop_step ({}) params: {:?}",
loop_step_func_name, loop_step_params
);
// Phase 177-FIX: Process loop_step params but skip if already mapped
//
// We use a name-based approach: for each carrier_phi, check if
// its join_value was already set in Phase 177-3-B (body-only carriers).
// Only process loop_step params for carriers NOT already handled.
for loop_step_param in loop_step_params {
// Phase 177-3: Don't override condition_bindings
if condition_binding_ids.contains(loop_step_param) {
eprintln!(
"[DEBUG-177] Phase 177-FIX: Skipping condition_binding {:?}",
loop_step_param
);
continue;
}
// 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 &&
phi_info.carrier_phis.iter().any(|(name, _)| name == &cb.name)
});
if already_mapped {
eprintln!(
"[DEBUG-177] Phase 177-FIX: Skipping {:?} (already mapped by Phase 177-3-B)",
loop_step_param
);
continue;
}
// Phase 177-STRUCT-2: Use carrier_order for index-based matching
//
// Problem: BTreeMap iterates in alphabetical order, but JoinIR
// 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) {
// Map params[i] to carrier_order[i]
if let (Some(carrier_name), Some(entry)) = (
phi_info.get_carrier_at_index(param_idx),
phi_info.get_entry_at_index(param_idx),
) {
eprintln!(
"[cf_loop/joinir] Phase 177-3: Skipping override for condition_binding {:?} ('{}')",
loop_step_param, carrier_name
"[DEBUG-177] Phase 177-STRUCT-2: REMAP loop_step param[{}] {:?} {:?} (carrier '{}')",
param_idx, loop_step_param, entry.phi_dst, carrier_name
);
continue;
remapper.set_value(*loop_step_param, entry.phi_dst);
}
if debug {
eprintln!(
"[cf_loop/joinir] Phase 33-21: REMAP loop_step param {:?}{:?} ('{}')",
loop_step_param, entry.phi_dst, carrier_name
);
}
remapper.set_value(loop_step_param, entry.phi_dst);
}
}
}
@ -403,10 +426,15 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
);
}
}
for (idx, (carrier_name, entry)) in phi_info.carrier_phis.iter().enumerate() {
// Phase 177-STRUCT-2: Use carrier_order for deterministic iteration
for (idx, carrier_name) in phi_info.carrier_order.iter().enumerate() {
if carrier_name == loop_var_name {
continue;
}
let entry = match phi_info.carrier_phis.get(carrier_name) {
Some(e) => e,
None => continue,
};
let join_value_id = ValueId(idx as u32);
// Phase 177-3: Don't override condition_bindings
if !condition_binding_ids.contains(&join_value_id) {