Files
hakorune/src/mir/builder/control_flow/joinir/merge/mod.rs

1074 lines
43 KiB
Rust
Raw Normal View History

refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
//! JoinIR MIR Block Merging Coordinator
//!
//! This module coordinates the merging of JoinIR-generated MIR functions
//! into the host MIR builder. The process is broken into 6 phases:
//!
//! 1. Block ID allocation (block_allocator.rs)
//! 2. Value collection (value_collector.rs)
//! 3. ValueId remapping (uses JoinIrIdRemapper)
//! 4. Instruction rewriting (instruction_rewriter.rs)
//! 5. Exit PHI construction (exit_phi_builder.rs)
//! 6. Boundary reconnection (inline in this file)
//!
//! Phase 4 Refactoring: Breaking down 714-line merge_joinir_mir_blocks() into focused modules
mod block_allocator;
refactor(joinir): Phase 86 - Carrier init builder, debug migration, error tags P1: Carrier Initialization Builder (HIGH) ✅ - New module: carrier_init_builder.rs (197 lines, 8 tests) - Refactored loop_header_phi_builder.rs (-34 lines) - Centralized CarrierInit value generation (SSOT) - Eliminates scattered match patterns across header PHI, exit line - Consistent debug output: [carrier_init_builder] format - Net: -34 lines of duplicated logic P2: Remaining DebugOutputBox Migration (QUICK) ✅ - Migrated carrier_info.rs::record_promoted_binding() - Uses DebugOutputBox for JOINIR_DEBUG checks - Maintains JOINIR_TEST_DEBUG override for test diagnostics - Consistent log formatting: [context/category] message - Net: +3 lines (SSOT migration) P3: Error Message Centralization (LOW) ✅ - New module: error_tags.rs (136 lines, 5 tests) - Migrated 3 error sites: * ownership/relay:runtime_unsupported (plan_validator.rs) * joinir/freeze (control_flow/mod.rs) * (ExitLine errors were debug messages, not returns) - Centralized error tag generation (freeze, exit_line_contract, ownership_relay_unsupported, etc.) - Net: +133 lines (SSOT module + tests) Total changes: - New files: carrier_init_builder.rs (197), error_tags.rs (136) - Modified: 6 files - Production code: +162 lines (SSOT investment) - Tests: 987/987 PASS (982→987, +5 new tests) - Phase 81 ExitLine: 2/2 PASS - Zero compilation errors/warnings Benefits: ✅ Single Responsibility: Each helper has one concern ✅ Testability: 13 new unit tests (8 carrier init, 5 error tags) ✅ Consistency: Uniform debug/error formatting ✅ SSOT: Centralized CarrierInit and error tag generation ✅ Discoverability: Easy to find all error types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 21:48:02 +09:00
mod carrier_init_builder;
#[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_builder::LoopHeaderPhiBuilder;
pub use loop_header_phi_info::LoopHeaderPhiInfo;
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
use crate::mir::{MirModule, ValueId};
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
/// Phase 49-3.2: Merge JoinIR-generated MIR blocks into current_function
///
/// # Phase 189: Multi-Function MIR Merge
///
/// This merges JoinIR-generated blocks by:
/// 1. Remapping all block IDs across ALL functions to avoid conflicts
/// 2. Remapping all value IDs across ALL functions to avoid conflicts
/// 3. Adding all blocks from all functions to current_function
/// 4. Jumping from current_block to the entry block
/// 5. Converting Return → Jump to exit block for all functions
///
/// **Multi-Function Support** (Phase 189):
/// - Pattern 1 (Simple While) generates 3 functions: entry + loop_step + k_exit
/// - All functions are flattened into current_function with global ID remapping
/// - Single exit block receives all Return instructions from all functions
///
/// # Phase 188-Impl-3: JoinInlineBoundary Support
///
/// When `boundary` is provided, injects Copy instructions at the entry block
/// to connect host ValueIds to JoinIR local ValueIds:
///
/// ```text
/// entry_block:
/// // Injected by boundary
/// ValueId(100) = Copy ValueId(4) // join_input → host_input
/// // Original JoinIR instructions follow...
/// ```
///
/// This enables clean separation: JoinIR uses local IDs (0,1,2...),
/// host uses its own IDs, and Copy instructions bridge the gap.
///
/// # Returns
///
/// Returns `Ok(Some(exit_phi_id))` if the merged JoinIR functions have return values
/// that were collected into an exit block PHI. さらに、`boundary` に
/// host_outputs が指定されている場合は、exit PHI の結果をホスト側の
/// SSA スロットへ再接続するvariable_map 内の ValueId を更新する)。
pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
builder: &mut crate::mir::builder::MirBuilder,
mir_module: &MirModule,
boundary: Option<&JoinInlineBoundary>,
debug: bool,
) -> Result<Option<ValueId>, String> {
let verbose = debug || crate::config::env::joinir_dev_enabled();
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
if debug {
eprintln!(
"[cf_loop/joinir] merge_joinir_mir_blocks called with {} functions",
mir_module.functions.len()
);
}
if verbose {
if let Some(boundary) = boundary {
let exit_summary: Vec<String> = boundary
.exit_bindings
.iter()
.map(|b| {
format!(
"{}: join {:?} → host {:?} ({:?})",
b.carrier_name, b.join_exit_value, b.host_slot, b.role
)
})
.collect();
let cond_summary: Vec<String> = boundary
.condition_bindings
.iter()
.map(|b| {
format!(
"{}: host {:?} → join {:?}",
b.name, b.host_value, b.join_value
)
})
.collect();
eprintln!(
"[cf_loop/joinir] Boundary join_inputs={:?} host_inputs={:?}",
boundary.join_inputs, boundary.host_inputs
);
eprintln!(
"[cf_loop/joinir] Boundary exit_bindings ({}): {}",
boundary.exit_bindings.len(),
exit_summary.join(", ")
);
if !cond_summary.is_empty() {
eprintln!(
"[cf_loop/joinir] Boundary condition_bindings ({}): {}",
cond_summary.len(),
cond_summary.join(", ")
);
}
if let Some(ci) = &boundary.carrier_info {
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
);
}
} else {
eprintln!("[cf_loop/joinir] No boundary provided");
}
}
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
// 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)?;
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
// Phase 2: Collect values from all functions
let (mut used_values, value_to_func_name, function_params) =
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
value_collector::collect_values(mir_module, &remapper, debug)?;
// Phase 171-fix: Add condition_bindings' join_values to used_values for remapping
if let Some(boundary) = boundary {
for binding in &boundary.condition_bindings {
if debug {
eprintln!(
"[cf_loop/joinir] Phase 171-fix: Adding condition binding '{}' JoinIR {:?} to used_values",
binding.name, binding.join_value
);
}
used_values.insert(binding.join_value);
}
// Phase 172-3: Add exit_bindings' join_exit_values to used_values for remapping
for binding in &boundary.exit_bindings {
if debug {
eprintln!(
"[cf_loop/joinir] Phase 172-3: Adding exit binding '{}' JoinIR {:?} to used_values",
binding.carrier_name, binding.join_exit_value
);
}
used_values.insert(binding.join_exit_value);
}
}
// Phase 201-A: Build loop header PHI info BEFORE Phase 3
//
// We need to allocate PHI dst ValueIds before remap_values() runs,
// to prevent conflicts where a Const instruction gets a ValueId that
// will later be used as a PHI dst, causing carrier value corruption.
//
// This is a reordering of Phase 3 and Phase 3.5 logic.
let mut loop_header_phi_info = if let Some(boundary) = boundary {
if let Some(loop_var_name) = &boundary.loop_var_name {
// Get entry function and block for building PHI info
let (entry_func_name, entry_func) = mir_module
.functions
.iter()
.next()
.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
)
})?;
// 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")?;
// 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")?;
// 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()
};
if debug {
eprintln!(
"[cf_loop/joinir] Phase 201-A: Pre-building header PHIs for loop_var='{}' at {:?}",
loop_var_name, entry_block_remapped
);
eprintln!(
"[cf_loop/joinir] loop_var_init={:?}, carriers={:?}",
loop_var_init,
other_carriers
.iter()
.map(|(n, _, _, _)| n.as_str())
.collect::<Vec<_>>()
);
}
// Build PHI info (this allocates PHI dst ValueIds)
LoopHeaderPhiBuilder::build(
builder,
entry_block_remapped,
host_entry_block,
loop_var_name,
loop_var_init,
&other_carriers,
boundary.expr_result.is_some(),
debug,
)?
} else {
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(),
)
};
// 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
);
}
// 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
);
}
// Phase 3: Remap ValueIds (with reserved PHI dsts protection)
remap_values(
builder,
&used_values,
&mut remapper,
&reserved_phi_dsts,
debug,
)?;
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
// Phase 177-3 DEBUG: Verify remapper state after Phase 3
eprintln!("[DEBUG-177] === Remapper state after Phase 3 ===");
eprintln!("[DEBUG-177] used_values count: {}", used_values.len());
for value_id in &used_values {
if let Some(remapped) = remapper.get_value(*value_id) {
eprintln!("[DEBUG-177] JoinIR {:?} → Host {:?}", value_id, remapped);
} else {
eprintln!("[DEBUG-177] JoinIR {:?} → NOT FOUND ❌", value_id);
}
}
// Check condition_bindings specifically
if let Some(boundary) = boundary {
eprintln!("[DEBUG-177] === Condition bindings check ===");
for binding in &boundary.condition_bindings {
let lookup_result = remapper.get_value(binding.join_value);
eprintln!(
"[DEBUG-177] '{}': JoinIR {:?} → {:?}",
binding.name, binding.join_value, lookup_result
);
}
}
eprintln!("[DEBUG-177] ==============================");
// Phase 3.5: Override remapper for function parameters to use PHI dsts
//
// Phase 201-A: This phase now uses the loop_header_phi_info built before Phase 3.
// The PHI dst allocation has been moved earlier to prevent ValueId conflicts.
if let Some(boundary) = boundary {
if let Some(loop_var_name) = &boundary.loop_var_name {
// Phase 201-A: PHI info is already built (before Phase 3) - just use it
// 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, ...)
//
// The loop body uses loop_step's parameters, so we need to remap THOSE
// to the header PHI dsts, not main()'s parameters.
//
// We get loop_step's parameters from function_params collected earlier.
// 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, ...)
//
// ALL of these need to be mapped to header PHI dsts so that:
// 1. condition evaluation uses PHI result
// 2. loop body uses PHI result
// 3. tail call args are correctly routed
// Phase 177-3 fix: Protect condition-ONLY bindings from being overridden to PHI dsts
//
// Problem: condition_bindings may contain:
// 1. True condition-only variables (e.g., 'limit' in loop(i < limit)) - NOT carriers
// 2. Body-only carriers added by Phase 176-5 (e.g., 'result') - ARE carriers
//
// We must ONLY protect (1), not (2), because:
// - Condition-only vars should keep their HOST mapping (e.g., limit = %8)
// - Body-only carriers MUST be remapped to PHI dsts (e.g., result = %24)
//
// Solution: Protect condition_bindings that are NOT in exit_bindings (i.e., not carriers)
let carrier_names: std::collections::HashSet<&str> = boundary
.exit_bindings
.iter()
.map(|eb| eb.carrier_name.as_str())
.collect();
let condition_binding_ids: std::collections::HashSet<ValueId> = boundary
.condition_bindings
.iter()
.filter(|cb| !carrier_names.contains(cb.name.as_str()))
.map(|cb| cb.join_value)
.collect();
if !condition_binding_ids.is_empty() {
eprintln!(
"[cf_loop/joinir] Phase 177-3: Protected ValueIds (condition-only, not carriers): {:?}",
condition_binding_ids
);
for cb in &boundary.condition_bindings {
let is_carrier = carrier_names.contains(cb.name.as_str());
eprintln!(
"[cf_loop/joinir] Phase 177-3: '{}': JoinIR {:?} (carrier={})",
cb.name, cb.join_value, is_carrier
);
}
}
let main_func_name = "join_func_0";
let loop_step_func_name = "join_func_1";
if function_params.get(main_func_name).is_none() {
eprintln!(
"[cf_loop/joinir] WARNING: function_params.get('{}') returned None. Available keys: {:?}",
main_func_name,
function_params.keys().collect::<Vec<_>>()
);
}
if let Some(main_params) = function_params.get(main_func_name) {
eprintln!(
"[DEBUG-177] Phase 33-21: main ({}) params: {:?}",
main_func_name, main_params
);
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<_>>()
);
// 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()
{
if let Some(&main_param) = main_params.get(idx) {
// Phase 177-3: Don't override condition_bindings
if condition_binding_ids.contains(&main_param) {
eprintln!(
"[cf_loop/joinir] Phase 177-3: Skipping override for condition_binding {:?} ('{}')",
main_param, carrier_name
);
continue;
}
eprintln!(
"[DEBUG-177] Phase 33-21: REMAP main param[{}] {:?} → {:?} ('{}')",
idx, main_param, entry.phi_dst, carrier_name
);
remapper.set_value(main_param, entry.phi_dst);
}
}
}
// Phase 177-3-B: Handle body-only carriers
// These are carriers in carrier_phis that are NOT in main function params.
// 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)
{
// Skip if it's a true condition-only variable (already protected above)
if condition_binding_ids.contains(&binding.join_value) {
continue;
}
// This is a body-only carrier - remap it to PHI dst
eprintln!(
"[cf_loop/joinir] Phase 177-3-B: Body-only carrier '{}': JoinIR {:?} → PHI {:?}",
carrier_name, binding.join_value, entry.phi_dst
);
remapper.set_value(binding.join_value, entry.phi_dst);
}
}
// Map loop_step's parameters
// 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: {:?}",
loop_step_func_name,
function_params.keys().collect::<Vec<_>>()
);
}
if let Some(loop_step_params) = function_params.get(loop_step_func_name) {
// 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
&& loop_header_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)) = (
loop_header_phi_info.get_carrier_at_index(param_idx),
loop_header_phi_info.get_entry_at_index(param_idx),
) {
eprintln!(
"[DEBUG-177] Phase 177-STRUCT-2: REMAP loop_step param[{}] {:?} → {:?} (carrier '{}')",
param_idx, loop_step_param, entry.phi_dst, carrier_name
);
remapper.set_value(*loop_step_param, entry.phi_dst);
}
}
}
}
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) {
// Phase 177-3: Don't override condition_bindings
if !condition_binding_ids.contains(&ValueId(0)) {
remapper.set_value(ValueId(0), phi_dst);
if debug {
eprintln!(
"[cf_loop/joinir] Phase 33-16 fallback: Override remap ValueId(0) → {:?} (PHI dst)",
phi_dst
);
}
} else {
eprintln!(
"[cf_loop/joinir] Phase 177-3 fallback: Skipping override for condition_binding ValueId(0)"
);
}
}
// Phase 177-STRUCT-2: Use carrier_order for deterministic iteration
for (idx, carrier_name) in loop_header_phi_info.carrier_order.iter().enumerate() {
if carrier_name == loop_var_name {
continue;
}
let entry = match loop_header_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) {
remapper.set_value(join_value_id, entry.phi_dst);
if debug {
eprintln!(
"[cf_loop/joinir] Phase 33-20 fallback: Override remap {:?} → {:?} (carrier '{}' PHI dst)",
join_value_id, entry.phi_dst, carrier_name
);
}
} else {
eprintln!(
"[cf_loop/joinir] Phase 177-3 fallback: Skipping override for condition_binding {:?} ('{}')",
join_value_id, carrier_name
);
}
}
}
// Phase 177-3 DEBUG: Check remapper after Phase 33-21 overrides
eprintln!("[DEBUG-177] === Remapper state after Phase 33-21 ===");
for binding in &boundary.condition_bindings {
let lookup_result = remapper.get_value(binding.join_value);
eprintln!(
"[DEBUG-177] '{}': JoinIR {:?} → {:?} (after 33-21)",
binding.name, binding.join_value, lookup_result
);
}
// Phase 201-A: loop_header_phi_info already built (no assignment needed)
}
}
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
// Phase 4: Merge blocks and rewrite instructions
// Phase 33-16: Pass mutable loop_header_phi_info for latch_incoming tracking
// Phase 177-3: Pass exit_block_id from allocator to avoid conflicts
feat(joinir): Phase 33-14 JoinFragmentMeta for expr/carrier separation Introduces JoinFragmentMeta to distinguish between loop expression results and carrier variable updates, fixing SSA correctness issues. ## Changes ### New: JoinFragmentMeta struct (carrier_info.rs) - `expr_result: Option<ValueId>` - Loop as expression (return loop(...)) - `exit_meta: ExitMeta` - Carrier updates for variable_map - Helper methods: with_expr_result(), carrier_only(), empty() ### Pattern 2 Lowerer Updates - loop_with_break_minimal.rs: Returns (JoinModule, JoinFragmentMeta) - pattern2_with_break.rs: Sets boundary.expr_result from fragment_meta ### instruction_rewriter.rs - Phase 33-14: Only add to exit_phi_inputs when boundary.expr_result is Some - Phase 33-13: MergeResult struct with carrier_inputs map ### JoinInlineBoundary (inline_boundary.rs) - New field: expr_result: Option<ValueId> - All constructors updated with expr_result: None default ## Design Philosophy Previously, exit_phi_inputs mixed expr results with carrier updates, causing: - PHI inputs referencing undefined remapped values - SSA-undef errors in VM execution With JoinFragmentMeta: - expr_result → exit_phi_inputs (generates PHI for expr value) - exit_meta → carrier_inputs (updates variable_map via carrier PHIs) ## Test Results - Pattern 1 (carrier-only): Works correctly (no exit_phi_inputs) - Pattern 2 (expr result): Design complete, SSA-undef fix deferred to Phase 33-15 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 05:07:28 +09:00
let merge_result = instruction_rewriter::merge_and_rewrite(
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
builder,
mir_module,
&mut remapper,
&value_to_func_name,
&function_params,
boundary,
&mut loop_header_phi_info,
exit_block_id,
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
debug,
)?;
// Phase 4.5: Finalize loop header PHIs (insert into header block)
//
// By now, instruction_rewriter has set latch_incoming for all carriers.
// We can finalize the PHIs and insert them into the header block.
if !loop_header_phi_info.carrier_phis.is_empty() {
if debug {
eprintln!(
"[cf_loop/joinir] Phase 4.5: Finalizing {} header PHIs",
loop_header_phi_info.carrier_phis.len()
);
}
LoopHeaderPhiBuilder::finalize(builder, &loop_header_phi_info, debug)?;
}
// Phase 5: Build exit PHI (expr result only, not carrier PHIs)
// Phase 33-20: Carrier PHIs are now taken from header PHI info, not exit block
// Phase 246-EX: REVERT Phase 33-20 - Use EXIT PHI dsts, not header PHI dsts!
let (exit_phi_result_id, exit_carrier_phis) = exit_phi_builder::build_exit_phi(
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
builder,
feat(joinir): Phase 33-14 JoinFragmentMeta for expr/carrier separation Introduces JoinFragmentMeta to distinguish between loop expression results and carrier variable updates, fixing SSA correctness issues. ## Changes ### New: JoinFragmentMeta struct (carrier_info.rs) - `expr_result: Option<ValueId>` - Loop as expression (return loop(...)) - `exit_meta: ExitMeta` - Carrier updates for variable_map - Helper methods: with_expr_result(), carrier_only(), empty() ### Pattern 2 Lowerer Updates - loop_with_break_minimal.rs: Returns (JoinModule, JoinFragmentMeta) - pattern2_with_break.rs: Sets boundary.expr_result from fragment_meta ### instruction_rewriter.rs - Phase 33-14: Only add to exit_phi_inputs when boundary.expr_result is Some - Phase 33-13: MergeResult struct with carrier_inputs map ### JoinInlineBoundary (inline_boundary.rs) - New field: expr_result: Option<ValueId> - All constructors updated with expr_result: None default ## Design Philosophy Previously, exit_phi_inputs mixed expr results with carrier updates, causing: - PHI inputs referencing undefined remapped values - SSA-undef errors in VM execution With JoinFragmentMeta: - expr_result → exit_phi_inputs (generates PHI for expr value) - exit_meta → carrier_inputs (updates variable_map via carrier PHIs) ## Test Results - Pattern 1 (carrier-only): Works correctly (no exit_phi_inputs) - Pattern 2 (expr result): Design complete, SSA-undef fix deferred to Phase 33-15 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 05:07:28 +09:00
merge_result.exit_block_id,
&merge_result.exit_phi_inputs,
&merge_result.carrier_inputs,
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
debug,
)?;
// Phase 246-EX: CRITICAL FIX - Use exit PHI dsts for variable_map reconnection
//
// **Why EXIT PHI, not HEADER PHI?**
//
// Header PHI represents the value at the BEGINNING of each iteration.
// Exit PHI represents the FINAL value when leaving the loop (from any exit path).
//
// For Pattern 2 loops with multiple exit paths (natural exit + break):
// - Header PHI: `%15 = phi [%3, bb7], [%42, bb14]` (loop variable at iteration start)
// - Exit PHI: `%5 = phi [%15, bb11], [%15, bb13]` (final value from exit paths)
//
// When we exit the loop, we want the FINAL value (%5), not the iteration-start value (%15).
// Phase 33-20 incorrectly used header PHI, causing loops to return initial values (e.g., 0 instead of 42).
//
// Example (_atoi):
// - Initial: result=0 (header PHI)
// - After iteration 1: result=4 (updated in loop body)
// - After iteration 2: result=42 (updated in loop body)
// - Exit: Should return 42 (exit PHI), not 0 (header PHI initial value)
//
// The exit PHI correctly merges values from both exit paths, giving us the final result.
let carrier_phis = &exit_carrier_phis;
if debug && !carrier_phis.is_empty() {
eprintln!(
"[cf_loop/joinir] Phase 246-EX: Using EXIT PHI dsts for variable_map (not header): {:?}",
carrier_phis.iter().map(|(n, v)| (n.as_str(), v)).collect::<Vec<_>>()
);
}
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
// Phase 6: Reconnect boundary (if specified)
// Phase 197-B: Pass remapper to enable per-carrier exit value lookup
// Phase 33-10-Refactor-P3: Delegate to ExitLineOrchestrator
// Phase 246-EX: Now uses EXIT PHI dsts (reverted Phase 33-20)
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
if let Some(boundary) = boundary {
exit_line::ExitLineOrchestrator::execute(builder, boundary, carrier_phis, debug)?;
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
}
feat(joinir): Phase 33-14 JoinFragmentMeta for expr/carrier separation Introduces JoinFragmentMeta to distinguish between loop expression results and carrier variable updates, fixing SSA correctness issues. ## Changes ### New: JoinFragmentMeta struct (carrier_info.rs) - `expr_result: Option<ValueId>` - Loop as expression (return loop(...)) - `exit_meta: ExitMeta` - Carrier updates for variable_map - Helper methods: with_expr_result(), carrier_only(), empty() ### Pattern 2 Lowerer Updates - loop_with_break_minimal.rs: Returns (JoinModule, JoinFragmentMeta) - pattern2_with_break.rs: Sets boundary.expr_result from fragment_meta ### instruction_rewriter.rs - Phase 33-14: Only add to exit_phi_inputs when boundary.expr_result is Some - Phase 33-13: MergeResult struct with carrier_inputs map ### JoinInlineBoundary (inline_boundary.rs) - New field: expr_result: Option<ValueId> - All constructors updated with expr_result: None default ## Design Philosophy Previously, exit_phi_inputs mixed expr results with carrier updates, causing: - PHI inputs referencing undefined remapped values - SSA-undef errors in VM execution With JoinFragmentMeta: - expr_result → exit_phi_inputs (generates PHI for expr value) - exit_meta → carrier_inputs (updates variable_map via carrier PHIs) ## Test Results - Pattern 1 (carrier-only): Works correctly (no exit_phi_inputs) - Pattern 2 (expr result): Design complete, SSA-undef fix deferred to Phase 33-15 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 05:07:28 +09:00
let exit_block_id = merge_result.exit_block_id;
// Phase 201-A: Get entry block from loop_header_phi_info
// The header_block in loop_header_phi_info is the remapped entry block
let entry_block = loop_header_phi_info.header_block;
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
if debug {
eprintln!(
"[cf_loop/joinir] Entry block (from loop_header_phi_info): {:?}",
entry_block
);
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
eprintln!(
"[cf_loop/joinir] Current block before emit_jump: {:?}",
builder.current_block
);
eprintln!(
"[cf_loop/joinir] Jumping to entry block: {:?}",
entry_block
);
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
}
crate::mir::builder::emission::branch::emit_jump(builder, entry_block)?;
if debug {
eprintln!(
"[cf_loop/joinir] After emit_jump, current_block: {:?}",
builder.current_block
);
}
// Switch to exit block for subsequent code
builder.start_new_block(exit_block_id)?;
if debug {
eprintln!(
"[cf_loop/joinir] Phase 189: Merge complete: {} functions merged, continuing from {:?}",
mir_module.functions.len(),
exit_block_id
);
}
// Phase 200-3: Verify JoinIR contracts (debug only)
#[cfg(debug_assertions)]
{
if let Some(boundary) = boundary {
if let Some(ref func) = builder.current_function {
verify_joinir_contracts(
func,
entry_block,
exit_block_id,
&loop_header_phi_info,
boundary,
);
}
if debug {
eprintln!("[cf_loop/joinir] Phase 200-3: Contract verification passed");
}
}
}
// Phase 201-A: Clear reserved ValueIds after merge completes
// 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
);
}
builder.reserved_value_ids.clear();
}
// Phase 246-EX-FIX: Handle loop variable expr_result separately from carrier expr_result
//
// The loop variable (e.g., 'i') is returned via exit_phi_result_id, not carrier_phis.
// Other carriers use carrier_phis. We need to check which case we're in.
let expr_result_value = if let Some(b) = boundary {
if let Some(expr_result_id) = b.expr_result {
// 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()
.find(|binding| binding.carrier_name == *loop_var_name);
if let Some(binding) = loop_var_binding {
if binding.join_exit_value == expr_result_id {
// expr_result is the loop variable! Use exit_phi_result_id
if debug {
eprintln!(
"[cf_loop/joinir] Phase 246-EX-FIX: expr_result {:?} is loop variable '{}', using exit_phi_result_id {:?}",
expr_result_id, loop_var_name, exit_phi_result_id
);
}
exit_phi_result_id
} else {
// expr_result is not the loop variable, resolve as carrier
expr_result_resolver::ExprResultResolver::resolve(
Some(expr_result_id),
b.exit_bindings.as_slice(),
&carrier_phis,
&remapper,
debug,
)?
}
} else {
// No loop variable binding, resolve normally
expr_result_resolver::ExprResultResolver::resolve(
Some(expr_result_id),
b.exit_bindings.as_slice(),
&carrier_phis,
&remapper,
debug,
)?
}
} else {
// No loop variable name, resolve normally
expr_result_resolver::ExprResultResolver::resolve(
Some(expr_result_id),
b.exit_bindings.as_slice(),
&carrier_phis,
&remapper,
debug,
)?
}
} else {
None
}
} else {
None
};
// 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
);
}
Ok(Some(resolved))
} else {
// Fallback: return exit_phi_result_id (for legacy patterns or carrier-only loops)
if debug && exit_phi_result_id.is_some() {
eprintln!(
"[cf_loop/joinir] Phase 221-R: Returning exit_phi_result_id (fallback): {:?}",
exit_phi_result_id
);
}
Ok(exit_phi_result_id)
}
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
}
/// Phase 3: Allocate new ValueIds for all collected values
///
/// Phase 201-A: Accept reserved ValueIds that must not be reused.
/// These are PHI dst ValueIds that will be created by LoopHeaderPhiBuilder.
/// We must skip these IDs to prevent carrier value corruption.
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
fn remap_values(
builder: &mut crate::mir::builder::MirBuilder,
used_values: &std::collections::BTreeSet<ValueId>,
remapper: &mut crate::mir::builder::joinir_id_remapper::JoinIrIdRemapper,
reserved_ids: &std::collections::HashSet<ValueId>,
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
debug: bool,
) -> Result<(), String> {
if debug {
eprintln!(
"[cf_loop/joinir] Phase 3: Remapping {} ValueIds (reserved: {})",
used_values.len(),
reserved_ids.len()
);
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
}
for old_value in used_values {
// Phase 201-A: Allocate new ValueId, skipping reserved PHI dsts
let new_value = loop {
let candidate = builder.next_value_id();
if !reserved_ids.contains(&candidate) {
break candidate;
}
// Skip reserved ID - will try next one
if debug {
eprintln!(
"[cf_loop/joinir] Phase 201-A: Skipping reserved PHI dst {:?}",
candidate
);
}
};
refactor: Break down merge_joinir_mir_blocks into 6 modules (Phase 4) Phase 4 Implementation Complete: Successfully modularized the 714-line merge_joinir_mir_blocks() function into 6 focused, maintainable modules. ## Changes Made ### 1. Created Module Structure - `src/mir/builder/control_flow/joinir/merge/` directory - 5 sub-modules + 1 coordinator (6 files total) ### 2. Module Breakdown (848 lines total) - **mod.rs** (223 lines) - Coordinator function - Orchestrates all 6 phases - Handles boundary reconnection - Manages entry/exit block jumps - **block_allocator.rs** (70 lines) - Block ID allocation - Allocates new BlockIds for all JoinIR functions - Maintains determinism via sorted iteration - **value_collector.rs** (90 lines) - Value collection - Collects all ValueIds from JoinIR functions - Builds auxiliary maps for Call→Jump conversion - **instruction_rewriter.rs** (405 lines) - Instruction rewriting - Rewrites instructions with remapped IDs - Handles tail call optimization - Converts Return → Jump to exit block - **exit_phi_builder.rs** (60 lines) - Exit PHI construction - Builds PHI node merging return values - Creates exit block ### 3. Updated control_flow/mod.rs - Replaced 714-line function with 18-line delegation - Reduced from 904 lines → 312 lines (65% reduction) - Added documentation explaining Phase 4 refactoring ## Verification Results ✅ **Build**: `cargo build --release` - SUCCESS (23.36s) ✅ **Smoke Test**: loop_min_while.hako - PASS (correct output: 0,1,2) ✅ **Determinism**: 3 consecutive runs - IDENTICAL OUTPUT ✅ **Debug Traces**: NYASH_OPTION_C_DEBUG=1 traces work correctly ✅ **No Regressions**: Behavior preserved 100% ## Benefits 1. **Maintainability**: 714 lines → 6 focused modules (100-150 lines each) 2. **Readability**: Each phase isolated in its own file 3. **Testability**: Individual modules can be tested separately 4. **Future Development**: Easy to modify individual phases 5. **Zero Breaking Changes**: Backward compatible, no API changes ## Technical Notes - Uses JoinIrIdRemapper (already existed) for ID translation - Preserves all debug output and trace functionality - Maintains determinism via BTreeSet/BTreeMap - All Phase 189 features intact (multi-function support, etc.) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 21:00:55 +09:00
remapper.set_value(*old_value, new_value);
if debug {
eprintln!(
"[cf_loop/joinir] Value remap: {:?} → {:?}",
old_value, new_value
);
}
}
Ok(())
}
/// Verify that PHI dst values are not overwritten by later instructions (Phase 204-2)
///
/// # Checks
///
/// 1. PHI instructions define dst values in header block
/// 2. No subsequent instruction in the same block overwrites these dsts
///
/// # Rationale
///
/// PHI dst overwrite violates SSA invariant (single assignment) and causes undefined behavior.
/// While Phase 201 JoinValueSpace prevents ValueId collisions, manual coding errors can still
/// occur during pattern lowering.
///
/// # Panics
///
/// Panics in debug mode if PHI dst is overwritten by a later instruction.
#[cfg(debug_assertions)]
fn verify_no_phi_dst_overwrite(
func: &crate::mir::MirFunction,
header_block: crate::mir::BasicBlockId,
loop_info: &LoopHeaderPhiInfo,
) {
if loop_info.carrier_phis.is_empty() {
return; // No PHIs to verify
}
let header_block_data = func.blocks.get(&header_block).unwrap_or_else(|| {
panic!(
"[JoinIRVerifier] Header block {} not found ({} blocks in func)",
header_block,
func.blocks.len()
)
});
// 1. Collect all PHI dsts
let phi_dsts: std::collections::HashSet<crate::mir::ValueId> = loop_info
.carrier_phis
.values()
.map(|entry| entry.phi_dst)
.collect();
// 2. Check instructions after PHI definitions
let mut after_phis = false;
for instr in &header_block_data.instructions {
match instr {
crate::mir::MirInstruction::Phi { dst, .. } => {
// PHI instructions come first in basic block
if after_phis {
panic!(
"[JoinIRVerifier] PHI instruction {:?} appears after non-PHI instructions in block {}",
dst, header_block.0
);
}
}
_ => {
after_phis = true;
// Check if this instruction writes to a PHI dst
if let Some(dst) = get_instruction_dst(instr) {
if phi_dsts.contains(&dst) {
panic!(
"[JoinIRVerifier/Phase204] PHI dst {:?} is overwritten by instruction in header block {}: {:?}",
dst, header_block.0, instr
);
}
}
}
}
}
}
/// Helper: Extract dst ValueId from MirInstruction (Phase 204-2)
#[cfg(debug_assertions)]
fn get_instruction_dst(instr: &crate::mir::MirInstruction) -> Option<crate::mir::ValueId> {
use crate::mir::MirInstruction;
match instr {
// Instructions with always-present dst
MirInstruction::Const { dst, .. }
| MirInstruction::Load { dst, .. }
| MirInstruction::UnaryOp { dst, .. }
| MirInstruction::BinOp { dst, .. }
| MirInstruction::Compare { dst, .. }
| MirInstruction::TypeOp { dst, .. }
| MirInstruction::NewBox { dst, .. }
| MirInstruction::NewClosure { dst, .. }
| MirInstruction::Copy { dst, .. }
| MirInstruction::Cast { dst, .. }
| MirInstruction::TypeCheck { dst, .. }
| MirInstruction::Phi { dst, .. }
| MirInstruction::ArrayGet { dst, .. }
| MirInstruction::RefNew { dst, .. }
| MirInstruction::RefGet { dst, .. }
| MirInstruction::WeakNew { dst, .. }
| MirInstruction::WeakLoad { dst, .. }
| MirInstruction::WeakRef { dst, .. }
| MirInstruction::FutureNew { dst, .. }
| MirInstruction::Await { dst, .. } => Some(*dst),
// Instructions with Option<ValueId> dst
MirInstruction::BoxCall { dst, .. }
| MirInstruction::ExternCall { dst, .. }
| MirInstruction::Call { dst, .. }
| MirInstruction::PluginInvoke { dst, .. } => *dst,
// Instructions without dst (side-effects only)
_ => None,
}
}
feat(joinir): Phase 204 PHI Contract Verifier complete Phase 204-3/5/6/7: PHI inputs verification, integration, testing, docs Implementation: - verify_phi_inputs_defined(): Conservative sanity checks (ValueId < 100000) - Integration: All verifiers in verify_joinir_contracts() - Testing: 821 tests PASS, no regressions Task Status: - ✅ 204-1: Design document (phase204-phi-contract-verifier.md) - ✅ 204-2: PHI dst overwrite detection - ✅ 204-3: PHI inputs sanity checks - ⚠️ 204-4: JoinValueSpace region verification (deferred to Phase 205+) - Rationale: Requires LoopHeaderPhiInfo extension (4+ files) - Alternative: Conservative threshold checks in verify_phi_inputs_defined() - ✅ 204-5: Integration (verify_joinir_contracts) - ✅ 204-6: Tests (821 PASS) - ✅ 204-7: Documentation (phase204 doc + CURRENT_TASK.md) Verification Coverage: - ✅ PHI exists (Phase 200-3) - ✅ PHI dst match (Phase 200-3) - ✅ PHI dst not overwritten (Phase 204-2) ✨ - ✅ PHI inputs sanity (Phase 204-3) ✨ - ⚠️ PHI inputs DFA (Phase 205+) - ⚠️ ValueId regions (Phase 205+) Design Principles: - Debug-only (#[cfg(debug_assertions)]) - Fail-Fast (panic on violation) - Zero cost in release builds Files Modified: - src/mir/builder/control_flow/joinir/merge/mod.rs (+115 lines) - src/mir/builder/control_flow/joinir/merge/exit_line/reconnector.rs (1 line) - docs/development/current/main/phase204-phi-contract-verifier.md (updated) - CURRENT_TASK.md (Phase 204 complete) Success Criteria: 4/5 met (1 deferred with rationale)
2025-12-09 19:57:32 +09:00
/// Verify PHI inputs are defined (Phase 204-3 - Conservative sanity checks)
///
/// # Checks
///
/// 1. PHI inputs have reasonable ValueId values (< threshold)
/// 2. No obviously undefined values (e.g., suspiciously large IDs)
///
/// # Note
///
/// Full data-flow analysis (DFA) verification is deferred to Phase 205+.
/// This function only performs conservative sanity checks.
///
/// # Panics
///
/// Panics in debug mode if suspicious PHI inputs are detected.
#[cfg(debug_assertions)]
fn verify_phi_inputs_defined(
func: &crate::mir::MirFunction,
header_block: crate::mir::BasicBlockId,
) {
let header_block_data = func.blocks.get(&header_block).unwrap_or_else(|| {
panic!(
"[JoinIRVerifier] Header block {} not found ({} blocks in func)",
header_block,
func.blocks.len()
)
});
for instr in &header_block_data.instructions {
if let crate::mir::MirInstruction::Phi {
dst,
inputs,
type_hint: _,
} = instr
{
feat(joinir): Phase 204 PHI Contract Verifier complete Phase 204-3/5/6/7: PHI inputs verification, integration, testing, docs Implementation: - verify_phi_inputs_defined(): Conservative sanity checks (ValueId < 100000) - Integration: All verifiers in verify_joinir_contracts() - Testing: 821 tests PASS, no regressions Task Status: - ✅ 204-1: Design document (phase204-phi-contract-verifier.md) - ✅ 204-2: PHI dst overwrite detection - ✅ 204-3: PHI inputs sanity checks - ⚠️ 204-4: JoinValueSpace region verification (deferred to Phase 205+) - Rationale: Requires LoopHeaderPhiInfo extension (4+ files) - Alternative: Conservative threshold checks in verify_phi_inputs_defined() - ✅ 204-5: Integration (verify_joinir_contracts) - ✅ 204-6: Tests (821 PASS) - ✅ 204-7: Documentation (phase204 doc + CURRENT_TASK.md) Verification Coverage: - ✅ PHI exists (Phase 200-3) - ✅ PHI dst match (Phase 200-3) - ✅ PHI dst not overwritten (Phase 204-2) ✨ - ✅ PHI inputs sanity (Phase 204-3) ✨ - ⚠️ PHI inputs DFA (Phase 205+) - ⚠️ ValueId regions (Phase 205+) Design Principles: - Debug-only (#[cfg(debug_assertions)]) - Fail-Fast (panic on violation) - Zero cost in release builds Files Modified: - src/mir/builder/control_flow/joinir/merge/mod.rs (+115 lines) - src/mir/builder/control_flow/joinir/merge/exit_line/reconnector.rs (1 line) - docs/development/current/main/phase204-phi-contract-verifier.md (updated) - CURRENT_TASK.md (Phase 204 complete) Success Criteria: 4/5 met (1 deferred with rationale)
2025-12-09 19:57:32 +09:00
for (value_id, pred_block) in inputs {
// Conservative sanity check: ValueId should not be suspiciously large
// Phase 201 JoinValueSpace uses regions:
// - PHI Reserved: 0-99
// - Param: 100-999
// - Local: 1000+
// - Reasonable max: 100000 (arbitrary but catches obvious bugs)
if value_id.0 >= 100000 {
panic!(
"[JoinIRVerifier/Phase204-3] PHI {:?} has suspiciously large input {:?} from predecessor block {:?}",
dst, value_id, pred_block
);
}
}
}
}
}
/// Verify all loop contracts for a merged JoinIR function
///
/// This is the main entry point for verification. It runs all checks
/// and panics if any contract violation is found.
///
/// # Panics
///
/// Panics in debug mode if any contract violation is detected.
#[cfg(debug_assertions)]
fn verify_joinir_contracts(
func: &crate::mir::MirFunction,
header_block: crate::mir::BasicBlockId,
exit_block: crate::mir::BasicBlockId,
loop_info: &LoopHeaderPhiInfo,
boundary: &JoinInlineBoundary,
) {
contract_checks::verify_loop_header_phis(func, header_block, loop_info, boundary);
verify_no_phi_dst_overwrite(func, header_block, loop_info); // Phase 204-2
feat(joinir): Phase 204 PHI Contract Verifier complete Phase 204-3/5/6/7: PHI inputs verification, integration, testing, docs Implementation: - verify_phi_inputs_defined(): Conservative sanity checks (ValueId < 100000) - Integration: All verifiers in verify_joinir_contracts() - Testing: 821 tests PASS, no regressions Task Status: - ✅ 204-1: Design document (phase204-phi-contract-verifier.md) - ✅ 204-2: PHI dst overwrite detection - ✅ 204-3: PHI inputs sanity checks - ⚠️ 204-4: JoinValueSpace region verification (deferred to Phase 205+) - Rationale: Requires LoopHeaderPhiInfo extension (4+ files) - Alternative: Conservative threshold checks in verify_phi_inputs_defined() - ✅ 204-5: Integration (verify_joinir_contracts) - ✅ 204-6: Tests (821 PASS) - ✅ 204-7: Documentation (phase204 doc + CURRENT_TASK.md) Verification Coverage: - ✅ PHI exists (Phase 200-3) - ✅ PHI dst match (Phase 200-3) - ✅ PHI dst not overwritten (Phase 204-2) ✨ - ✅ PHI inputs sanity (Phase 204-3) ✨ - ⚠️ PHI inputs DFA (Phase 205+) - ⚠️ ValueId regions (Phase 205+) Design Principles: - Debug-only (#[cfg(debug_assertions)]) - Fail-Fast (panic on violation) - Zero cost in release builds Files Modified: - src/mir/builder/control_flow/joinir/merge/mod.rs (+115 lines) - src/mir/builder/control_flow/joinir/merge/exit_line/reconnector.rs (1 line) - docs/development/current/main/phase204-phi-contract-verifier.md (updated) - CURRENT_TASK.md (Phase 204 complete) Success Criteria: 4/5 met (1 deferred with rationale)
2025-12-09 19:57:32 +09:00
verify_phi_inputs_defined(func, header_block); // Phase 204-3
contract_checks::verify_exit_line(func, exit_block, boundary);
contract_checks::verify_valueid_regions(loop_info, boundary); // Phase 205-4
}