//! JoinIR Lowering Functions //! //! Phase 27.9: Modular separation of MIR → JoinIR lowering implementations. //! //! このモジュールは各種 MIR 関数を JoinIR に変換する lowering 関数を提供します。 //! //! ## 構成: //! - `common.rs`: CFG sanity checks と lowering 共通ユーティリティ(Phase 27.10) //! - `value_id_ranges.rs`: ValueId 範囲管理(Phase 27.13+) //! - `min_loop.rs`: JoinIrMin.main/0 専用の最小ループ lowering //! - `skip_ws.rs`: Main.skip/1 の空白スキップ lowering(手書き版+MIR自動解析版) //! - `funcscanner_trim.rs`: FuncScannerBox.trim/1 の trim lowering //! - `stage1_using_resolver.rs`: Stage1UsingResolverBox.resolve_for_source entries loop lowering(Phase 27.12) //! - `funcscanner_append_defs.rs`: FuncScannerBox._append_defs/2 の配列結合 lowering(Phase 27.14) //! - `if_select.rs`: Phase 33 If/Else → Select lowering //! - `if_dry_runner.rs`: Phase 33-10 If lowering dry-run スキャナー(箱化版) pub mod carrier_info; // Phase 196: Carrier metadata for loop lowering pub mod common; pub mod exit_args_resolver; pub mod funcscanner_append_defs; pub mod funcscanner_trim; 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_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_patterns; // Phase 188: Pattern-based loop lowering (3 patterns) pub mod loop_scope_shape; pub mod loop_to_join; pub mod loop_with_break_minimal; // Phase 188-Impl-2: Pattern 2 minimal lowerer pub mod loop_with_continue_minimal; // Phase 195: Pattern 4 minimal lowerer pub mod loop_with_if_phi_minimal; // Phase 188-Impl-3: Pattern 3 minimal lowerer pub mod simple_while_minimal; // Phase 188-Impl-1: Pattern 1 minimal lowerer pub mod min_loop; pub mod skip_ws; pub mod stage1_using_resolver; pub mod stageb_body; pub mod stageb_funcscanner; pub mod type_hint_policy; // Phase 65.5: 型ヒントポリシー箱化 pub mod type_inference; // Phase 65-2-A pub mod value_id_ranges; // Re-export public lowering functions pub use funcscanner_append_defs::lower_funcscanner_append_defs_to_joinir; pub use funcscanner_trim::lower_funcscanner_trim_to_joinir; // Phase 31: LoopToJoinLowerer 統一箱 pub use loop_to_join::LoopToJoinLowerer; // Phase 188: Pattern-based loop lowering pub use loop_with_if_phi_minimal::lower_loop_with_if_phi_pattern; // Phase 30 F-3: 旧 lower_case_a_loop_to_joinir_for_minimal_skip_ws は _with_scope に置き換え済みのため削除 pub use min_loop::lower_min_loop_to_joinir; pub use skip_ws::lower_skip_ws_to_joinir; 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-9.1: Loop lowering対象関数の判定 /// /// これらの関数は Phase 32/33 で LoopToJoinLowerer によって処理されます。 /// If lowering (Select/IfMerge) の対象から除外することで、Loop/If の責務を明確に分離します。 /// /// Phase 82 SSOT: JOINIR_TARGETS テーブルから Exec 対象を参照 /// (テーブルは vm_bridge_dispatch/targets.rs で一元管理) /// /// ## 対象関数(6本) /// - Main.skip/1: 空白スキップループ /// - FuncScannerBox.trim/1: 前後空白削除ループ /// - FuncScannerBox.append_defs/2: 配列結合ループ /// - Stage1UsingResolverBox.resolve_for_source/5: using解析ループ /// - StageBBodyExtractorBox.build_body_src/2: Stage-B本体抽出ループ /// - StageBFuncScannerBox.scan_all_boxes/1: Stage-B Box走査ループ /// /// ## 将来の拡張 /// NYASH_JOINIR_LOWER_GENERIC=1 で汎用 Case-A ループにも拡張可能 pub(crate) fn is_loop_lowered_function(name: &str) -> bool { // Phase 82 SSOT: vm_bridge_dispatch テーブルから Loop 関数を抽出 // Phase 33-9.1: If lowering の除外対象は、JOINIR_TARGETS に登録されたすべての関数 // (Exec/LowerOnly 問わず、ループ専任関数として Loop lowering で処理) crate::mir::join_ir_vm_bridge_dispatch::JOINIR_TARGETS .iter() .any(|t| t.func_name == name) } // ============================================================================ // Phase 80: JoinIR Mainline Unification - Core ON 時の本線化判定 // ============================================================================ /// Phase 80: JoinIR 本線化対象(Loop)の判定 /// /// `joinir_core_enabled()=true` の時、これらの関数のループは /// 必ず JoinIR → MIR 経路を本線として試行します。 pub fn is_loop_mainline_target(name: &str) -> bool { is_loop_lowered_function(name) } /// Phase 80/184: JoinIR 本線化対象(If)の判定 /// /// `joinir_core_enabled()=true` の時、これらの関数の if/else は /// 必ず JoinIR → MIR 経路を本線として試行します。 /// /// Phase 184: JOINIR_IF_TARGETS テーブルからの参照に変更 pub fn is_if_mainline_target(name: &str) -> bool { crate::mir::join_ir_vm_bridge_dispatch::is_if_lowered_function(name) } /// Phase 80: Core ON 時に JoinIR を本線として試行すべきか判定 /// /// Returns true if: /// - `joinir_core_enabled()=true` AND /// - 関数が本線化対象 (Loop or If) pub fn should_try_joinir_mainline(func_name: &str, is_loop: bool) -> bool { if !crate::config::env::joinir_core_enabled() { return false; } if is_loop { is_loop_mainline_target(func_name) } else { is_if_mainline_target(func_name) } } /// Phase 80/81: Strict モードで JoinIR lowering 失敗時にパニックすべきか判定 pub fn should_panic_on_joinir_failure(func_name: &str, is_loop: bool) -> bool { if !crate::config::env::joinir_strict_enabled() { return false; } should_try_joinir_mainline(func_name, is_loop) } /// Phase 61-4/184: ループ外 If の JoinIR 対象関数判定 /// /// HAKO_JOINIR_IF_TOPLEVEL=1 有効時に、ループ外 if の JoinIR 経路を試行する関数。 /// Phase 184: JOINIR_IF_TARGETS テーブルに統一(SSOT化) /// /// ## 対象関数(テーブル管理) /// - IfSelectTest.*: テスト専用関数群 /// - IfMergeTest.*: 複数変数テスト(Phase 33-7) /// - IfToplevelTest.*: ループ外 if テスト専用(Phase 61-4) /// - JsonShapeToMap._read_value_from_pair/1: Phase 33-4 Stage-1 実用関数 /// - Stage1JsonScannerBox.value_start_after_key_pos/2: Phase 33-4 Stage-B 実用関数 /// /// ## 使用方法 /// if_form.rs から呼び出され、関数名がテーブルに含まれる場合のみ /// JoinIR 経路を試行する。 /// /// Phase 184: テーブル参照に変更(プレフィックス判定は併用) pub fn is_joinir_if_toplevel_target(name: &str) -> bool { // Phase 184: JOINIR_IF_TARGETS テーブルから参照(exact match) if crate::mir::join_ir_vm_bridge_dispatch::JOINIR_IF_TARGETS .iter() .any(|t| t.func_name == name) { return true; } // Test prefixes (backward compatibility - allows any test function) if name.starts_with("IfSelectTest.") || name.starts_with("IfToplevelTest.") || name.starts_with("IfMergeTest.") { return true; } 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 { // 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 { // 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::*; /// Phase 33-9.1: is_loop_lowered_function() の動作確認 #[test] fn test_is_loop_lowered_function() { // Loop 専任関数(6本)は true を返す assert!(is_loop_lowered_function("Main.skip/1")); assert!(is_loop_lowered_function("FuncScannerBox.trim/1")); assert!(is_loop_lowered_function("FuncScannerBox.append_defs/2")); assert!(is_loop_lowered_function( "Stage1UsingResolverBox.resolve_for_source/5" )); assert!(is_loop_lowered_function( "StageBBodyExtractorBox.build_body_src/2" )); assert!(is_loop_lowered_function( "StageBFuncScannerBox.scan_all_boxes/1" )); // If lowering 対象関数は false を返す assert!(!is_loop_lowered_function("IfSelectTest.simple_return/0")); assert!(!is_loop_lowered_function("IfMergeTest.multiple_true/0")); assert!(!is_loop_lowered_function( "JsonShapeToMap._read_value_from_pair/1" )); assert!(!is_loop_lowered_function( "Stage1JsonScannerBox.value_start_after_key_pos/2" )); // 一般的な関数も false を返す assert!(!is_loop_lowered_function("SomeBox.some_method/3")); assert!(!is_loop_lowered_function("Main.main/0")); } }