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:
nyash-codex
2025-12-07 03:26:06 +09:00
parent 192c29efb1
commit adccfe5a4e
9 changed files with 1113 additions and 1033 deletions

View File

@ -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::*;