refactor(joinir): Phase 33-12 Large module modularization complete
Task 1: Split mod.rs into if/loop routers - Created if_lowering_router.rs (172 lines): If-expression routing - Created loop_pattern_router.rs (149 lines): Loop pattern routing - Refactored mod.rs (511 → 221 lines): Thin re-export module Task 2: Modularize loop_patterns per-pattern - Created loop_patterns/ directory with 4 pattern files: - simple_while.rs (225 lines): Pattern 1 implementation - with_break.rs (129 lines): Pattern 2 implementation - with_if_phi.rs (123 lines): Pattern 3 implementation - with_continue.rs (129 lines): Pattern 4 stub - Created mod.rs (178 lines): Dispatcher + shared utilities - Removed old loop_patterns.rs (735 lines → directory) Line count changes: - mod.rs: 511 → 221 lines (57% reduction) - loop_patterns: 735 → 784 lines (modularized) - Total: Net +80 lines for better organization Benefits: - Single responsibility per file - Clear pattern boundaries - Improved testability - Better maintainability - Backward compatibility maintained Testing: - cargo build --release: ✅ Success (0 errors) - Regression test: ✅ Pass (RC: 0)
This commit is contained in:
172
src/mir/join_ir/lowering/if_lowering_router.rs
Normal file
172
src/mir/join_ir/lowering/if_lowering_router.rs
Normal file
@ -0,0 +1,172 @@
|
||||
//! Phase 33-12: If-Expression JoinIR Lowering Router
|
||||
//!
|
||||
//! Routes if-expressions to appropriate JoinIR lowering strategies
|
||||
//! (if_select, if_merge, etc.)
|
||||
//!
|
||||
//! # Routing Strategy
|
||||
//!
|
||||
//! This router tries multiple lowering strategies in order:
|
||||
//! 1. **IfMerge**: For multiple-variable patterns (Phase 33-7)
|
||||
//! 2. **IfSelect**: For single-variable patterns (Phase 33-2/33-3)
|
||||
//!
|
||||
//! # Control Flow
|
||||
//!
|
||||
//! - Checks toggle flags (`joinir_if_select_enabled()`)
|
||||
//! - Validates function whitelist (test/Stage-1/explicit approvals)
|
||||
//! - Excludes loop-lowered functions (Phase 33-9.1 separation)
|
||||
//! - Falls back to traditional if_phi on pattern mismatch
|
||||
//!
|
||||
//! # Phase 61-1: If-in-Loop Support
|
||||
//!
|
||||
//! Context parameter enables if-in-loop lowering:
|
||||
//! - `None`: Pure if-expression
|
||||
//! - `Some(context)`: If-in-loop with carrier variables
|
||||
|
||||
use crate::mir::join_ir::JoinInst;
|
||||
use crate::mir::{BasicBlockId, MirFunction};
|
||||
|
||||
/// Phase 33-7: Try to lower if/else to JoinIR Select/IfMerge instruction
|
||||
///
|
||||
/// Scope:
|
||||
/// - Only applies to whitelisted functions:
|
||||
/// - IfSelectTest.* (Phase 33-2/33-3)
|
||||
/// - IfMergeTest.* (Phase 33-7)
|
||||
/// - JsonShapeToMap._read_value_from_pair/1 (Phase 33-4 Stage-1)
|
||||
/// - Stage1JsonScannerBox.value_start_after_key_pos/2 (Phase 33-4 Stage-B)
|
||||
/// - Requires JoinIR If-select toggle (HAKO_JOINIR_IF_SELECT / joinir_if_select_enabled)
|
||||
/// - Falls back to traditional if_phi on pattern mismatch
|
||||
///
|
||||
/// Pattern selection:
|
||||
/// - 1 variable → Select
|
||||
/// - 2+ variables → IfMerge
|
||||
///
|
||||
/// Phase 61-1: If-in-loop support
|
||||
/// - `context` parameter: If-in-loop context (carrier_names for loop variables)
|
||||
/// - None = Pure If, Some(_) = If-in-loop
|
||||
///
|
||||
/// Returns Some(JoinInst::Select) or Some(JoinInst::IfMerge) if pattern matched, None otherwise.
|
||||
pub fn try_lower_if_to_joinir(
|
||||
func: &MirFunction,
|
||||
block_id: BasicBlockId,
|
||||
debug: bool,
|
||||
context: Option<&crate::mir::join_ir::lowering::if_phi_context::IfPhiContext>, // Phase 61-1: If-in-loop context
|
||||
) -> Option<JoinInst> {
|
||||
// 1. dev/Core トグルチェック
|
||||
//
|
||||
// - Core: joinir_core_enabled() / joinir_if_select_enabled()
|
||||
// - Dev: joinir_dev_enabled()(詳細ログ等)
|
||||
//
|
||||
// 実際の挙動切り替えは joinir_if_select_enabled() に集約し、
|
||||
// Core/Dev ポリシーは config::env 側で判定する。
|
||||
if !crate::config::env::joinir_if_select_enabled() {
|
||||
return None;
|
||||
}
|
||||
let core_on = crate::config::env::joinir_core_enabled();
|
||||
// Phase 185: strict check moved to caller (if_form.rs)
|
||||
// let strict_on = crate::config::env::joinir_strict_enabled();
|
||||
|
||||
// Phase 33-9.1: Loop専任関数の除外(Loop/If責務分離)
|
||||
// Loop lowering対象関数はIf loweringの対象外にすることで、
|
||||
// 1関数につき1 loweringの原則を保証します
|
||||
if super::is_loop_lowered_function(&func.signature.name) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Phase 33-8: デバッグログレベル取得(0-3)
|
||||
let debug_level = crate::config::env::joinir_debug_level();
|
||||
let _debug = debug || debug_level >= 1;
|
||||
|
||||
// 2. Phase 33-8: 関数名ガード拡張(テスト + Stage-1 rollout + 明示承認)
|
||||
let is_allowed =
|
||||
// Test functions (always enabled)
|
||||
func.signature.name.starts_with("IfSelectTest.") ||
|
||||
func.signature.name.starts_with("IfSelectLocalTest.") || // Phase 33-10 test
|
||||
func.signature.name.starts_with("IfMergeTest.") ||
|
||||
func.signature.name.starts_with("IfToplevelTest.") || // Phase 61-4: loop-outside if test
|
||||
func.signature.name.starts_with("Stage1JsonScannerTestBox.") || // Phase 33-5 test
|
||||
|
||||
// Stage-1 rollout (env-controlled)
|
||||
(crate::config::env::joinir_stage1_enabled() &&
|
||||
func.signature.name.starts_with("Stage1")) ||
|
||||
|
||||
// Explicit approvals (Phase 33-4で検証済み, always on)
|
||||
matches!(func.signature.name.as_str(),
|
||||
"JsonShapeToMap._read_value_from_pair/1" |
|
||||
"Stage1JsonScannerBox.value_start_after_key_pos/2"
|
||||
);
|
||||
|
||||
// Phase 80: Core ON のときは許可リストを「JoinIRをまず試す」対象とみなす。
|
||||
// Core OFF のときは従来どおり whitelist + env に頼る。
|
||||
if !is_allowed || !core_on {
|
||||
// Core OFF かつ許可外なら従来のガードでスキップ
|
||||
if !is_allowed {
|
||||
if debug_level >= 2 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] skipping non-allowed function: {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// Phase 185: strict_allowed removed (strict check moved to caller: if_form.rs)
|
||||
|
||||
if debug_level >= 1 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] trying to lower {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン)
|
||||
// IfMerge が成功すればそれを返す、失敗したら Select を試行
|
||||
// Phase 61-1: context がある場合は with_context() を使用
|
||||
let if_merge_lowerer = if let Some(ctx) = context {
|
||||
crate::mir::join_ir::lowering::if_merge::IfMergeLowerer::with_context(debug_level, ctx.clone())
|
||||
} else {
|
||||
crate::mir::join_ir::lowering::if_merge::IfMergeLowerer::new(debug_level)
|
||||
};
|
||||
|
||||
if if_merge_lowerer.can_lower_to_if_merge(func, block_id) {
|
||||
if let Some(result) = if_merge_lowerer.lower_if_to_if_merge(func, block_id) {
|
||||
if debug_level >= 1 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] ✅ IfMerge lowering used for {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. IfMerge が失敗したら Select を試行(単一変数パターン)
|
||||
// Phase 61-1: context がある場合は with_context() を使用
|
||||
let if_select_lowerer = if let Some(ctx) = context {
|
||||
crate::mir::join_ir::lowering::if_select::IfSelectLowerer::with_context(debug_level, ctx.clone())
|
||||
} else {
|
||||
crate::mir::join_ir::lowering::if_select::IfSelectLowerer::new(debug_level)
|
||||
};
|
||||
|
||||
// Phase 185: Remove strict checks from lowerer (thin Result-returning box)
|
||||
// Strict mode panic should happen at caller level (if_form.rs), not here
|
||||
if !if_select_lowerer.can_lower_to_select(func, block_id) {
|
||||
if debug_level >= 1 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] pattern not matched for {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
let result = if_select_lowerer.lower_if_to_select(func, block_id);
|
||||
|
||||
if result.is_some() && debug_level >= 1 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] ✅ Select lowering used for {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
149
src/mir/join_ir/lowering/loop_pattern_router.rs
Normal file
149
src/mir/join_ir/lowering/loop_pattern_router.rs
Normal file
@ -0,0 +1,149 @@
|
||||
//! Phase 33-12: Loop Pattern JoinIR Lowering Router
|
||||
//!
|
||||
//! Routes loop patterns to appropriate JoinIR lowering strategies
|
||||
//! (Pattern 1-4: simple while, break, if+phi, continue)
|
||||
//!
|
||||
//! # 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)
|
||||
//! 3. Route to appropriate pattern lowerer
|
||||
//!
|
||||
//! # 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.rs::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.rs::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::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
|
||||
}
|
||||
@ -1,735 +0,0 @@
|
||||
//! Loop Pattern Lowering Functions
|
||||
//!
|
||||
//! Phase 188 Task 188-4: Skeleton lowering functions for 3 loop patterns.
|
||||
//!
|
||||
//! This module provides lowering functions that transform specific loop patterns
|
||||
//! to JoinIR representation. Each function is a "thin box":
|
||||
//! - Takes input (LoopForm, builder)
|
||||
//! - Returns Result (success/error)
|
||||
//! - No side effects outside the builder
|
||||
//!
|
||||
//! ## Patterns
|
||||
//!
|
||||
//! 1. **Pattern 1: Simple While Loop**
|
||||
//! - Foundational pattern (MUST implement first)
|
||||
//! - Single carrier variable, no breaks/continues
|
||||
//! - Transforms to: exit check + body + tail recursion
|
||||
//!
|
||||
//! 2. **Pattern 2: Loop with Conditional Break**
|
||||
//! - Builds on Pattern 1
|
||||
//! - Adds break handling with multiple exit paths
|
||||
//! - Transforms to: exit check + break check + body + tail recursion
|
||||
//!
|
||||
//! 3. **Pattern 3: Loop with If-Else PHI**
|
||||
//! - Builds on Pattern 1
|
||||
//! - Handles multiple carrier variables with if-else assignment
|
||||
//! - Reuses existing If lowering (Select/IfMerge)
|
||||
//! - Transforms to: exit check + if-else (Select) + body + tail recursion
|
||||
//!
|
||||
//! ## Reference
|
||||
//!
|
||||
//! Design document: `docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/design.md`
|
||||
//!
|
||||
//! Each pattern has complete pseudocode in the design doc that can be adapted
|
||||
//! to actual Rust implementation.
|
||||
|
||||
use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer;
|
||||
use crate::mir::join_ir::JoinInst;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
|
||||
// ============================================================================
|
||||
// Pattern 1: Simple While Loop
|
||||
// ============================================================================
|
||||
|
||||
/// Lowering for Pattern 1: Simple While Loop
|
||||
///
|
||||
/// # Transformation (Pseudocode from design.md)
|
||||
///
|
||||
/// ```text
|
||||
/// fn loop_step(i):
|
||||
/// exit_cond = !(i < 3)
|
||||
/// Jump(k_exit, [], cond=exit_cond)
|
||||
/// print(i)
|
||||
/// i_next = i + 1
|
||||
/// Call(loop_step, [i_next])
|
||||
/// ```
|
||||
///
|
||||
/// # Steps (from design.md § Pattern 1 § Step-by-Step Transformation)
|
||||
///
|
||||
/// 1. **Extract Loop Variables (Carriers)**
|
||||
/// - Analyze header PHI nodes
|
||||
/// - Identify initial values and next values
|
||||
///
|
||||
/// 2. **Create loop_step Function Signature**
|
||||
/// - Parameters: carrier variables + k_exit continuation
|
||||
///
|
||||
/// 3. **Create k_exit Continuation**
|
||||
/// - Handles loop exit (returns final value)
|
||||
///
|
||||
/// 4. **Generate Exit Condition Check**
|
||||
/// - Negate loop condition: `exit_cond = !(i < 3)`
|
||||
/// - Add Jump to k_exit if exit_cond is true
|
||||
///
|
||||
/// 5. **Translate Loop Body**
|
||||
/// - Copy body instructions to loop_step body
|
||||
/// - Preserve side effects (print, etc.)
|
||||
///
|
||||
/// 6. **Generate Tail Recursion**
|
||||
/// - Update carrier: `i_next = i + 1`
|
||||
/// - Tail call: `Call(loop_step, [i_next], k_next: None)`
|
||||
///
|
||||
/// 7. **Wire Exit Continuation**
|
||||
/// - Connect loop_step exit Jump to k_exit
|
||||
/// - Set k_exit exit_cont to parent continuation
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `loop_form` - The loop structure to lower
|
||||
/// * `lowerer` - The LoopToJoinLowerer builder (provides ValueId allocation, etc.)
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction
|
||||
/// * `None` - Lowering failed (pattern not matched or unsupported)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - Loop has breaks or continues
|
||||
/// - Loop has multiple latches
|
||||
/// - Loop condition is too complex
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See design.md § Pattern 1 for complete transformation details and pseudocode.
|
||||
///
|
||||
/// # Example Usage
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::mir::loop_pattern_detection::is_simple_while_pattern;
|
||||
///
|
||||
/// if is_simple_while_pattern(&loop_form) {
|
||||
/// lower_simple_while_to_joinir(&loop_form, &mut lowerer)?;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lower_simple_while_to_joinir(
|
||||
loop_form: &LoopForm,
|
||||
lowerer: &mut LoopToJoinLowerer,
|
||||
) -> Option<JoinInst> {
|
||||
// TODO: Implement Pattern 1 lowering
|
||||
//
|
||||
// Step 1: Extract Loop Variables (Carriers)
|
||||
// ==========================================
|
||||
// From header PHI: %2 = phi [%1, bb1], [%6, bb4]
|
||||
// Extract: (var_name: "i", init_value: ValueId(1), next_value: ValueId(6))
|
||||
//
|
||||
// ```rust
|
||||
// let carriers = extract_carriers_from_header_phi(loop_form)?;
|
||||
// ```
|
||||
//
|
||||
// Step 2: Create loop_step Function Signature
|
||||
// ============================================
|
||||
// Signature: fn loop_step(i: ValueId, k_exit: JoinContId) -> ...
|
||||
//
|
||||
// ```rust
|
||||
// let loop_step_id = lowerer.allocate_join_func_id();
|
||||
// let k_exit_id = lowerer.allocate_join_func_id();
|
||||
//
|
||||
// let mut loop_step_params = vec![];
|
||||
// for carrier in &carriers {
|
||||
// loop_step_params.push(carrier.param_valueid);
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Step 3: Create k_exit Continuation
|
||||
// ===================================
|
||||
// fn k_exit() -> ValueId // Returns final value (0 in this case)
|
||||
//
|
||||
// ```rust
|
||||
// let k_exit_func = JoinFunction {
|
||||
// id: k_exit_id,
|
||||
// name: "k_exit".to_string(),
|
||||
// params: vec![], // No exit values in Pattern 1
|
||||
// body: vec![
|
||||
// JoinInst::Compute(MirLikeInst::Const {
|
||||
// dst: lowerer.fresh_valueid(),
|
||||
// value: ConstValue::Integer(0),
|
||||
// }),
|
||||
// JoinInst::Ret { value: Some(return_val) },
|
||||
// ],
|
||||
// exit_cont: None,
|
||||
// };
|
||||
// lowerer.register_join_function(k_exit_func);
|
||||
// ```
|
||||
//
|
||||
// Step 4: Generate Exit Condition Check
|
||||
// ======================================
|
||||
// exit_cond = !(i < 3)
|
||||
// Jump(k_exit, [], cond=exit_cond)
|
||||
//
|
||||
// ```rust
|
||||
// let loop_cond = extract_loop_condition_from_header(loop_form)?;
|
||||
// let exit_cond = lowerer.fresh_valueid();
|
||||
//
|
||||
// body.push(JoinInst::Compute(MirLikeInst::UnaryOp {
|
||||
// dst: exit_cond,
|
||||
// op: UnaryOp::Not,
|
||||
// operand: loop_cond,
|
||||
// }));
|
||||
//
|
||||
// body.push(JoinInst::Jump {
|
||||
// cont: k_exit_id.as_cont(),
|
||||
// args: vec![],
|
||||
// cond: Some(exit_cond),
|
||||
// });
|
||||
// ```
|
||||
//
|
||||
// Step 5: Translate Loop Body
|
||||
// ===========================
|
||||
// Copy body instructions to loop_step body
|
||||
//
|
||||
// ```rust
|
||||
// let body_insts = extract_body_instructions(loop_form)?;
|
||||
// for inst in body_insts {
|
||||
// body.push(translate_mir_inst_to_joinir(inst, lowerer)?);
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Step 6: Generate Tail Recursion
|
||||
// ================================
|
||||
// i_next = i + 1
|
||||
// Call(loop_step, [i_next], k_next: None)
|
||||
//
|
||||
// ```rust
|
||||
// let const_1 = lowerer.fresh_valueid();
|
||||
// let i_next = lowerer.fresh_valueid();
|
||||
//
|
||||
// body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
// dst: const_1,
|
||||
// value: ConstValue::Integer(1),
|
||||
// }));
|
||||
//
|
||||
// body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
// dst: i_next,
|
||||
// op: BinOp::Add,
|
||||
// lhs: i,
|
||||
// rhs: const_1,
|
||||
// }));
|
||||
//
|
||||
// body.push(JoinInst::Call {
|
||||
// func: loop_step_id,
|
||||
// args: vec![i_next],
|
||||
// k_next: None, // CRITICAL: Must be None (tail call)
|
||||
// dst: Some(result_var),
|
||||
// });
|
||||
// ```
|
||||
//
|
||||
// Step 7: Wire Exit Continuation
|
||||
// ===============================
|
||||
// Connect loop_step to k_exit
|
||||
//
|
||||
// ```rust
|
||||
// let loop_step_func = JoinFunction {
|
||||
// id: loop_step_id,
|
||||
// name: "loop_step".to_string(),
|
||||
// params: loop_step_params,
|
||||
// body: body,
|
||||
// exit_cont: Some(k_exit_id.as_cont()),
|
||||
// };
|
||||
// lowerer.register_join_function(loop_step_func);
|
||||
// ```
|
||||
//
|
||||
// Return success
|
||||
// ```rust
|
||||
// Some(JoinInst::Call { ... })
|
||||
// ```
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pattern 2: Loop with Conditional Break
|
||||
// ============================================================================
|
||||
|
||||
/// Lowering for Pattern 2: Loop with Conditional Break
|
||||
///
|
||||
/// # Transformation (Pseudocode from design.md)
|
||||
///
|
||||
/// ```text
|
||||
/// fn loop_step(i):
|
||||
/// exit_cond = !(i < 3)
|
||||
/// Jump(k_exit, [i], cond=exit_cond) // Natural exit
|
||||
/// break_cond = (i >= 2)
|
||||
/// Jump(k_exit, [i], cond=break_cond) // Break exit
|
||||
/// i_next = i + 1
|
||||
/// Call(loop_step, [i_next])
|
||||
/// ```
|
||||
///
|
||||
/// # Steps (from design.md § Pattern 2 § Step-by-Step Transformation)
|
||||
///
|
||||
/// 1. **Extract Loop Variables** (same as Pattern 1)
|
||||
/// 2. **Create loop_step Function** (same as Pattern 1)
|
||||
/// 3. **Create k_exit with Exit PHI**
|
||||
/// - k_exit(i_exit) - receives exit value from both exit paths
|
||||
/// 4. **Generate Natural Exit Check** (same as Pattern 1)
|
||||
/// 5. **Generate Break Check**
|
||||
/// - Extract break condition: `break_cond = (i >= 2)`
|
||||
/// - Add conditional Jump to k_exit: `Jump(k_exit, [i], cond=break_cond)`
|
||||
/// 6. **Translate Loop Body** (same as Pattern 1)
|
||||
/// 7. **Generate Tail Recursion** (same as Pattern 1)
|
||||
///
|
||||
/// # Key Difference from Pattern 1
|
||||
///
|
||||
/// - **Multiple Exit Paths**: Natural exit + break exit
|
||||
/// - **Exit PHI**: k_exit receives exit value from both paths
|
||||
/// - **Sequential Jumps**: Natural exit check → break check → body
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `loop_form` - The loop structure to lower (must have break_targets)
|
||||
/// * `lowerer` - The LoopToJoinLowerer builder
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction
|
||||
/// * `None` - Lowering failed (pattern not matched or unsupported)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - Loop has no breaks (use Pattern 1 instead)
|
||||
/// - Loop has multiple break targets (not yet supported)
|
||||
/// - Break is not in an if statement
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See design.md § Pattern 2 for complete transformation details and pseudocode.
|
||||
///
|
||||
/// # Example Usage
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::mir::loop_pattern_detection::is_loop_with_break_pattern;
|
||||
///
|
||||
/// if is_loop_with_break_pattern(&loop_form) {
|
||||
/// lower_loop_with_break_to_joinir(&loop_form, &mut lowerer)?;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lower_loop_with_break_to_joinir(
|
||||
_loop_form: &LoopForm,
|
||||
_lowerer: &mut LoopToJoinLowerer,
|
||||
) -> Option<JoinInst> {
|
||||
// Phase 188-Impl-2: Delegate to minimal lowerer
|
||||
// TODO: Extract LoopScopeShape from loop_form for generic implementation
|
||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||
|
||||
use crate::mir::BasicBlockId;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
// For now, use a placeholder LoopScopeShape
|
||||
// TODO: Build actual LoopScopeShape from loop_form
|
||||
let placeholder_scope = LoopScopeShape {
|
||||
header: BasicBlockId(0),
|
||||
body: BasicBlockId(0),
|
||||
latch: BasicBlockId(0),
|
||||
exit: BasicBlockId(0),
|
||||
pinned: BTreeSet::new(),
|
||||
carriers: BTreeSet::new(),
|
||||
body_locals: BTreeSet::new(),
|
||||
exit_live: BTreeSet::new(),
|
||||
progress_carrier: None,
|
||||
variable_definitions: BTreeMap::new(),
|
||||
};
|
||||
|
||||
// Generate JoinIR module
|
||||
// Phase 169: lower_loop_with_break_minimal now requires condition AST and builder
|
||||
// This test stub is not used by the actual router, so commenting out for now
|
||||
// let _join_module = lower_loop_with_break_minimal(placeholder_scope, condition, builder)?;
|
||||
|
||||
// Phase 188-Impl-2: Pattern 2 is now integrated in control_flow.rs via cf_loop_pattern2_with_break()
|
||||
// This function (lower_loop_with_break_to_joinir) is currently not used by the router.
|
||||
// The actual lowering happens directly in control_flow.rs which calls loop_with_break_minimal.
|
||||
//
|
||||
// TODO: Either:
|
||||
// 1. Remove this function and rely only on control_flow.rs integration, OR
|
||||
// 2. Implement JoinModule → JoinInst conversion here (future phase)
|
||||
|
||||
eprintln!("[loop_patterns] Pattern 2: Lowering delegated to control_flow.rs");
|
||||
|
||||
// Temporary: Return None to trigger fallback
|
||||
// Pattern 2 currently works via hardcoded route in control_flow.rs
|
||||
None
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pattern 3: Loop with If-Else PHI
|
||||
// ============================================================================
|
||||
|
||||
/// Lowering for Pattern 3: Loop with If-Else PHI
|
||||
///
|
||||
/// # Transformation (Pseudocode from design.md)
|
||||
///
|
||||
/// ```text
|
||||
/// fn loop_step(i, sum):
|
||||
/// exit_cond = !(i <= 5)
|
||||
/// Jump(k_exit, [sum], cond=exit_cond)
|
||||
/// sum_new = Select(cond=(i%2==1), then=sum+i, else=sum+0)
|
||||
/// i_next = i + 1
|
||||
/// Call(loop_step, [i_next, sum_new])
|
||||
/// ```
|
||||
///
|
||||
/// # Steps (from design.md § Pattern 3 § Step-by-Step Transformation)
|
||||
///
|
||||
/// 1. **Extract Loop Variables** (multiple carriers: i + sum)
|
||||
/// 2. **Create loop_step Function** (params: i, sum, k_exit)
|
||||
/// 3. **Create k_exit with Exit PHI** (receives sum exit value)
|
||||
/// 4. **Generate Exit Condition Check** (same as Pattern 1)
|
||||
/// 5. **Translate If-Else to Select**
|
||||
/// - Use existing If lowering (Phase 33: Select/IfMerge)
|
||||
/// - Generate: `sum_new = Select(cond, then_val, else_val)`
|
||||
/// 6. **Translate Loop Body** (remaining instructions)
|
||||
/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_new)
|
||||
///
|
||||
/// # Key Difference from Pattern 1
|
||||
///
|
||||
/// - **Multiple Carrier Variables**: Loop updates i + sum
|
||||
/// - **In-Loop If Lowering**: Reuses existing Select/IfMerge lowering
|
||||
/// - **PHI in Loop Body**: If-else assigns to same variable (becomes Select)
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `loop_form` - The loop structure to lower (must have if-else in body)
|
||||
/// * `lowerer` - The LoopToJoinLowerer builder
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction
|
||||
/// * `None` - Lowering failed (pattern not matched or unsupported)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - Loop has breaks or continues
|
||||
/// - If-else does not assign to same variable
|
||||
/// - If context cannot be resolved
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See design.md § Pattern 3 for complete transformation details and pseudocode.
|
||||
///
|
||||
/// # Example Usage
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::mir::loop_pattern_detection::is_loop_with_conditional_phi_pattern;
|
||||
///
|
||||
/// if is_loop_with_conditional_phi_pattern(&loop_form) {
|
||||
/// lower_loop_with_conditional_phi_to_joinir(&loop_form, &mut lowerer)?;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lower_loop_with_conditional_phi_to_joinir(
|
||||
_loop_form: &LoopForm,
|
||||
_lowerer: &mut LoopToJoinLowerer,
|
||||
) -> Option<JoinInst> {
|
||||
// Phase 188-Impl-3: Delegate to minimal lowerer
|
||||
// TODO: Extract LoopScopeShape from loop_form for generic implementation
|
||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||
use crate::mir::join_ir::lowering::loop_with_if_phi_minimal::lower_loop_with_if_phi_pattern;
|
||||
use crate::mir::BasicBlockId;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
// For now, use a placeholder LoopScopeShape
|
||||
// TODO: Build actual LoopScopeShape from loop_form
|
||||
let placeholder_scope = LoopScopeShape {
|
||||
header: BasicBlockId(0),
|
||||
body: BasicBlockId(0),
|
||||
latch: BasicBlockId(0),
|
||||
exit: BasicBlockId(0),
|
||||
pinned: BTreeSet::new(),
|
||||
carriers: BTreeSet::new(),
|
||||
body_locals: BTreeSet::new(),
|
||||
exit_live: BTreeSet::new(),
|
||||
progress_carrier: None,
|
||||
variable_definitions: BTreeMap::new(),
|
||||
};
|
||||
|
||||
// Generate JoinIR module
|
||||
let _join_module = lower_loop_with_if_phi_pattern(placeholder_scope)?;
|
||||
|
||||
// Phase 188-Impl-3: Pattern 3 is now integrated via the router
|
||||
// This function delegates to loop_with_if_phi_minimal which generates JoinModule
|
||||
//
|
||||
// TODO: Either:
|
||||
// 1. Remove this function and rely only on router integration, OR
|
||||
// 2. Implement JoinModule → JoinInst conversion here (future phase)
|
||||
|
||||
eprintln!("[loop_patterns] Pattern 3: Lowering delegated to loop_with_if_phi_minimal");
|
||||
|
||||
// Temporary: Return None to trigger fallback
|
||||
// Pattern 3 currently works via router which calls minimal lowerer directly
|
||||
None
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pattern 4: Loop with Continue
|
||||
// ============================================================================
|
||||
|
||||
/// Lowering for Pattern 4: Loop with Continue
|
||||
///
|
||||
/// # Transformation (Pseudocode)
|
||||
///
|
||||
/// ```text
|
||||
/// fn loop_step(i, sum):
|
||||
/// exit_cond = !(i < 10)
|
||||
/// Jump(k_exit, [sum], cond=exit_cond) // Natural exit
|
||||
/// i_next = i + 1
|
||||
/// continue_cond = (i_next % 2 == 0)
|
||||
/// Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue jumps to loop start
|
||||
/// sum_next = sum + i_next
|
||||
/// Call(loop_step, [i_next, sum_next]) // Normal iteration
|
||||
/// ```
|
||||
///
|
||||
/// # Steps (Pattern 4 Transformation)
|
||||
///
|
||||
/// 1. **Extract Loop Variables** (multiple carriers: i + sum)
|
||||
/// 2. **Create loop_step Function** (params: i, sum, k_exit)
|
||||
/// 3. **Create k_exit with Exit PHI** (receives sum exit value)
|
||||
/// 4. **Generate Exit Condition Check** (same as Pattern 1)
|
||||
/// 5. **Generate Continue Check**
|
||||
/// - Extract continue condition (if exists)
|
||||
/// - Add conditional Jump back to loop_step: `Jump(loop_step, [i_next, sum], cond=continue_cond)`
|
||||
/// 6. **Translate Loop Body** (remaining instructions after continue)
|
||||
/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_next)
|
||||
///
|
||||
/// # Key Difference from Pattern 1/2/3
|
||||
///
|
||||
/// - **Continue Jump**: Continue jumps back to loop_step with current carrier values
|
||||
/// - **Dual Path**: Continue path + normal path (both recursive)
|
||||
/// - **PHI at Loop Start**: Loop header receives values from both continue and normal paths
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `loop_form` - The loop structure to lower (must have continue_targets)
|
||||
/// * `lowerer` - The LoopToJoinLowerer builder
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction
|
||||
/// * `None` - Lowering failed (pattern not matched or unsupported)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - Loop has no continues (use Pattern 1 instead)
|
||||
/// - Loop has break statements (not yet supported)
|
||||
/// - Continue is not in an if statement
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See design.md § Pattern 4 for complete transformation details and pseudocode.
|
||||
///
|
||||
/// # Example Usage
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::mir::loop_pattern_detection::is_loop_with_continue_pattern;
|
||||
///
|
||||
/// if is_loop_with_continue_pattern(&loop_form) {
|
||||
/// lower_loop_with_continue_to_joinir(&loop_form, &mut lowerer)?;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lower_loop_with_continue_to_joinir(
|
||||
_loop_form: &LoopForm,
|
||||
_lowerer: &mut LoopToJoinLowerer,
|
||||
) -> Option<JoinInst> {
|
||||
// Phase 188-Impl-4: Pattern 4 implementation placeholder
|
||||
// TODO: Implement Pattern 4 lowering
|
||||
//
|
||||
// Step 1: Extract Loop Variables (Carriers)
|
||||
// ==========================================
|
||||
// From header PHI: %i = phi [%0, preheader], [%i_next, body]
|
||||
// %sum = phi [%0, preheader], [%sum_next, body]
|
||||
// Extract: (var_name: "i", init_value: 0, next_value: i_next)
|
||||
// (var_name: "sum", init_value: 0, next_value: sum_next)
|
||||
//
|
||||
// Step 2: Create loop_step Function Signature
|
||||
// ============================================
|
||||
// Signature: fn loop_step(i: ValueId, sum: ValueId, k_exit: JoinContId) -> ...
|
||||
//
|
||||
// Step 3: Create k_exit Continuation
|
||||
// ===================================
|
||||
// fn k_exit(sum_exit) -> ValueId // Returns final sum value
|
||||
//
|
||||
// Step 4: Generate Exit Condition Check
|
||||
// ======================================
|
||||
// exit_cond = !(i < 10)
|
||||
// Jump(k_exit, [sum], cond=exit_cond)
|
||||
//
|
||||
// Step 5: Generate Continue Check
|
||||
// ================================
|
||||
// i_next = i + 1
|
||||
// continue_cond = (i_next % 2 == 0)
|
||||
// Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue to loop start
|
||||
//
|
||||
// Step 6: Translate Loop Body (after continue)
|
||||
// =============================================
|
||||
// sum_next = sum + i_next
|
||||
//
|
||||
// Step 7: Generate Tail Recursion
|
||||
// ================================
|
||||
// Call(loop_step, [i_next, sum_next], k_next: None)
|
||||
|
||||
eprintln!("[loop_patterns] Pattern 4: Continue lowering not yet implemented");
|
||||
None
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions (Future Use)
|
||||
// ============================================================================
|
||||
|
||||
// TODO: Implement helper functions for extraction and translation
|
||||
// These will be shared across all 3 patterns (moved from old comments below):
|
||||
//
|
||||
// For Pattern 3:
|
||||
// - extract_carriers_from_header_phi: Extract multiple loop variables (i, sum)
|
||||
// - extract_if_condition: Find if-else condition in loop body
|
||||
// - extract_then_value/extract_else_value: Get values from both branches
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions (Future Use)
|
||||
// ============================================================================
|
||||
|
||||
// TODO: Implement helper functions for extraction and translation
|
||||
// These will be shared across all 3 patterns:
|
||||
//
|
||||
// 1. extract_carriers_from_header_phi(loop_form) -> Vec<CarrierVar>
|
||||
// 2. extract_loop_condition_from_header(loop_form) -> ValueId
|
||||
// 3. extract_body_instructions(loop_form) -> Vec<MirInstruction>
|
||||
// 4. translate_mir_inst_to_joinir(inst, lowerer) -> JoinInst
|
||||
// 5. find_break_block(loop_form) -> BasicBlockId
|
||||
// 6. extract_break_condition(block) -> ValueId
|
||||
// 7. find_if_else_block(loop_form) -> BasicBlockId
|
||||
// 8. extract_if_condition(block) -> ValueId
|
||||
// 9. extract_then_value(block) -> ValueId
|
||||
// 10. extract_else_value(block) -> ValueId
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// ========================================================================
|
||||
// Pattern 1: Simple While Loop Tests
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern1_lowering_success() {
|
||||
// TODO: Add integration test for simple while pattern lowering
|
||||
// Step 1: Create mock LoopForm for simple while pattern
|
||||
// Step 2: Create mock LoopToJoinLowerer
|
||||
// Step 3: Call lower_simple_while_to_joinir()
|
||||
// Step 4: Assert returns Ok(())
|
||||
// Step 5: Verify generated JoinIR structure
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern1_rejects_break() {
|
||||
// TODO: Add test that rejects loop with break
|
||||
// Step 1: Create mock LoopForm with break
|
||||
// Step 2: Call lower_simple_while_to_joinir()
|
||||
// Step 3: Assert returns Err(UnsupportedPattern)
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Pattern 2: Loop with Break Tests
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern2_lowering_success() {
|
||||
// TODO: Add integration test for break pattern lowering
|
||||
// Step 1: Create mock LoopForm for break pattern
|
||||
// Step 2: Create mock LoopToJoinLowerer
|
||||
// Step 3: Call lower_loop_with_break_to_joinir()
|
||||
// Step 4: Assert returns Ok(())
|
||||
// Step 5: Verify generated JoinIR structure (two Jumps to k_exit)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern2_exit_phi_correct() {
|
||||
// TODO: Add test that verifies k_exit receives correct exit values
|
||||
// Step 1: Create mock LoopForm for break pattern
|
||||
// Step 2: Call lower_loop_with_break_to_joinir()
|
||||
// Step 3: Verify k_exit params = [i_exit]
|
||||
// Step 4: Verify both Jumps pass current i as argument
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Pattern 3: Loop with If-Else PHI Tests
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern3_lowering_success() {
|
||||
// TODO: Add integration test for if-else phi pattern lowering
|
||||
// Step 1: Create mock LoopForm for if-else phi pattern
|
||||
// Step 2: Create mock LoopToJoinLowerer
|
||||
// Step 3: Call lower_loop_with_conditional_phi_to_joinir()
|
||||
// Step 4: Assert returns Ok(())
|
||||
// Step 5: Verify generated JoinIR structure (Select instruction)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern3_multiple_carriers() {
|
||||
// TODO: Add test that verifies multiple carrier variables
|
||||
// Step 1: Create mock LoopForm with i + sum carriers
|
||||
// Step 2: Call lower_loop_with_conditional_phi_to_joinir()
|
||||
// Step 3: Verify loop_step params = [i, sum]
|
||||
// Step 4: Verify tail Call args = [i_next, sum_new]
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern3_if_lowering_integration() {
|
||||
// TODO: Add test that verifies If lowering integration
|
||||
// Step 1: Create mock LoopForm with if-else
|
||||
// Step 2: Call lower_loop_with_conditional_phi_to_joinir()
|
||||
// Step 3: Verify Select instruction is generated
|
||||
// Step 4: Verify Select has correct cond/then_val/else_val
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Pattern 4: Loop with Continue Tests
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern4_lowering_success() {
|
||||
// TODO: Add integration test for continue pattern lowering
|
||||
// Step 1: Create mock LoopForm for continue pattern
|
||||
// Step 2: Create mock LoopToJoinLowerer
|
||||
// Step 3: Call lower_loop_with_continue_to_joinir()
|
||||
// Step 4: Assert returns Ok(())
|
||||
// Step 5: Verify generated JoinIR structure (Jump to loop_step on continue)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern4_continue_jump_correct() {
|
||||
// TODO: Add test that verifies continue jumps to loop_step
|
||||
// Step 1: Create mock LoopForm for continue pattern
|
||||
// Step 2: Call lower_loop_with_continue_to_joinir()
|
||||
// Step 3: Verify conditional Jump targets loop_step
|
||||
// Step 4: Verify Jump passes current carrier values as arguments
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern4_multiple_carriers() {
|
||||
// TODO: Add test that verifies multiple carrier variables
|
||||
// Step 1: Create mock LoopForm with i + sum carriers
|
||||
// Step 2: Call lower_loop_with_continue_to_joinir()
|
||||
// Step 3: Verify loop_step params = [i, sum]
|
||||
// Step 4: Verify both tail Call and continue Jump use [i_next, sum_next]
|
||||
}
|
||||
}
|
||||
178
src/mir/join_ir/lowering/loop_patterns/mod.rs
Normal file
178
src/mir/join_ir/lowering/loop_patterns/mod.rs
Normal file
@ -0,0 +1,178 @@
|
||||
//! Phase 33-12: Loop Pattern Lowering Module
|
||||
//!
|
||||
//! Implements JoinIR lowering for different loop patterns:
|
||||
//! - Pattern 1: Simple while loops (no break/continue)
|
||||
//! - Pattern 2: Loops with break statements
|
||||
//! - Pattern 3: Loops with if expressions + PHI merging
|
||||
//! - Pattern 4: Loops with continue statements (stub)
|
||||
//!
|
||||
//! # Module Structure
|
||||
//!
|
||||
//! Each pattern is implemented in its own file:
|
||||
//! - `simple_while.rs`: Pattern 1 implementation
|
||||
//! - `with_break.rs`: Pattern 2 implementation
|
||||
//! - `with_if_phi.rs`: Pattern 3 implementation
|
||||
//! - `with_continue.rs`: Pattern 4 stub
|
||||
//!
|
||||
//! # Design Philosophy
|
||||
//!
|
||||
//! Pattern lowering functions are "thin boxes":
|
||||
//! - Takes input (LoopForm, builder)
|
||||
//! - Returns Result (success/error)
|
||||
//! - No side effects outside the builder
|
||||
//!
|
||||
//! # Reference
|
||||
//!
|
||||
//! Design document: `docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/design.md`
|
||||
|
||||
pub mod simple_while;
|
||||
pub mod with_break;
|
||||
pub mod with_if_phi;
|
||||
pub mod with_continue;
|
||||
|
||||
pub use simple_while::lower_simple_while_to_joinir;
|
||||
pub use with_break::lower_loop_with_break_to_joinir;
|
||||
pub use with_if_phi::lower_loop_with_conditional_phi_to_joinir;
|
||||
pub use with_continue::lower_loop_with_continue_to_joinir;
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions (Shared Utilities)
|
||||
// ============================================================================
|
||||
|
||||
// TODO: Implement helper functions for extraction and translation
|
||||
// These will be shared across all 4 patterns:
|
||||
//
|
||||
// 1. extract_carriers_from_header_phi(loop_form) -> Vec<CarrierVar>
|
||||
// 2. extract_loop_condition_from_header(loop_form) -> ValueId
|
||||
// 3. extract_body_instructions(loop_form) -> Vec<MirInstruction>
|
||||
// 4. translate_mir_inst_to_joinir(inst, lowerer) -> JoinInst
|
||||
// 5. find_break_block(loop_form) -> BasicBlockId
|
||||
// 6. extract_break_condition(block) -> ValueId
|
||||
// 7. find_if_else_block(loop_form) -> BasicBlockId
|
||||
// 8. extract_if_condition(block) -> ValueId
|
||||
// 9. extract_then_value(block) -> ValueId
|
||||
// 10. extract_else_value(block) -> ValueId
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// ========================================================================
|
||||
// Pattern 1: Simple While Loop Tests
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern1_lowering_success() {
|
||||
// TODO: Add integration test for simple while pattern lowering
|
||||
// Step 1: Create mock LoopForm for simple while pattern
|
||||
// Step 2: Create mock LoopToJoinLowerer
|
||||
// Step 3: Call lower_simple_while_to_joinir()
|
||||
// Step 4: Assert returns Some(JoinInst)
|
||||
// Step 5: Verify generated JoinIR structure
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern1_rejects_break() {
|
||||
// TODO: Add test that rejects loop with break
|
||||
// Step 1: Create mock LoopForm with break
|
||||
// Step 2: Call lower_simple_while_to_joinir()
|
||||
// Step 3: Assert returns None (unsupported pattern)
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Pattern 2: Loop with Break Tests
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern2_lowering_success() {
|
||||
// TODO: Add integration test for break pattern lowering
|
||||
// Step 1: Create mock LoopForm for break pattern
|
||||
// Step 2: Create mock LoopToJoinLowerer
|
||||
// Step 3: Call lower_loop_with_break_to_joinir()
|
||||
// Step 4: Assert returns Some(JoinInst)
|
||||
// Step 5: Verify generated JoinIR structure (two Jumps to k_exit)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern2_exit_phi_correct() {
|
||||
// TODO: Add test that verifies k_exit receives correct exit values
|
||||
// Step 1: Create mock LoopForm for break pattern
|
||||
// Step 2: Call lower_loop_with_break_to_joinir()
|
||||
// Step 3: Verify k_exit params = [i_exit]
|
||||
// Step 4: Verify both Jumps pass current i as argument
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Pattern 3: Loop with If-Else PHI Tests
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern3_lowering_success() {
|
||||
// TODO: Add integration test for if-else phi pattern lowering
|
||||
// Step 1: Create mock LoopForm for if-else phi pattern
|
||||
// Step 2: Create mock LoopToJoinLowerer
|
||||
// Step 3: Call lower_loop_with_conditional_phi_to_joinir()
|
||||
// Step 4: Assert returns Some(JoinInst)
|
||||
// Step 5: Verify generated JoinIR structure (Select instruction)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern3_multiple_carriers() {
|
||||
// TODO: Add test that verifies multiple carrier variables
|
||||
// Step 1: Create mock LoopForm with i + sum carriers
|
||||
// Step 2: Call lower_loop_with_conditional_phi_to_joinir()
|
||||
// Step 3: Verify loop_step params = [i, sum]
|
||||
// Step 4: Verify tail Call args = [i_next, sum_new]
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern3_if_lowering_integration() {
|
||||
// TODO: Add test that verifies If lowering integration
|
||||
// Step 1: Create mock LoopForm with if-else
|
||||
// Step 2: Call lower_loop_with_conditional_phi_to_joinir()
|
||||
// Step 3: Verify Select instruction is generated
|
||||
// Step 4: Verify Select has correct cond/then_val/else_val
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Pattern 4: Loop with Continue Tests
|
||||
// ========================================================================
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern4_lowering_success() {
|
||||
// TODO: Add integration test for continue pattern lowering
|
||||
// Step 1: Create mock LoopForm for continue pattern
|
||||
// Step 2: Create mock LoopToJoinLowerer
|
||||
// Step 3: Call lower_loop_with_continue_to_joinir()
|
||||
// Step 4: Assert returns Some(JoinInst)
|
||||
// Step 5: Verify generated JoinIR structure (Jump to loop_step on continue)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern4_continue_jump_correct() {
|
||||
// TODO: Add test that verifies continue jumps to loop_step
|
||||
// Step 1: Create mock LoopForm for continue pattern
|
||||
// Step 2: Call lower_loop_with_continue_to_joinir()
|
||||
// Step 3: Verify conditional Jump targets loop_step
|
||||
// Step 4: Verify Jump passes current carrier values as arguments
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Implement test after lowering logic is complete
|
||||
fn test_pattern4_multiple_carriers() {
|
||||
// TODO: Add test that verifies multiple carrier variables
|
||||
// Step 1: Create mock LoopForm with i + sum carriers
|
||||
// Step 2: Call lower_loop_with_continue_to_joinir()
|
||||
// Step 3: Verify loop_step params = [i, sum]
|
||||
// Step 4: Verify both tail Call and continue Jump use [i_next, sum_next]
|
||||
}
|
||||
}
|
||||
225
src/mir/join_ir/lowering/loop_patterns/simple_while.rs
Normal file
225
src/mir/join_ir/lowering/loop_patterns/simple_while.rs
Normal file
@ -0,0 +1,225 @@
|
||||
//! Pattern 1: Simple While Loop Lowering
|
||||
//!
|
||||
//! Target: Simple while loops with no break/continue
|
||||
//! Example: `while(i < 10) { i = i + 1 }`
|
||||
//!
|
||||
//! # Transformation
|
||||
//!
|
||||
//! ```text
|
||||
//! fn loop_step(i):
|
||||
//! exit_cond = !(i < 3)
|
||||
//! Jump(k_exit, [], cond=exit_cond)
|
||||
//! print(i)
|
||||
//! i_next = i + 1
|
||||
//! Call(loop_step, [i_next])
|
||||
//! ```
|
||||
|
||||
use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer;
|
||||
use crate::mir::join_ir::JoinInst;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
|
||||
/// Lowering for Pattern 1: Simple While Loop
|
||||
///
|
||||
/// # Transformation (Pseudocode from design.md)
|
||||
///
|
||||
/// ```text
|
||||
/// fn loop_step(i):
|
||||
/// exit_cond = !(i < 3)
|
||||
/// Jump(k_exit, [], cond=exit_cond)
|
||||
/// print(i)
|
||||
/// i_next = i + 1
|
||||
/// Call(loop_step, [i_next])
|
||||
/// ```
|
||||
///
|
||||
/// # Steps (from design.md § Pattern 1 § Step-by-Step Transformation)
|
||||
///
|
||||
/// 1. **Extract Loop Variables (Carriers)**
|
||||
/// - Analyze header PHI nodes
|
||||
/// - Identify initial values and next values
|
||||
///
|
||||
/// 2. **Create loop_step Function Signature**
|
||||
/// - Parameters: carrier variables + k_exit continuation
|
||||
///
|
||||
/// 3. **Create k_exit Continuation**
|
||||
/// - Handles loop exit (returns final value)
|
||||
///
|
||||
/// 4. **Generate Exit Condition Check**
|
||||
/// - Negate loop condition: `exit_cond = !(i < 3)`
|
||||
/// - Add Jump to k_exit if exit_cond is true
|
||||
///
|
||||
/// 5. **Translate Loop Body**
|
||||
/// - Copy body instructions to loop_step body
|
||||
/// - Preserve side effects (print, etc.)
|
||||
///
|
||||
/// 6. **Generate Tail Recursion**
|
||||
/// - Update carrier: `i_next = i + 1`
|
||||
/// - Tail call: `Call(loop_step, [i_next], k_next: None)`
|
||||
///
|
||||
/// 7. **Wire Exit Continuation**
|
||||
/// - Connect loop_step exit Jump to k_exit
|
||||
/// - Set k_exit exit_cont to parent continuation
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `loop_form` - The loop structure to lower
|
||||
/// * `lowerer` - The LoopToJoinLowerer builder (provides ValueId allocation, etc.)
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction
|
||||
/// * `None` - Lowering failed (pattern not matched or unsupported)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - Loop has breaks or continues
|
||||
/// - Loop has multiple latches
|
||||
/// - Loop condition is too complex
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See design.md § Pattern 1 for complete transformation details and pseudocode.
|
||||
///
|
||||
/// # Example Usage
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::mir::loop_pattern_detection::is_simple_while_pattern;
|
||||
///
|
||||
/// if is_simple_while_pattern(&loop_form) {
|
||||
/// lower_simple_while_to_joinir(&loop_form, &mut lowerer)?;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lower_simple_while_to_joinir(
|
||||
loop_form: &LoopForm,
|
||||
lowerer: &mut LoopToJoinLowerer,
|
||||
) -> Option<JoinInst> {
|
||||
// TODO: Implement Pattern 1 lowering
|
||||
//
|
||||
// Step 1: Extract Loop Variables (Carriers)
|
||||
// ==========================================
|
||||
// From header PHI: %2 = phi [%1, bb1], [%6, bb4]
|
||||
// Extract: (var_name: "i", init_value: ValueId(1), next_value: ValueId(6))
|
||||
//
|
||||
// ```rust
|
||||
// let carriers = extract_carriers_from_header_phi(loop_form)?;
|
||||
// ```
|
||||
//
|
||||
// Step 2: Create loop_step Function Signature
|
||||
// ============================================
|
||||
// Signature: fn loop_step(i: ValueId, k_exit: JoinContId) -> ...
|
||||
//
|
||||
// ```rust
|
||||
// let loop_step_id = lowerer.allocate_join_func_id();
|
||||
// let k_exit_id = lowerer.allocate_join_func_id();
|
||||
//
|
||||
// let mut loop_step_params = vec![];
|
||||
// for carrier in &carriers {
|
||||
// loop_step_params.push(carrier.param_valueid);
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Step 3: Create k_exit Continuation
|
||||
// ===================================
|
||||
// fn k_exit() -> ValueId // Returns final value (0 in this case)
|
||||
//
|
||||
// ```rust
|
||||
// let k_exit_func = JoinFunction {
|
||||
// id: k_exit_id,
|
||||
// name: "k_exit".to_string(),
|
||||
// params: vec![], // No exit values in Pattern 1
|
||||
// body: vec![
|
||||
// JoinInst::Compute(MirLikeInst::Const {
|
||||
// dst: lowerer.fresh_valueid(),
|
||||
// value: ConstValue::Integer(0),
|
||||
// }),
|
||||
// JoinInst::Ret { value: Some(return_val) },
|
||||
// ],
|
||||
// exit_cont: None,
|
||||
// };
|
||||
// lowerer.register_join_function(k_exit_func);
|
||||
// ```
|
||||
//
|
||||
// Step 4: Generate Exit Condition Check
|
||||
// ======================================
|
||||
// exit_cond = !(i < 3)
|
||||
// Jump(k_exit, [], cond=exit_cond)
|
||||
//
|
||||
// ```rust
|
||||
// let loop_cond = extract_loop_condition_from_header(loop_form)?;
|
||||
// let exit_cond = lowerer.fresh_valueid();
|
||||
//
|
||||
// body.push(JoinInst::Compute(MirLikeInst::UnaryOp {
|
||||
// dst: exit_cond,
|
||||
// op: UnaryOp::Not,
|
||||
// operand: loop_cond,
|
||||
// }));
|
||||
//
|
||||
// body.push(JoinInst::Jump {
|
||||
// cont: k_exit_id.as_cont(),
|
||||
// args: vec![],
|
||||
// cond: Some(exit_cond),
|
||||
// });
|
||||
// ```
|
||||
//
|
||||
// Step 5: Translate Loop Body
|
||||
// ===========================
|
||||
// Copy body instructions to loop_step body
|
||||
//
|
||||
// ```rust
|
||||
// let body_insts = extract_body_instructions(loop_form)?;
|
||||
// for inst in body_insts {
|
||||
// body.push(translate_mir_inst_to_joinir(inst, lowerer)?);
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Step 6: Generate Tail Recursion
|
||||
// ================================
|
||||
// i_next = i + 1
|
||||
// Call(loop_step, [i_next], k_next: None)
|
||||
//
|
||||
// ```rust
|
||||
// let const_1 = lowerer.fresh_valueid();
|
||||
// let i_next = lowerer.fresh_valueid();
|
||||
//
|
||||
// body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
// dst: const_1,
|
||||
// value: ConstValue::Integer(1),
|
||||
// }));
|
||||
//
|
||||
// body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
// dst: i_next,
|
||||
// op: BinOp::Add,
|
||||
// lhs: i,
|
||||
// rhs: const_1,
|
||||
// }));
|
||||
//
|
||||
// body.push(JoinInst::Call {
|
||||
// func: loop_step_id,
|
||||
// args: vec![i_next],
|
||||
// k_next: None, // CRITICAL: Must be None (tail call)
|
||||
// dst: Some(result_var),
|
||||
// });
|
||||
// ```
|
||||
//
|
||||
// Step 7: Wire Exit Continuation
|
||||
// ===============================
|
||||
// Connect loop_step to k_exit
|
||||
//
|
||||
// ```rust
|
||||
// let loop_step_func = JoinFunction {
|
||||
// id: loop_step_id,
|
||||
// name: "loop_step".to_string(),
|
||||
// params: loop_step_params,
|
||||
// body: body,
|
||||
// exit_cont: Some(k_exit_id.as_cont()),
|
||||
// };
|
||||
// lowerer.register_join_function(loop_step_func);
|
||||
// ```
|
||||
//
|
||||
// Return success
|
||||
// ```rust
|
||||
// Some(JoinInst::Call { ... })
|
||||
// ```
|
||||
|
||||
None
|
||||
}
|
||||
129
src/mir/join_ir/lowering/loop_patterns/with_break.rs
Normal file
129
src/mir/join_ir/lowering/loop_patterns/with_break.rs
Normal file
@ -0,0 +1,129 @@
|
||||
//! Pattern 2: Loop with Break Lowering
|
||||
//!
|
||||
//! Target: Loops with conditional break statements
|
||||
//! Example: `while(i < 10) { if i >= 5 { break } i = i + 1 }`
|
||||
//!
|
||||
//! # Transformation
|
||||
//!
|
||||
//! ```text
|
||||
//! fn loop_step(i):
|
||||
//! exit_cond = !(i < 3)
|
||||
//! Jump(k_exit, [i], cond=exit_cond) // Natural exit
|
||||
//! break_cond = (i >= 2)
|
||||
//! Jump(k_exit, [i], cond=break_cond) // Break exit
|
||||
//! i_next = i + 1
|
||||
//! Call(loop_step, [i_next])
|
||||
//! ```
|
||||
|
||||
use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer;
|
||||
use crate::mir::join_ir::JoinInst;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
|
||||
/// Lowering for Pattern 2: Loop with Conditional Break
|
||||
///
|
||||
/// # Transformation (Pseudocode from design.md)
|
||||
///
|
||||
/// ```text
|
||||
/// fn loop_step(i):
|
||||
/// exit_cond = !(i < 3)
|
||||
/// Jump(k_exit, [i], cond=exit_cond) // Natural exit
|
||||
/// break_cond = (i >= 2)
|
||||
/// Jump(k_exit, [i], cond=break_cond) // Break exit
|
||||
/// i_next = i + 1
|
||||
/// Call(loop_step, [i_next])
|
||||
/// ```
|
||||
///
|
||||
/// # Steps (from design.md § Pattern 2 § Step-by-Step Transformation)
|
||||
///
|
||||
/// 1. **Extract Loop Variables** (same as Pattern 1)
|
||||
/// 2. **Create loop_step Function** (same as Pattern 1)
|
||||
/// 3. **Create k_exit with Exit PHI**
|
||||
/// - k_exit(i_exit) - receives exit value from both exit paths
|
||||
/// 4. **Generate Natural Exit Check** (same as Pattern 1)
|
||||
/// 5. **Generate Break Check**
|
||||
/// - Extract break condition: `break_cond = (i >= 2)`
|
||||
/// - Add conditional Jump to k_exit: `Jump(k_exit, [i], cond=break_cond)`
|
||||
/// 6. **Translate Loop Body** (same as Pattern 1)
|
||||
/// 7. **Generate Tail Recursion** (same as Pattern 1)
|
||||
///
|
||||
/// # Key Difference from Pattern 1
|
||||
///
|
||||
/// - **Multiple Exit Paths**: Natural exit + break exit
|
||||
/// - **Exit PHI**: k_exit receives exit value from both paths
|
||||
/// - **Sequential Jumps**: Natural exit check → break check → body
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `loop_form` - The loop structure to lower (must have break_targets)
|
||||
/// * `lowerer` - The LoopToJoinLowerer builder
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction
|
||||
/// * `None` - Lowering failed (pattern not matched or unsupported)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - Loop has no breaks (use Pattern 1 instead)
|
||||
/// - Loop has multiple break targets (not yet supported)
|
||||
/// - Break is not in an if statement
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See design.md § Pattern 2 for complete transformation details and pseudocode.
|
||||
///
|
||||
/// # Example Usage
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::mir::loop_pattern_detection::is_loop_with_break_pattern;
|
||||
///
|
||||
/// if is_loop_with_break_pattern(&loop_form) {
|
||||
/// lower_loop_with_break_to_joinir(&loop_form, &mut lowerer)?;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lower_loop_with_break_to_joinir(
|
||||
_loop_form: &LoopForm,
|
||||
_lowerer: &mut LoopToJoinLowerer,
|
||||
) -> Option<JoinInst> {
|
||||
// Phase 188-Impl-2: Delegate to minimal lowerer
|
||||
// TODO: Extract LoopScopeShape from loop_form for generic implementation
|
||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||
|
||||
use crate::mir::BasicBlockId;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
// For now, use a placeholder LoopScopeShape
|
||||
// TODO: Build actual LoopScopeShape from loop_form
|
||||
let _placeholder_scope = LoopScopeShape {
|
||||
header: BasicBlockId(0),
|
||||
body: BasicBlockId(0),
|
||||
latch: BasicBlockId(0),
|
||||
exit: BasicBlockId(0),
|
||||
pinned: BTreeSet::new(),
|
||||
carriers: BTreeSet::new(),
|
||||
body_locals: BTreeSet::new(),
|
||||
exit_live: BTreeSet::new(),
|
||||
progress_carrier: None,
|
||||
variable_definitions: BTreeMap::new(),
|
||||
};
|
||||
|
||||
// Generate JoinIR module
|
||||
// Phase 169: lower_loop_with_break_minimal now requires condition AST and builder
|
||||
// This test stub is not used by the actual router, so commenting out for now
|
||||
// let _join_module = lower_loop_with_break_minimal(placeholder_scope, condition, builder)?;
|
||||
|
||||
// Phase 188-Impl-2: Pattern 2 is now integrated in control_flow.rs via cf_loop_pattern2_with_break()
|
||||
// This function (lower_loop_with_break_to_joinir) is currently not used by the router.
|
||||
// The actual lowering happens directly in control_flow.rs which calls loop_with_break_minimal.
|
||||
//
|
||||
// TODO: Either:
|
||||
// 1. Remove this function and rely only on control_flow.rs integration, OR
|
||||
// 2. Implement JoinModule → JoinInst conversion here (future phase)
|
||||
|
||||
eprintln!("[loop_patterns] Pattern 2: Lowering delegated to control_flow.rs");
|
||||
|
||||
// Temporary: Return None to trigger fallback
|
||||
// Pattern 2 currently works via hardcoded route in control_flow.rs
|
||||
None
|
||||
}
|
||||
129
src/mir/join_ir/lowering/loop_patterns/with_continue.rs
Normal file
129
src/mir/join_ir/lowering/loop_patterns/with_continue.rs
Normal file
@ -0,0 +1,129 @@
|
||||
//! Pattern 4: Loop with Continue - STUB
|
||||
//!
|
||||
//! Target: Loops with continue statements
|
||||
//! Status: Deferred to Phase 195+
|
||||
//!
|
||||
//! # Transformation
|
||||
//!
|
||||
//! ```text
|
||||
//! fn loop_step(i, sum):
|
||||
//! exit_cond = !(i < 10)
|
||||
//! Jump(k_exit, [sum], cond=exit_cond) // Natural exit
|
||||
//! i_next = i + 1
|
||||
//! continue_cond = (i_next % 2 == 0)
|
||||
//! Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue jumps to loop start
|
||||
//! sum_next = sum + i_next
|
||||
//! Call(loop_step, [i_next, sum_next]) // Normal iteration
|
||||
//! ```
|
||||
|
||||
use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer;
|
||||
use crate::mir::join_ir::JoinInst;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
|
||||
/// Lowering for Pattern 4: Loop with Continue
|
||||
///
|
||||
/// # Transformation (Pseudocode)
|
||||
///
|
||||
/// ```text
|
||||
/// fn loop_step(i, sum):
|
||||
/// exit_cond = !(i < 10)
|
||||
/// Jump(k_exit, [sum], cond=exit_cond) // Natural exit
|
||||
/// i_next = i + 1
|
||||
/// continue_cond = (i_next % 2 == 0)
|
||||
/// Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue jumps to loop start
|
||||
/// sum_next = sum + i_next
|
||||
/// Call(loop_step, [i_next, sum_next]) // Normal iteration
|
||||
/// ```
|
||||
///
|
||||
/// # Steps (Pattern 4 Transformation)
|
||||
///
|
||||
/// 1. **Extract Loop Variables** (multiple carriers: i + sum)
|
||||
/// 2. **Create loop_step Function** (params: i, sum, k_exit)
|
||||
/// 3. **Create k_exit with Exit PHI** (receives sum exit value)
|
||||
/// 4. **Generate Exit Condition Check** (same as Pattern 1)
|
||||
/// 5. **Generate Continue Check**
|
||||
/// - Extract continue condition (if exists)
|
||||
/// - Add conditional Jump back to loop_step: `Jump(loop_step, [i_next, sum], cond=continue_cond)`
|
||||
/// 6. **Translate Loop Body** (remaining instructions after continue)
|
||||
/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_next)
|
||||
///
|
||||
/// # Key Difference from Pattern 1/2/3
|
||||
///
|
||||
/// - **Continue Jump**: Continue jumps back to loop_step with current carrier values
|
||||
/// - **Dual Path**: Continue path + normal path (both recursive)
|
||||
/// - **PHI at Loop Start**: Loop header receives values from both continue and normal paths
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `loop_form` - The loop structure to lower (must have continue_targets)
|
||||
/// * `lowerer` - The LoopToJoinLowerer builder
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction
|
||||
/// * `None` - Lowering failed (pattern not matched or unsupported)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - Loop has no continues (use Pattern 1 instead)
|
||||
/// - Loop has break statements (not yet supported)
|
||||
/// - Continue is not in an if statement
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See design.md § Pattern 4 for complete transformation details and pseudocode.
|
||||
///
|
||||
/// # Example Usage
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::mir::loop_pattern_detection::is_loop_with_continue_pattern;
|
||||
///
|
||||
/// if is_loop_with_continue_pattern(&loop_form) {
|
||||
/// lower_loop_with_continue_to_joinir(&loop_form, &mut lowerer)?;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lower_loop_with_continue_to_joinir(
|
||||
_loop_form: &LoopForm,
|
||||
_lowerer: &mut LoopToJoinLowerer,
|
||||
) -> Option<JoinInst> {
|
||||
// Phase 188-Impl-4: Pattern 4 implementation placeholder
|
||||
// TODO: Implement Pattern 4 lowering
|
||||
//
|
||||
// Step 1: Extract Loop Variables (Carriers)
|
||||
// ==========================================
|
||||
// From header PHI: %i = phi [%0, preheader], [%i_next, body]
|
||||
// %sum = phi [%0, preheader], [%sum_next, body]
|
||||
// Extract: (var_name: "i", init_value: 0, next_value: i_next)
|
||||
// (var_name: "sum", init_value: 0, next_value: sum_next)
|
||||
//
|
||||
// Step 2: Create loop_step Function Signature
|
||||
// ============================================
|
||||
// Signature: fn loop_step(i: ValueId, sum: ValueId, k_exit: JoinContId) -> ...
|
||||
//
|
||||
// Step 3: Create k_exit Continuation
|
||||
// ===================================
|
||||
// fn k_exit(sum_exit) -> ValueId // Returns final sum value
|
||||
//
|
||||
// Step 4: Generate Exit Condition Check
|
||||
// ======================================
|
||||
// exit_cond = !(i < 10)
|
||||
// Jump(k_exit, [sum], cond=exit_cond)
|
||||
//
|
||||
// Step 5: Generate Continue Check
|
||||
// ================================
|
||||
// i_next = i + 1
|
||||
// continue_cond = (i_next % 2 == 0)
|
||||
// Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue to loop start
|
||||
//
|
||||
// Step 6: Translate Loop Body (after continue)
|
||||
// =============================================
|
||||
// sum_next = sum + i_next
|
||||
//
|
||||
// Step 7: Generate Tail Recursion
|
||||
// ================================
|
||||
// Call(loop_step, [i_next, sum_next], k_next: None)
|
||||
|
||||
eprintln!("[loop_patterns] Pattern 4: Continue lowering not yet implemented");
|
||||
None
|
||||
}
|
||||
123
src/mir/join_ir/lowering/loop_patterns/with_if_phi.rs
Normal file
123
src/mir/join_ir/lowering/loop_patterns/with_if_phi.rs
Normal file
@ -0,0 +1,123 @@
|
||||
//! Pattern 3: Loop with If-Else PHI Lowering
|
||||
//!
|
||||
//! Target: Loops with if expressions inside that merge values
|
||||
//! Example: `while(i < 10) { if x { y = 1 } else { y = 2 } }`
|
||||
//!
|
||||
//! # Transformation
|
||||
//!
|
||||
//! ```text
|
||||
//! fn loop_step(i, sum):
|
||||
//! exit_cond = !(i <= 5)
|
||||
//! Jump(k_exit, [sum], cond=exit_cond)
|
||||
//! sum_new = Select(cond=(i%2==1), then=sum+i, else=sum+0)
|
||||
//! i_next = i + 1
|
||||
//! Call(loop_step, [i_next, sum_new])
|
||||
//! ```
|
||||
|
||||
use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer;
|
||||
use crate::mir::join_ir::JoinInst;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
|
||||
/// Lowering for Pattern 3: Loop with If-Else PHI
|
||||
///
|
||||
/// # Transformation (Pseudocode from design.md)
|
||||
///
|
||||
/// ```text
|
||||
/// fn loop_step(i, sum):
|
||||
/// exit_cond = !(i <= 5)
|
||||
/// Jump(k_exit, [sum], cond=exit_cond)
|
||||
/// sum_new = Select(cond=(i%2==1), then=sum+i, else=sum+0)
|
||||
/// i_next = i + 1
|
||||
/// Call(loop_step, [i_next, sum_new])
|
||||
/// ```
|
||||
///
|
||||
/// # Steps (from design.md § Pattern 3 § Step-by-Step Transformation)
|
||||
///
|
||||
/// 1. **Extract Loop Variables** (multiple carriers: i + sum)
|
||||
/// 2. **Create loop_step Function** (params: i, sum, k_exit)
|
||||
/// 3. **Create k_exit with Exit PHI** (receives sum exit value)
|
||||
/// 4. **Generate Exit Condition Check** (same as Pattern 1)
|
||||
/// 5. **Translate If-Else to Select**
|
||||
/// - Use existing If lowering (Phase 33: Select/IfMerge)
|
||||
/// - Generate: `sum_new = Select(cond, then_val, else_val)`
|
||||
/// 6. **Translate Loop Body** (remaining instructions)
|
||||
/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_new)
|
||||
///
|
||||
/// # Key Difference from Pattern 1
|
||||
///
|
||||
/// - **Multiple Carrier Variables**: Loop updates i + sum
|
||||
/// - **In-Loop If Lowering**: Reuses existing Select/IfMerge lowering
|
||||
/// - **PHI in Loop Body**: If-else assigns to same variable (becomes Select)
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `loop_form` - The loop structure to lower (must have if-else in body)
|
||||
/// * `lowerer` - The LoopToJoinLowerer builder
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction
|
||||
/// * `None` - Lowering failed (pattern not matched or unsupported)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `None` if:
|
||||
/// - Loop has breaks or continues
|
||||
/// - If-else does not assign to same variable
|
||||
/// - If context cannot be resolved
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See design.md § Pattern 3 for complete transformation details and pseudocode.
|
||||
///
|
||||
/// # Example Usage
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::mir::loop_pattern_detection::is_loop_with_conditional_phi_pattern;
|
||||
///
|
||||
/// if is_loop_with_conditional_phi_pattern(&loop_form) {
|
||||
/// lower_loop_with_conditional_phi_to_joinir(&loop_form, &mut lowerer)?;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lower_loop_with_conditional_phi_to_joinir(
|
||||
_loop_form: &LoopForm,
|
||||
_lowerer: &mut LoopToJoinLowerer,
|
||||
) -> Option<JoinInst> {
|
||||
// Phase 188-Impl-3: Delegate to minimal lowerer
|
||||
// TODO: Extract LoopScopeShape from loop_form for generic implementation
|
||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||
use crate::mir::join_ir::lowering::loop_with_if_phi_minimal::lower_loop_with_if_phi_pattern;
|
||||
use crate::mir::BasicBlockId;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
// For now, use a placeholder LoopScopeShape
|
||||
// TODO: Build actual LoopScopeShape from loop_form
|
||||
let placeholder_scope = LoopScopeShape {
|
||||
header: BasicBlockId(0),
|
||||
body: BasicBlockId(0),
|
||||
latch: BasicBlockId(0),
|
||||
exit: BasicBlockId(0),
|
||||
pinned: BTreeSet::new(),
|
||||
carriers: BTreeSet::new(),
|
||||
body_locals: BTreeSet::new(),
|
||||
exit_live: BTreeSet::new(),
|
||||
progress_carrier: None,
|
||||
variable_definitions: BTreeMap::new(),
|
||||
};
|
||||
|
||||
// Generate JoinIR module
|
||||
let _join_module = lower_loop_with_if_phi_pattern(placeholder_scope)?;
|
||||
|
||||
// Phase 188-Impl-3: Pattern 3 is now integrated via the router
|
||||
// This function delegates to loop_with_if_phi_minimal which generates JoinModule
|
||||
//
|
||||
// TODO: Either:
|
||||
// 1. Remove this function and rely only on router integration, OR
|
||||
// 2. Implement JoinModule → JoinInst conversion here (future phase)
|
||||
|
||||
eprintln!("[loop_patterns] Pattern 3: Lowering delegated to loop_with_if_phi_minimal");
|
||||
|
||||
// Temporary: Return None to trigger fallback
|
||||
// Pattern 3 currently works via router which calls minimal lowerer directly
|
||||
None
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
//! JoinIR Lowering Functions
|
||||
//!
|
||||
//! Phase 27.9: Modular separation of MIR → JoinIR lowering implementations.
|
||||
//! Phase 33-12: Router-based If/Loop lowering organization.
|
||||
//!
|
||||
//! このモジュールは各種 MIR 関数を JoinIR に変換する lowering 関数を提供します。
|
||||
//!
|
||||
@ -15,6 +16,8 @@
|
||||
//! - `if_select.rs`: Phase 33 If/Else → Select lowering
|
||||
//! - `if_dry_runner.rs`: Phase 33-10 If lowering dry-run スキャナー(箱化版)
|
||||
//! - `bool_expr_lowerer.rs`: Phase 168 Boolean expression lowering (AST → SSA)
|
||||
//! - `if_lowering_router.rs`: Phase 33-12 If-expression routing (Select/IfMerge dispatcher)
|
||||
//! - `loop_pattern_router.rs`: Phase 33-12 Loop pattern routing (Pattern 1-4 dispatcher)
|
||||
|
||||
pub mod bool_expr_lowerer; // Phase 168: Boolean expression lowering for complex conditions
|
||||
pub mod carrier_info; // Phase 196: Carrier metadata for loop lowering
|
||||
@ -28,12 +31,14 @@ pub mod generic_case_a; // Phase 192: Modularized Case A lowering
|
||||
pub mod generic_type_resolver; // Phase 66: P3-C ジェネリック型推論箱
|
||||
pub mod method_return_hint; // Phase 83: P3-D 既知メソッド戻り値型推論箱
|
||||
pub mod if_dry_runner; // Phase 33-10.0
|
||||
pub mod if_lowering_router; // Phase 33-12: If-expression routing
|
||||
pub mod if_merge; // Phase 33-7
|
||||
pub mod if_phi_context; // Phase 61-1
|
||||
pub mod if_phi_spec; // Phase 61-2
|
||||
pub mod if_select; // Phase 33
|
||||
pub mod inline_boundary; // Phase 188-Impl-3: JoinIR→Host boundary
|
||||
pub mod loop_form_intake;
|
||||
pub mod loop_pattern_router; // Phase 33-12: Loop pattern routing
|
||||
pub mod loop_patterns; // Phase 188: Pattern-based loop lowering (3 patterns)
|
||||
pub mod loop_scope_shape;
|
||||
pub mod loop_to_join;
|
||||
@ -64,10 +69,9 @@ pub use stage1_using_resolver::lower_stage1_usingresolver_to_joinir;
|
||||
pub use stageb_body::lower_stageb_body_to_joinir;
|
||||
pub use stageb_funcscanner::lower_stageb_funcscanner_to_joinir;
|
||||
|
||||
// Phase 33: If/Else → Select lowering entry point
|
||||
use crate::mir::join_ir::JoinInst;
|
||||
use crate::mir::loop_form::LoopForm; // Phase 188: Loop pattern lowering
|
||||
use crate::mir::{BasicBlockId, MirFunction};
|
||||
// Phase 33-12: Re-export router functions (backward compatibility)
|
||||
pub use if_lowering_router::try_lower_if_to_joinir;
|
||||
pub use loop_pattern_router::try_lower_loop_pattern_to_joinir;
|
||||
|
||||
/// Phase 33-9.1: Loop lowering対象関数の判定
|
||||
///
|
||||
@ -179,300 +183,6 @@ pub fn is_joinir_if_toplevel_target(name: &str) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Phase 33-7: Try to lower if/else to JoinIR Select/IfMerge instruction
|
||||
///
|
||||
/// Scope:
|
||||
/// - Only applies to whitelisted functions:
|
||||
/// - IfSelectTest.* (Phase 33-2/33-3)
|
||||
/// - IfMergeTest.* (Phase 33-7)
|
||||
/// - JsonShapeToMap._read_value_from_pair/1 (Phase 33-4 Stage-1)
|
||||
/// - Stage1JsonScannerBox.value_start_after_key_pos/2 (Phase 33-4 Stage-B)
|
||||
/// - Requires JoinIR If-select toggle (HAKO_JOINIR_IF_SELECT / joinir_if_select_enabled)
|
||||
/// - Falls back to traditional if_phi on pattern mismatch
|
||||
///
|
||||
/// Pattern selection:
|
||||
/// - 1 variable → Select
|
||||
/// - 2+ variables → IfMerge
|
||||
///
|
||||
/// Phase 61-1: If-in-loop support
|
||||
/// - `context` parameter: If-in-loop context (carrier_names for loop variables)
|
||||
/// - None = Pure If, Some(_) = If-in-loop
|
||||
///
|
||||
/// Returns Some(JoinInst::Select) or Some(JoinInst::IfMerge) if pattern matched, None otherwise.
|
||||
pub fn try_lower_if_to_joinir(
|
||||
func: &MirFunction,
|
||||
block_id: BasicBlockId,
|
||||
debug: bool,
|
||||
context: Option<&if_phi_context::IfPhiContext>, // Phase 61-1: If-in-loop context
|
||||
) -> Option<JoinInst> {
|
||||
// 1. dev/Core トグルチェック
|
||||
//
|
||||
// - Core: joinir_core_enabled() / joinir_if_select_enabled()
|
||||
// - Dev: joinir_dev_enabled()(詳細ログ等)
|
||||
//
|
||||
// 実際の挙動切り替えは joinir_if_select_enabled() に集約し、
|
||||
// Core/Dev ポリシーは config::env 側で判定する。
|
||||
if !crate::config::env::joinir_if_select_enabled() {
|
||||
return None;
|
||||
}
|
||||
let core_on = crate::config::env::joinir_core_enabled();
|
||||
// Phase 185: strict check moved to caller (if_form.rs)
|
||||
// let strict_on = crate::config::env::joinir_strict_enabled();
|
||||
|
||||
// Phase 33-9.1: Loop専任関数の除外(Loop/If責務分離)
|
||||
// Loop lowering対象関数はIf loweringの対象外にすることで、
|
||||
// 1関数につき1 loweringの原則を保証します
|
||||
if is_loop_lowered_function(&func.signature.name) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Phase 33-8: デバッグログレベル取得(0-3)
|
||||
let debug_level = crate::config::env::joinir_debug_level();
|
||||
let _debug = debug || debug_level >= 1;
|
||||
|
||||
// 2. Phase 33-8: 関数名ガード拡張(テスト + Stage-1 rollout + 明示承認)
|
||||
let is_allowed =
|
||||
// Test functions (always enabled)
|
||||
func.signature.name.starts_with("IfSelectTest.") ||
|
||||
func.signature.name.starts_with("IfSelectLocalTest.") || // Phase 33-10 test
|
||||
func.signature.name.starts_with("IfMergeTest.") ||
|
||||
func.signature.name.starts_with("IfToplevelTest.") || // Phase 61-4: loop-outside if test
|
||||
func.signature.name.starts_with("Stage1JsonScannerTestBox.") || // Phase 33-5 test
|
||||
|
||||
// Stage-1 rollout (env-controlled)
|
||||
(crate::config::env::joinir_stage1_enabled() &&
|
||||
func.signature.name.starts_with("Stage1")) ||
|
||||
|
||||
// Explicit approvals (Phase 33-4で検証済み, always on)
|
||||
matches!(func.signature.name.as_str(),
|
||||
"JsonShapeToMap._read_value_from_pair/1" |
|
||||
"Stage1JsonScannerBox.value_start_after_key_pos/2"
|
||||
);
|
||||
|
||||
// Phase 80: Core ON のときは許可リストを「JoinIRをまず試す」対象とみなす。
|
||||
// Core OFF のときは従来どおり whitelist + env に頼る。
|
||||
if !is_allowed || !core_on {
|
||||
// Core OFF かつ許可外なら従来のガードでスキップ
|
||||
if !is_allowed {
|
||||
if debug_level >= 2 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] skipping non-allowed function: {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// Phase 185: strict_allowed removed (strict check moved to caller: if_form.rs)
|
||||
|
||||
if debug_level >= 1 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] trying to lower {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン)
|
||||
// IfMerge が成功すればそれを返す、失敗したら Select を試行
|
||||
// Phase 61-1: context がある場合は with_context() を使用
|
||||
let if_merge_lowerer = if let Some(ctx) = context {
|
||||
if_merge::IfMergeLowerer::with_context(debug_level, ctx.clone())
|
||||
} else {
|
||||
if_merge::IfMergeLowerer::new(debug_level)
|
||||
};
|
||||
|
||||
if if_merge_lowerer.can_lower_to_if_merge(func, block_id) {
|
||||
if let Some(result) = if_merge_lowerer.lower_if_to_if_merge(func, block_id) {
|
||||
if debug_level >= 1 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] ✅ IfMerge lowering used for {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. IfMerge が失敗したら Select を試行(単一変数パターン)
|
||||
// Phase 61-1: context がある場合は with_context() を使用
|
||||
let if_select_lowerer = if let Some(ctx) = context {
|
||||
if_select::IfSelectLowerer::with_context(debug_level, ctx.clone())
|
||||
} else {
|
||||
if_select::IfSelectLowerer::new(debug_level)
|
||||
};
|
||||
|
||||
// Phase 185: Remove strict checks from lowerer (thin Result-returning box)
|
||||
// Strict mode panic should happen at caller level (if_form.rs), not here
|
||||
if !if_select_lowerer.can_lower_to_select(func, block_id) {
|
||||
if debug_level >= 1 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] pattern not matched for {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
let result = if_select_lowerer.lower_if_to_select(func, block_id);
|
||||
|
||||
if result.is_some() && debug_level >= 1 {
|
||||
eprintln!(
|
||||
"[try_lower_if_to_joinir] ✅ Select lowering used for {}",
|
||||
func.signature.name
|
||||
);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Phase 188: Loop Pattern-Based Lowering Router
|
||||
// ============================================================================
|
||||
|
||||
/// 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)
|
||||
///
|
||||
/// # 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 `Ok(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)
|
||||
///
|
||||
/// # Integration Point
|
||||
///
|
||||
/// This function should be called from loop lowering entry points:
|
||||
/// - `loop_to_join.rs::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`
|
||||
///
|
||||
/// # TODO (Phase 188 Task 188-4 Implementation)
|
||||
///
|
||||
/// This function is a skeleton. Implementation steps:
|
||||
///
|
||||
/// 1. **Implement Pattern Detection** (Step 1: 6-8h)
|
||||
/// - Complete `loop_pattern_detection::is_simple_while_pattern()`
|
||||
/// - Test with `apps/tests/loop_min_while.hako`
|
||||
///
|
||||
/// 2. **Implement Pattern 1 Lowering** (Step 1: 6-8h)
|
||||
/// - Complete `loop_patterns::lower_simple_while_to_joinir()`
|
||||
/// - Verify no [joinir/freeze] error
|
||||
///
|
||||
/// 3. **Implement Pattern 2** (Step 2: 6-10h)
|
||||
/// - Complete `loop_pattern_detection::is_loop_with_break_pattern()`
|
||||
/// - Complete `loop_patterns::lower_loop_with_break_to_joinir()`
|
||||
/// - Test with `apps/tests/joinir_min_loop.hako`
|
||||
///
|
||||
/// 4. **Implement Pattern 3** (Step 3: 6-10h)
|
||||
/// - Complete `loop_pattern_detection::is_loop_with_conditional_phi_pattern()`
|
||||
/// - Complete `loop_patterns::lower_loop_with_conditional_phi_to_joinir()`
|
||||
/// - Test with `apps/tests/loop_if_phi.hako`
|
||||
///
|
||||
/// 5. **Integration Testing** (Step 4: 2-4h)
|
||||
/// - Run all 3 tests with JoinIR-only
|
||||
/// - Verify no regressions
|
||||
/// - Document results
|
||||
///
|
||||
/// **Total Estimated Effort**: 18-28 hours
|
||||
pub fn try_lower_loop_pattern_to_joinir(
|
||||
loop_form: &LoopForm,
|
||||
lowerer: &mut 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) = 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) = 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) = 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) = loop_patterns::lower_simple_while_to_joinir(loop_form, lowerer) {
|
||||
eprintln!("[try_lower_loop_pattern] ✅ Pattern 1 (Simple While) matched");
|
||||
return Some(inst);
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user