## Problem `block_end_values` used block ID only as key, causing collisions when multiple functions share the same block IDs (e.g., bb0 in both condition_fn and main). ## Root Cause - condition_fn's bb0 → block_end_values[0] - main's bb0 → block_end_values[0] (OVERWRITES!) - PHI resolution gets wrong snapshot → dominance error ## Solution (Box-First principle) Change key from `int` to `Tuple[str, int]` (func_name, block_id): ```python # Before block_end_values: Dict[int, Dict[int, ir.Value]] # After block_end_values: Dict[Tuple[str, int], Dict[int, ir.Value]] ``` ## Files Modified (Python - 6 files) 1. `llvm_builder.py` - Type annotation update 2. `function_lower.py` - Pass func_name to lower_blocks 3. `block_lower.py` - Use tuple keys for snapshot save/load 4. `resolver.py` - Add func_name parameter to resolve_incoming 5. `wiring.py` - Thread func_name through PHI wiring 6. `phi_manager.py` - Debug traces ## Files Modified (Rust - cleanup) - Removed deprecated `loop_to_join.rs` (297 lines deleted) - Updated pattern lowerers for cleaner exit handling - Added lifecycle management improvements ## Verification - ✅ Pattern 1: VM RC: 3, LLVM Result: 3 (no regression) - ⚠️ Case C: Still has dominance error (separate root cause) - Needs additional scope fixes (phi_manager, resolver caches) ## Design Principles - **Box-First**: Each function is an isolated Box with scoped state - **SSOT**: (func_name, block_id) uniquely identifies block snapshots - **Fail-Fast**: No cross-function state contamination ## Known Issues (Phase 132-P1) Other function-local state needs same treatment: - phi_manager.predeclared - resolver caches (i64_cache, ptr_cache, etc.) - builder._jump_only_blocks ## Documentation - docs/development/current/main/investigations/phase132-p0-case-c-root-cause.md - docs/development/current/main/investigations/phase132-p0-tuple-key-implementation.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
181 lines
6.9 KiB
Rust
181 lines
6.9 KiB
Rust
//! # Loop Pattern JoinIR Lowering Router
|
|
//!
|
|
//! **Phase 33-12 Modularization**: Extracted from `mod.rs` (lines 424-511)
|
|
//!
|
|
//! ## Responsibility
|
|
//! Routes loop patterns to appropriate JoinIR lowering strategies.
|
|
//! This is the **main entry point** for loop → JoinIR lowering.
|
|
//!
|
|
//! ## Pattern Dispatch
|
|
//! Routes to:
|
|
//! - Pattern 1: `loop_patterns::simple_while` (no break/continue)
|
|
//! - Pattern 2: `loop_patterns::with_break` (conditional break)
|
|
//! - Pattern 3: `loop_patterns::with_if_phi` (if + PHI merging)
|
|
//! - Pattern 4: `loop_patterns::with_continue` (deferred to Phase 195)
|
|
//!
|
|
//! ## Why Separate Router?
|
|
//! See `if_lowering_router.rs` for rationale.
|
|
//! Summary: Orthogonal concerns, easier to maintain/extend.
|
|
//!
|
|
//! # Routing Strategy
|
|
//!
|
|
//! This router uses structure-based pattern classification (Phase 194):
|
|
//! 1. Extract CFG features from LoopForm
|
|
//! 2. Classify into pattern kind (1-4 or Unknown) using `loop_pattern_detection::classify`
|
|
//! 3. Route to appropriate pattern lowerer
|
|
//!
|
|
//! # Phase 183: Unified Detection
|
|
//!
|
|
//! This router shares pattern detection logic with `patterns/router.rs`.
|
|
//! Both use `loop_pattern_detection::classify()` for consistent classification.
|
|
//!
|
|
//! # Pattern Priority (Phase 188)
|
|
//!
|
|
//! Patterns are tried in complexity order:
|
|
//! - **Pattern 4: Continue** (highest complexity)
|
|
//! - **Pattern 3: If-Else PHI** (leverages If lowering)
|
|
//! - **Pattern 2: Break** (medium complexity)
|
|
//! - **Pattern 1: Simple While** (foundational, easiest)
|
|
//!
|
|
//! # Integration Points
|
|
//!
|
|
//! Called from:
|
|
//! - `loop_to_join::LoopToJoinLowerer::lower_loop()`
|
|
//! - `loop_form_intake.rs::handle_loop_form()`
|
|
|
|
use crate::mir::join_ir::JoinInst;
|
|
use crate::mir::loop_form::LoopForm;
|
|
|
|
/// Phase 188: Try to lower loop to JoinIR using pattern-based approach
|
|
///
|
|
/// This function routes loop lowering to specific pattern handlers based on
|
|
/// loop structure characteristics. It tries patterns in order of complexity:
|
|
///
|
|
/// 1. **Pattern 1: Simple While** (foundational, easiest)
|
|
/// 2. **Pattern 2: Break** (medium complexity)
|
|
/// 3. **Pattern 3: If-Else PHI** (leverages existing If lowering)
|
|
/// 4. **Pattern 4: Continue** (highest complexity)
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `loop_form` - The loop structure to lower
|
|
/// * `lowerer` - The LoopToJoinLowerer builder (provides ValueId allocation, etc.)
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// * `Some(JoinInst)` - Successfully lowered to JoinIR
|
|
/// * `None` - No pattern matched (fallback to existing lowering)
|
|
///
|
|
/// # Pattern Selection Strategy
|
|
///
|
|
/// Patterns are tried sequentially. First matching pattern wins.
|
|
/// If no pattern matches, returns `None` to trigger fallback.
|
|
///
|
|
/// ## Pattern 1: Simple While Loop
|
|
/// - **Condition**: Empty break/continue targets, single latch
|
|
/// - **Handler**: `loop_patterns::lower_simple_while_to_joinir()`
|
|
/// - **Priority**: First (most common, simplest)
|
|
///
|
|
/// ## Pattern 2: Loop with Conditional Break
|
|
/// - **Condition**: Non-empty break_targets, exactly 1 break
|
|
/// - **Handler**: `loop_patterns::lower_loop_with_break_to_joinir()`
|
|
/// - **Priority**: Second (common, medium complexity)
|
|
///
|
|
/// ## Pattern 3: Loop with If-Else PHI
|
|
/// - **Condition**: Empty break/continue, if-else in body
|
|
/// - **Handler**: `loop_patterns::lower_loop_with_conditional_phi_to_joinir()`
|
|
/// - **Priority**: Third (reuses If lowering infrastructure)
|
|
///
|
|
/// ## Pattern 4: Loop with Continue
|
|
/// - **Condition**: Non-empty continue_targets
|
|
/// - **Handler**: `loop_patterns::lower_loop_with_continue_to_joinir()`
|
|
/// - **Priority**: Fourth (most complex)
|
|
///
|
|
/// # Integration Point
|
|
///
|
|
/// This function should be called from loop lowering entry points:
|
|
/// - `loop_to_join::LoopToJoinLowerer::lower_loop()`
|
|
/// - `loop_form_intake.rs::handle_loop_form()`
|
|
///
|
|
/// # Example Usage
|
|
///
|
|
/// ```rust,ignore
|
|
/// use crate::mir::join_ir::lowering::try_lower_loop_pattern_to_joinir;
|
|
///
|
|
/// // In loop lowering entry point:
|
|
/// if let Some(joinir_inst) = try_lower_loop_pattern_to_joinir(&loop_form, &mut lowerer) {
|
|
/// // Pattern matched, use JoinIR
|
|
/// return Some(joinir_inst);
|
|
/// }
|
|
/// // No pattern matched, use existing lowering
|
|
/// existing_loop_lowering(&loop_form, &mut lowerer)
|
|
/// ```
|
|
///
|
|
/// # Reference
|
|
///
|
|
/// See design.md for complete pattern specifications and transformation rules:
|
|
/// `docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/design.md`
|
|
pub fn try_lower_loop_pattern_to_joinir(
|
|
loop_form: &LoopForm,
|
|
lowerer: &mut crate::mir::join_ir::lowering::LoopToJoinLowerer,
|
|
) -> Option<JoinInst> {
|
|
// Phase 194: Structure-based pattern classification
|
|
// Tries patterns based on CFG structure, not function names
|
|
|
|
use crate::mir::loop_pattern_detection::{classify, extract_features, LoopPatternKind};
|
|
|
|
// Step 1: Extract features from LoopForm (no LoopScope needed for now)
|
|
let features = extract_features(loop_form, None);
|
|
|
|
// Step 2: Classify pattern based on structure
|
|
let pattern = classify(&features);
|
|
|
|
// Step 3: Route to appropriate lowerer based on pattern
|
|
match pattern {
|
|
LoopPatternKind::Pattern4Continue => {
|
|
if let Some(inst) =
|
|
super::loop_patterns::lower_loop_with_continue_to_joinir(loop_form, lowerer)
|
|
{
|
|
eprintln!("[try_lower_loop_pattern] ✅ Pattern 4 (Continue) matched");
|
|
return Some(inst);
|
|
}
|
|
}
|
|
LoopPatternKind::Pattern3IfPhi => {
|
|
if let Some(inst) =
|
|
super::loop_patterns::lower_loop_with_conditional_phi_to_joinir(loop_form, lowerer)
|
|
{
|
|
eprintln!("[try_lower_loop_pattern] ✅ Pattern 3 (If-Else PHI) matched");
|
|
return Some(inst);
|
|
}
|
|
}
|
|
LoopPatternKind::Pattern2Break => {
|
|
if let Some(inst) =
|
|
super::loop_patterns::lower_loop_with_break_to_joinir(loop_form, lowerer)
|
|
{
|
|
eprintln!("[try_lower_loop_pattern] ✅ Pattern 2 (Break) matched");
|
|
return Some(inst);
|
|
}
|
|
}
|
|
LoopPatternKind::Pattern1SimpleWhile => {
|
|
if let Some(inst) =
|
|
super::loop_patterns::lower_simple_while_to_joinir(loop_form, lowerer)
|
|
{
|
|
eprintln!("[try_lower_loop_pattern] ✅ Pattern 1 (Simple While) matched");
|
|
return Some(inst);
|
|
}
|
|
}
|
|
LoopPatternKind::InfiniteEarlyExit => {
|
|
// Phase 131-11: Not implemented yet in LoopForm-based router
|
|
eprintln!("[try_lower_loop_pattern] ⚠️ Pattern 5 (InfiniteEarlyExit) not implemented in LoopForm router");
|
|
}
|
|
LoopPatternKind::Unknown => {
|
|
eprintln!("[try_lower_loop_pattern] ❌ Unknown pattern, fallback to existing lowering");
|
|
}
|
|
}
|
|
|
|
// No Pattern Matched (fallback to existing lowering)
|
|
// ===================================================
|
|
eprintln!("[try_lower_loop_pattern] ❌ Pattern lowering failed, fallback to existing lowering");
|
|
None
|
|
}
|