diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index 3de9787a..493c4bb1 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -2,7 +2,10 @@ ## Current Focus: Phase 29ag(JoinIR merge SSOT unification) -Next: `docs/development/current/main/phases/phase-29ag/P0-COORDINATOR-USES-BOUNDARY-CARRIER-LAYOUT-INSTRUCTIONS.md` +**2025-12-29: Phase 29ag P1 完了** ✅ +- 目的: coordinator の ValueId(idx) 前提を撤去し、boundary.join_inputs を SSOT 化(仕様不変) +- 入口: `docs/development/current/main/phases/phase-29ag/README.md` +- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` PASS **2025-12-29: Phase 29af P5 完了** ✅ - 目的: 29af を closeout して JoinIR 回帰確認を 1 本に収束(仕様不変) diff --git a/docs/development/current/main/30-Backlog.md b/docs/development/current/main/30-Backlog.md index 89b077e3..ad16acef 100644 --- a/docs/development/current/main/30-Backlog.md +++ b/docs/development/current/main/30-Backlog.md @@ -11,7 +11,7 @@ Related: - **Phase 29af(✅ COMPLETE): Boundary hygiene / regression entrypoint / carrier layout SSOT** - 入口: `docs/development/current/main/phases/phase-29af/README.md` -- **Phase 29ag(candidate): JoinIR merge の追加安定化** +- **Phase 29ag(✅ COMPLETE): JoinIR merge SSOT unification** - 入口: `docs/development/current/main/phases/phase-29ag/README.md` - **Phase 29ae P1(✅ COMPLETE): JoinIR Regression Pack (SSOT固定)** diff --git a/docs/development/current/main/phases/phase-29ag/README.md b/docs/development/current/main/phases/phase-29ag/README.md index cbc153f4..acde0194 100644 --- a/docs/development/current/main/phases/phase-29ag/README.md +++ b/docs/development/current/main/phases/phase-29ag/README.md @@ -2,6 +2,11 @@ Goal: Phase 29af で固めた boundary/layout/contract を前提に、merge 内の order SSOT をさらに一箇所へ寄せて回帰余地を減らす(仕様不変)。 +## Status + +- P0: ✅ COMPLETE +- P1: ✅ COMPLETE + ## Why now - Phase 29af で carrier order SSOT(`BoundaryCarrierLayout`)と整合契約(P4)まで揃った @@ -9,10 +14,12 @@ Goal: Phase 29af で固めた boundary/layout/contract を前提に、merge 内 ## P0: Coordinator param remap uses BoundaryCarrierLayout +- ✅ COMPLETE - 指示書: `docs/development/current/main/phases/phase-29ag/P0-COORDINATOR-USES-BOUNDARY-CARRIER-LAYOUT-INSTRUCTIONS.md` ## P1: Eliminate ValueId(i) fallback; remap via boundary.join_inputs +- ✅ COMPLETE - 指示書: `docs/development/current/main/phases/phase-29ag/P1-COORDINATOR-REMAPPERS-USE-JOIN_INPUTS-INSTRUCTIONS.md` ## Verification (SSOT) diff --git a/src/mir/builder/control_flow/joinir/merge/coordinator.rs b/src/mir/builder/control_flow/joinir/merge/coordinator.rs index d97dd432..7010690e 100644 --- a/src/mir/builder/control_flow/joinir/merge/coordinator.rs +++ b/src/mir/builder/control_flow/joinir/merge/coordinator.rs @@ -285,8 +285,8 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks( // Phase 33-21: Override remapper for loop_step's parameters // // JoinIR generates separate parameter ValueIds for each function: - // - main(): ValueId(0), ValueId(1), ... for (i_init, carrier1_init, ...) - // - loop_step(): ValueId(3), ValueId(4), ... for (i_param, carrier1_param, ...) + // - main(): boundary.join_inputs slots for (i_init, carrier1_init, ...) + // - loop_step(): loop_step params for (i_param, carrier1_param, ...) // // The loop body uses loop_step's parameters, so we need to remap THOSE // to the header PHI dsts, not main()'s parameters. @@ -295,8 +295,8 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks( // Phase 33-21: Override remapper for ALL functions' parameters // // JoinIR generates separate parameter ValueIds for each function: - // - main (join_func_0): ValueId(0), ValueId(1), ... for (i_init, carrier1_init, ...) - // - loop_step (join_func_1): ValueId(3), ValueId(4), ... for (i_param, carrier1_param, ...) + // - main (join_func_0): boundary.join_inputs slots for (i_init, carrier1_init, ...) + // - loop_step (join_func_1): loop_step params for (i_param, carrier1_param, ...) // // ALL of these need to be mapped to header PHI dsts so that: // 1. condition evaluation uses PHI result @@ -370,6 +370,8 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks( verbose, ); } + let layout = boundary_carrier_layout::BoundaryCarrierLayout::from_boundary(boundary); + let layout_names = layout.ordered_names(); if let Some(main_params) = function_params.get(main_func_name) { trace.stderr_if( &format!( @@ -391,14 +393,11 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks( verbose, ); // Map main's parameters to header PHI dsts. - // - // IMPORTANT: Do not iterate carrier_phis (BTreeMap) here. - // JoinIR params are laid out in carrier_order, not alphabetical order. for (idx, &main_param) in main_params.iter().enumerate() { - let (Some(carrier_name), Some(entry)) = ( - loop_header_phi_info.get_carrier_at_index(idx), - loop_header_phi_info.get_entry_at_index(idx), - ) else { + let Some(carrier_name) = layout_names.get(idx) else { + continue; + }; + let Some(entry) = loop_header_phi_info.carrier_phis.get(*carrier_name) else { continue; }; @@ -460,8 +459,6 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks( ), verbose, ); - let layout = boundary_carrier_layout::BoundaryCarrierLayout::from_boundary(boundary); - let layout_names = layout.ordered_names(); if function_params.get(loop_step_func_name).is_none() { trace.stderr_if( &format!( @@ -543,27 +540,38 @@ 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() { - // Fallback: Use old behavior (ValueId(0), ValueId(1), ...) - // This handles patterns that don't have loop_step function + // Fallback: Use boundary.join_inputs for remap (no ValueId(idx) assumption). if let Some(phi_dst) = loop_header_phi_info.get_carrier_phi(loop_var_name) { - // Phase 177-3: Don't override condition_bindings - if !condition_binding_ids.contains(&ValueId(0)) { - remapper.set_value(ValueId(0), phi_dst); - trace.stderr_if( - &format!( - "[cf_loop/joinir] Phase 33-16 fallback: Override remap ValueId(0) → {:?} (PHI dst)", - phi_dst - ), - debug, - ); - } else { - trace.stderr_if( - "[cf_loop/joinir] Phase 177-3 fallback: Skipping override for condition_binding ValueId(0)", - verbose, - ); + let join_ids = boundary.join_inputs.as_slice(); + let loop_var_idx = layout_names + .iter() + .position(|name| *name == loop_var_name); + if let Some(idx) = loop_var_idx { + if let Some(&join_value_id) = join_ids.get(idx) { + // Phase 177-3: Don't override condition_bindings + if !condition_binding_ids.contains(&join_value_id) { + remapper.set_value(join_value_id, phi_dst); + trace.stderr_if( + &format!( + "[cf_loop/joinir] Phase 33-16 fallback: Override remap {:?} → {:?} (PHI dst)", + join_value_id, phi_dst + ), + debug, + ); + } else { + trace.stderr_if( + &format!( + "[cf_loop/joinir] Phase 177-3 fallback: Skipping override for condition_binding {:?}", + join_value_id + ), + verbose, + ); + } + } } } - // Phase 29ag P0: Use BoundaryCarrierLayout for deterministic iteration + // Phase 29ag P1: Use boundary.join_inputs for remap instead of ValueId(idx). + let join_ids = boundary.join_inputs.as_slice(); for (idx, carrier_name) in layout_names.iter().enumerate() { if *carrier_name == loop_var_name { continue; @@ -572,7 +580,9 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks( Some(e) => e, None => continue, }; - let join_value_id = ValueId(idx as u32); + let Some(&join_value_id) = join_ids.get(idx) else { + continue; + }; // Phase 177-3: Don't override condition_bindings if !condition_binding_ids.contains(&join_value_id) { remapper.set_value(join_value_id, entry.phi_dst); diff --git a/src/mir/builder/control_flow/joinir/merge/loop_header_phi_info.rs b/src/mir/builder/control_flow/joinir/merge/loop_header_phi_info.rs index a31dca4a..1b64e592 100644 --- a/src/mir/builder/control_flow/joinir/merge/loop_header_phi_info.rs +++ b/src/mir/builder/control_flow/joinir/merge/loop_header_phi_info.rs @@ -73,20 +73,6 @@ impl LoopHeaderPhiInfo { } } - /// 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 { self.carrier_phis.get(name).map(|e| e.phi_dst)