2025-11-23 16:49:49 +09:00
|
|
|
|
//! JoinIR Lowering Functions
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! Phase 27.9: Modular separation of MIR → JoinIR lowering implementations.
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! このモジュールは各種 MIR 関数を JoinIR に変換する lowering 関数を提供します。
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! ## 構成:
|
2025-11-23 22:51:30 +09:00
|
|
|
|
//! - `common.rs`: CFG sanity checks と lowering 共通ユーティリティ(Phase 27.10)
|
2025-11-24 03:58:30 +09:00
|
|
|
|
//! - `value_id_ranges.rs`: ValueId 範囲管理(Phase 27.13+)
|
2025-11-23 16:49:49 +09:00
|
|
|
|
//! - `min_loop.rs`: JoinIrMin.main/0 専用の最小ループ lowering
|
|
|
|
|
|
//! - `skip_ws.rs`: Main.skip/1 の空白スキップ lowering(手書き版+MIR自動解析版)
|
|
|
|
|
|
//! - `funcscanner_trim.rs`: FuncScannerBox.trim/1 の trim lowering
|
2025-11-24 02:34:36 +09:00
|
|
|
|
//! - `stage1_using_resolver.rs`: Stage1UsingResolverBox.resolve_for_source entries loop lowering(Phase 27.12)
|
2025-11-24 05:23:26 +09:00
|
|
|
|
//! - `funcscanner_append_defs.rs`: FuncScannerBox._append_defs/2 の配列結合 lowering(Phase 27.14)
|
2025-11-27 02:58:38 +09:00
|
|
|
|
//! - `if_select.rs`: Phase 33 If/Else → Select lowering
|
2025-11-27 17:05:46 +09:00
|
|
|
|
//! - `if_dry_runner.rs`: Phase 33-10 If lowering dry-run スキャナー(箱化版)
|
2025-11-23 16:49:49 +09:00
|
|
|
|
|
2025-11-23 22:51:30 +09:00
|
|
|
|
pub mod common;
|
2025-11-24 14:17:02 +09:00
|
|
|
|
pub mod exit_args_resolver;
|
2025-11-24 05:23:26 +09:00
|
|
|
|
pub mod funcscanner_append_defs;
|
2025-11-23 16:49:49 +09:00
|
|
|
|
pub mod funcscanner_trim;
|
2025-11-24 14:17:02 +09:00
|
|
|
|
pub mod generic_case_a;
|
2025-12-01 11:10:46 +09:00
|
|
|
|
pub mod generic_type_resolver; // Phase 66: P3-C ジェネリック型推論箱
|
2025-12-02 18:09:04 +09:00
|
|
|
|
pub mod method_return_hint; // Phase 83: P3-D 既知メソッド戻り値型推論箱
|
2025-11-27 17:05:46 +09:00
|
|
|
|
pub mod if_dry_runner; // Phase 33-10.0
|
2025-11-27 08:18:09 +09:00
|
|
|
|
pub mod if_merge; // Phase 33-7
|
2025-11-29 11:53:57 +09:00
|
|
|
|
pub mod if_phi_context; // Phase 61-1
|
2025-11-29 12:26:02 +09:00
|
|
|
|
pub mod if_phi_spec; // Phase 61-2
|
2025-11-27 02:58:38 +09:00
|
|
|
|
pub mod if_select; // Phase 33
|
2025-11-24 14:17:02 +09:00
|
|
|
|
pub mod loop_form_intake;
|
2025-12-05 07:47:22 +09:00
|
|
|
|
pub mod loop_patterns; // Phase 188: Pattern-based loop lowering (3 patterns)
|
2025-11-25 06:32:08 +09:00
|
|
|
|
pub mod loop_scope_shape;
|
2025-11-26 01:18:32 +09:00
|
|
|
|
pub mod loop_to_join;
|
2025-12-05 07:47:22 +09:00
|
|
|
|
pub mod simple_while_minimal; // Phase 188-Impl-1: Pattern 1 minimal lowerer
|
2025-11-23 16:49:49 +09:00
|
|
|
|
pub mod min_loop;
|
|
|
|
|
|
pub mod skip_ws;
|
2025-11-24 02:34:36 +09:00
|
|
|
|
pub mod stage1_using_resolver;
|
2025-11-24 14:17:02 +09:00
|
|
|
|
pub mod stageb_body;
|
|
|
|
|
|
pub mod stageb_funcscanner;
|
2025-11-30 06:37:34 +09:00
|
|
|
|
pub mod type_hint_policy; // Phase 65.5: 型ヒントポリシー箱化
|
2025-11-30 06:10:58 +09:00
|
|
|
|
pub mod type_inference; // Phase 65-2-A
|
2025-11-24 14:17:02 +09:00
|
|
|
|
pub mod value_id_ranges;
|
2025-11-23 16:49:49 +09:00
|
|
|
|
|
|
|
|
|
|
// Re-export public lowering functions
|
2025-11-24 05:23:26 +09:00
|
|
|
|
pub use funcscanner_append_defs::lower_funcscanner_append_defs_to_joinir;
|
2025-11-23 16:49:49 +09:00
|
|
|
|
pub use funcscanner_trim::lower_funcscanner_trim_to_joinir;
|
2025-11-26 01:18:32 +09:00
|
|
|
|
// Phase 31: LoopToJoinLowerer 統一箱
|
|
|
|
|
|
pub use loop_to_join::LoopToJoinLowerer;
|
2025-11-25 23:25:39 +09:00
|
|
|
|
// Phase 30 F-3: 旧 lower_case_a_loop_to_joinir_for_minimal_skip_ws は _with_scope に置き換え済みのため削除
|
2025-11-23 16:49:49 +09:00
|
|
|
|
pub use min_loop::lower_min_loop_to_joinir;
|
|
|
|
|
|
pub use skip_ws::lower_skip_ws_to_joinir;
|
2025-11-24 02:34:36 +09:00
|
|
|
|
pub use stage1_using_resolver::lower_stage1_usingresolver_to_joinir;
|
2025-11-24 14:17:02 +09:00
|
|
|
|
pub use stageb_body::lower_stageb_body_to_joinir;
|
|
|
|
|
|
pub use stageb_funcscanner::lower_stageb_funcscanner_to_joinir;
|
2025-11-27 03:28:32 +09:00
|
|
|
|
|
|
|
|
|
|
// Phase 33: If/Else → Select lowering entry point
|
|
|
|
|
|
use crate::mir::join_ir::JoinInst;
|
2025-12-05 07:47:22 +09:00
|
|
|
|
use crate::mir::loop_form::LoopForm; // Phase 188: Loop pattern lowering
|
2025-11-27 03:28:32 +09:00
|
|
|
|
use crate::mir::{BasicBlockId, MirFunction};
|
|
|
|
|
|
|
2025-11-27 10:58:56 +09:00
|
|
|
|
/// Phase 33-9.1: Loop lowering対象関数の判定
|
|
|
|
|
|
///
|
|
|
|
|
|
/// これらの関数は Phase 32/33 で LoopToJoinLowerer によって処理されます。
|
|
|
|
|
|
/// If lowering (Select/IfMerge) の対象から除外することで、Loop/If の責務を明確に分離します。
|
|
|
|
|
|
///
|
2025-12-02 14:01:44 +09:00
|
|
|
|
/// Phase 82 SSOT: JOINIR_TARGETS テーブルから Exec 対象を参照
|
|
|
|
|
|
/// (テーブルは vm_bridge_dispatch/targets.rs で一元管理)
|
|
|
|
|
|
///
|
2025-11-27 10:58:56 +09:00
|
|
|
|
/// ## 対象関数(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 {
|
2025-12-02 14:01:44 +09:00
|
|
|
|
// 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)
|
2025-11-27 10:58:56 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-02 13:45:47 +09:00
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// 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)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-04 21:58:45 +09:00
|
|
|
|
/// Phase 80/184: JoinIR 本線化対象(If)の判定
|
2025-12-02 13:45:47 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// `joinir_core_enabled()=true` の時、これらの関数の if/else は
|
|
|
|
|
|
/// 必ず JoinIR → MIR 経路を本線として試行します。
|
2025-12-04 21:58:45 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// Phase 184: JOINIR_IF_TARGETS テーブルからの参照に変更
|
2025-12-02 13:45:47 +09:00
|
|
|
|
pub fn is_if_mainline_target(name: &str) -> bool {
|
2025-12-04 21:58:45 +09:00
|
|
|
|
crate::mir::join_ir_vm_bridge_dispatch::is_if_lowered_function(name)
|
2025-12-02 13:45:47 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 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)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-04 21:58:45 +09:00
|
|
|
|
/// Phase 61-4/184: ループ外 If の JoinIR 対象関数判定
|
2025-11-29 15:15:22 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// HAKO_JOINIR_IF_TOPLEVEL=1 有効時に、ループ外 if の JoinIR 経路を試行する関数。
|
2025-12-04 21:58:45 +09:00
|
|
|
|
/// Phase 184: JOINIR_IF_TARGETS テーブルに統一(SSOT化)
|
2025-11-29 15:15:22 +09:00
|
|
|
|
///
|
2025-12-04 21:58:45 +09:00
|
|
|
|
/// ## 対象関数(テーブル管理)
|
2025-11-29 15:15:22 +09:00
|
|
|
|
/// - IfSelectTest.*: テスト専用関数群
|
2025-12-04 21:58:45 +09:00
|
|
|
|
/// - IfMergeTest.*: 複数変数テスト(Phase 33-7)
|
2025-11-29 15:15:22 +09:00
|
|
|
|
/// - IfToplevelTest.*: ループ外 if テスト専用(Phase 61-4)
|
2025-12-04 21:58:45 +09:00
|
|
|
|
/// - JsonShapeToMap._read_value_from_pair/1: Phase 33-4 Stage-1 実用関数
|
|
|
|
|
|
/// - Stage1JsonScannerBox.value_start_after_key_pos/2: Phase 33-4 Stage-B 実用関数
|
2025-11-29 15:15:22 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// ## 使用方法
|
2025-12-04 21:58:45 +09:00
|
|
|
|
/// if_form.rs から呼び出され、関数名がテーブルに含まれる場合のみ
|
2025-11-29 15:15:22 +09:00
|
|
|
|
/// JoinIR 経路を試行する。
|
2025-12-04 21:58:45 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// Phase 184: テーブル参照に変更(プレフィックス判定は併用)
|
2025-11-29 15:15:22 +09:00
|
|
|
|
pub fn is_joinir_if_toplevel_target(name: &str) -> bool {
|
2025-12-04 21:58:45 +09:00
|
|
|
|
// 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)
|
2025-11-29 15:15:22 +09:00
|
|
|
|
if name.starts_with("IfSelectTest.")
|
|
|
|
|
|
|| name.starts_with("IfToplevelTest.")
|
|
|
|
|
|
|| name.starts_with("IfMergeTest.")
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-04 21:58:45 +09:00
|
|
|
|
false
|
2025-11-29 15:15:22 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 08:18:09 +09:00
|
|
|
|
/// Phase 33-7: Try to lower if/else to JoinIR Select/IfMerge instruction
|
2025-11-27 03:28:32 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// Scope:
|
2025-11-27 04:58:01 +09:00
|
|
|
|
/// - Only applies to whitelisted functions:
|
|
|
|
|
|
/// - IfSelectTest.* (Phase 33-2/33-3)
|
2025-11-27 08:18:09 +09:00
|
|
|
|
/// - IfMergeTest.* (Phase 33-7)
|
2025-11-27 05:39:29 +09:00
|
|
|
|
/// - JsonShapeToMap._read_value_from_pair/1 (Phase 33-4 Stage-1)
|
2025-11-27 04:58:01 +09:00
|
|
|
|
/// - Stage1JsonScannerBox.value_start_after_key_pos/2 (Phase 33-4 Stage-B)
|
2025-11-30 14:30:28 +09:00
|
|
|
|
/// - Requires JoinIR If-select toggle (HAKO_JOINIR_IF_SELECT / joinir_if_select_enabled)
|
2025-11-27 03:28:32 +09:00
|
|
|
|
/// - Falls back to traditional if_phi on pattern mismatch
|
|
|
|
|
|
///
|
2025-11-27 08:18:09 +09:00
|
|
|
|
/// Pattern selection:
|
|
|
|
|
|
/// - 1 variable → Select
|
|
|
|
|
|
/// - 2+ variables → IfMerge
|
|
|
|
|
|
///
|
2025-11-29 11:53:57 +09:00
|
|
|
|
/// 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
|
|
|
|
|
|
///
|
2025-11-27 08:18:09 +09:00
|
|
|
|
/// Returns Some(JoinInst::Select) or Some(JoinInst::IfMerge) if pattern matched, None otherwise.
|
2025-11-27 03:28:32 +09:00
|
|
|
|
pub fn try_lower_if_to_joinir(
|
|
|
|
|
|
func: &MirFunction,
|
|
|
|
|
|
block_id: BasicBlockId,
|
|
|
|
|
|
debug: bool,
|
2025-11-29 11:53:57 +09:00
|
|
|
|
context: Option<&if_phi_context::IfPhiContext>, // Phase 61-1: If-in-loop context
|
2025-11-27 03:28:32 +09:00
|
|
|
|
) -> Option<JoinInst> {
|
2025-11-30 14:30:28 +09:00
|
|
|
|
// 1. dev/Core トグルチェック
|
|
|
|
|
|
//
|
|
|
|
|
|
// - Core: joinir_core_enabled() / joinir_if_select_enabled()
|
|
|
|
|
|
// - Dev: joinir_dev_enabled()(詳細ログ等)
|
|
|
|
|
|
//
|
|
|
|
|
|
// 実際の挙動切り替えは joinir_if_select_enabled() に集約し、
|
|
|
|
|
|
// Core/Dev ポリシーは config::env 側で判定する。
|
2025-11-27 03:28:32 +09:00
|
|
|
|
if !crate::config::env::joinir_if_select_enabled() {
|
|
|
|
|
|
return None;
|
|
|
|
|
|
}
|
2025-12-01 11:10:46 +09:00
|
|
|
|
let core_on = crate::config::env::joinir_core_enabled();
|
2025-12-04 22:27:12 +09:00
|
|
|
|
// Phase 185: strict check moved to caller (if_form.rs)
|
|
|
|
|
|
// let strict_on = crate::config::env::joinir_strict_enabled();
|
2025-11-27 03:28:32 +09:00
|
|
|
|
|
2025-11-27 10:58:56 +09:00
|
|
|
|
// Phase 33-9.1: Loop専任関数の除外(Loop/If責務分離)
|
|
|
|
|
|
// Loop lowering対象関数はIf loweringの対象外にすることで、
|
|
|
|
|
|
// 1関数につき1 loweringの原則を保証します
|
|
|
|
|
|
if is_loop_lowered_function(&func.signature.name) {
|
|
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// 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.") ||
|
2025-11-27 17:05:46 +09:00
|
|
|
|
func.signature.name.starts_with("IfSelectLocalTest.") || // Phase 33-10 test
|
2025-11-27 09:30:54 +09:00
|
|
|
|
func.signature.name.starts_with("IfMergeTest.") ||
|
2025-11-29 15:32:40 +09:00
|
|
|
|
func.signature.name.starts_with("IfToplevelTest.") || // Phase 61-4: loop-outside if test
|
2025-11-27 09:30:54 +09:00
|
|
|
|
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"
|
|
|
|
|
|
);
|
2025-11-27 04:58:01 +09:00
|
|
|
|
|
2025-12-01 11:10:46 +09:00
|
|
|
|
// 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;
|
2025-11-27 03:28:32 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-04 22:27:12 +09:00
|
|
|
|
// Phase 185: strict_allowed removed (strict check moved to caller: if_form.rs)
|
2025-11-27 03:28:32 +09:00
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
if debug_level >= 1 {
|
2025-11-28 17:42:19 +09:00
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[try_lower_if_to_joinir] trying to lower {}",
|
|
|
|
|
|
func.signature.name
|
|
|
|
|
|
);
|
2025-11-27 09:30:54 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 08:18:09 +09:00
|
|
|
|
// 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン)
|
|
|
|
|
|
// IfMerge が成功すればそれを返す、失敗したら Select を試行
|
2025-11-29 11:53:57 +09:00
|
|
|
|
// 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)
|
|
|
|
|
|
};
|
2025-11-27 08:18:09 +09:00
|
|
|
|
|
|
|
|
|
|
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) {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
if debug_level >= 1 {
|
2025-11-27 08:18:09 +09:00
|
|
|
|
eprintln!(
|
2025-11-27 09:30:54 +09:00
|
|
|
|
"[try_lower_if_to_joinir] ✅ IfMerge lowering used for {}",
|
2025-11-27 08:18:09 +09:00
|
|
|
|
func.signature.name
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Some(result);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. IfMerge が失敗したら Select を試行(単一変数パターン)
|
2025-11-29 11:53:57 +09:00
|
|
|
|
// 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)
|
|
|
|
|
|
};
|
2025-11-27 03:28:32 +09:00
|
|
|
|
|
2025-12-04 22:27:12 +09:00
|
|
|
|
// Phase 185: Remove strict checks from lowerer (thin Result-returning box)
|
|
|
|
|
|
// Strict mode panic should happen at caller level (if_form.rs), not here
|
2025-11-27 08:18:09 +09:00
|
|
|
|
if !if_select_lowerer.can_lower_to_select(func, block_id) {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
if debug_level >= 1 {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[try_lower_if_to_joinir] pattern not matched for {}",
|
|
|
|
|
|
func.signature.name
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 08:18:09 +09:00
|
|
|
|
let result = if_select_lowerer.lower_if_to_select(func, block_id);
|
2025-11-27 03:28:32 +09:00
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
if result.is_some() && debug_level >= 1 {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
eprintln!(
|
2025-11-27 09:30:54 +09:00
|
|
|
|
"[try_lower_if_to_joinir] ✅ Select lowering used for {}",
|
2025-11-27 03:28:32 +09:00
|
|
|
|
func.signature.name
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
|
}
|
2025-11-27 10:58:56 +09:00
|
|
|
|
|
2025-12-05 07:47:22 +09:00
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// 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> {
|
|
|
|
|
|
// TODO: Implement pattern routing logic
|
|
|
|
|
|
//
|
|
|
|
|
|
// Pattern 1: Simple While Loop (easiest, most common)
|
|
|
|
|
|
// ====================================================
|
|
|
|
|
|
//
|
|
|
|
|
|
// ```rust
|
|
|
|
|
|
// use crate::mir::loop_pattern_detection::is_simple_while_pattern;
|
|
|
|
|
|
// use crate::mir::join_ir::lowering::loop_patterns::lower_simple_while_to_joinir;
|
|
|
|
|
|
//
|
|
|
|
|
|
// if is_simple_while_pattern(loop_form) {
|
|
|
|
|
|
// if let Some(inst) = lower_simple_while_to_joinir(loop_form, lowerer) {
|
|
|
|
|
|
// return Some(inst);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// ```
|
|
|
|
|
|
//
|
|
|
|
|
|
// Pattern 2: Loop with Conditional Break (medium complexity)
|
|
|
|
|
|
// ===========================================================
|
|
|
|
|
|
//
|
|
|
|
|
|
// ```rust
|
|
|
|
|
|
// use crate::mir::loop_pattern_detection::is_loop_with_break_pattern;
|
|
|
|
|
|
// use crate::mir::join_ir::lowering::loop_patterns::lower_loop_with_break_to_joinir;
|
|
|
|
|
|
//
|
|
|
|
|
|
// if is_loop_with_break_pattern(loop_form) {
|
|
|
|
|
|
// if let Some(inst) = lower_loop_with_break_to_joinir(loop_form, lowerer) {
|
|
|
|
|
|
// return Some(inst);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// ```
|
|
|
|
|
|
//
|
|
|
|
|
|
// Pattern 3: Loop with If-Else PHI (leverages existing If lowering)
|
|
|
|
|
|
// ==================================================================
|
|
|
|
|
|
//
|
|
|
|
|
|
// ```rust
|
|
|
|
|
|
// use crate::mir::loop_pattern_detection::is_loop_with_conditional_phi_pattern;
|
|
|
|
|
|
// use crate::mir::join_ir::lowering::loop_patterns::lower_loop_with_conditional_phi_to_joinir;
|
|
|
|
|
|
//
|
|
|
|
|
|
// if is_loop_with_conditional_phi_pattern(loop_form) {
|
|
|
|
|
|
// if let Some(inst) = lower_loop_with_conditional_phi_to_joinir(loop_form, lowerer) {
|
|
|
|
|
|
// return Some(inst);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// ```
|
|
|
|
|
|
//
|
|
|
|
|
|
// No Pattern Matched (fallback to existing lowering)
|
|
|
|
|
|
// ===================================================
|
|
|
|
|
|
//
|
|
|
|
|
|
// ```rust
|
|
|
|
|
|
// // No pattern matched, return None to trigger fallback
|
|
|
|
|
|
// None
|
|
|
|
|
|
// ```
|
|
|
|
|
|
|
|
|
|
|
|
// For now, return None (no pattern matched)
|
|
|
|
|
|
// This allows existing lowering to continue working
|
|
|
|
|
|
None
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 10:58:56 +09:00
|
|
|
|
#[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"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|