diff --git a/docs/private b/docs/private index 80b08dc5..f224c849 160000 --- a/docs/private +++ b/docs/private @@ -1 +1 @@ -Subproject commit 80b08dc5f88359f129bb31b5f91eeabebb22c54f +Subproject commit f224c8497020f2b8d6067e7d5d2e30548d5fe5b8 diff --git a/src/mir/join_ir/lowering/if_merge.rs b/src/mir/join_ir/lowering/if_merge.rs index 10eb1312..f1698441 100644 --- a/src/mir/join_ir/lowering/if_merge.rs +++ b/src/mir/join_ir/lowering/if_merge.rs @@ -5,6 +5,14 @@ //! Phase 33-7 制約: //! - return パターンのみ(continuation は Phase 33-8) //! - k_next=None のみ +//! +//! ## 責務分離(Phase 33-9.1) +//! +//! **IfMergeLowerer の責務**: +//! - 複数変数を持つ if/else を IfMerge 命令に変換する +//! +//! **非責務**: +//! - Loop の PHI には触らない(Loop lowering の責務) use crate::mir::join_ir::{JoinInst, MergePair}; use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; diff --git a/src/mir/join_ir/lowering/if_select.rs b/src/mir/join_ir/lowering/if_select.rs index ae1e6981..ec04b93d 100644 --- a/src/mir/join_ir/lowering/if_select.rs +++ b/src/mir/join_ir/lowering/if_select.rs @@ -1,6 +1,14 @@ //! Phase 33: If/Else の Select 命令への lowering //! //! 最小の if/else(副作用なし、単純な値選択)を JoinInst::Select に変換する。 +//! +//! ## 責務分離(Phase 33-9.1) +//! +//! **IfSelectLowerer の責務**: +//! - 単純 if/else(副作用なし、単一変数)を Select 命令に変換する +//! +//! **非責務**: +//! - Loop の PHI には触らない(Loop lowering の責務) use crate::mir::join_ir::JoinInst; use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; diff --git a/src/mir/join_ir/lowering/loop_to_join.rs b/src/mir/join_ir/lowering/loop_to_join.rs index 2c05c0e2..36569428 100644 --- a/src/mir/join_ir/lowering/loop_to_join.rs +++ b/src/mir/join_ir/lowering/loop_to_join.rs @@ -8,6 +8,16 @@ //! - **パターン自動判定**: LoopScopeShape を解析して適切な変換を選択 //! - **既存コード再利用**: generic_case_a の `_with_scope` 関数を内部で呼び出し //! +//! ## 責務分離(Phase 33-9.1) +//! +//! **LoopToJoinLowerer の責務**: +//! - LoopForm / LoopScopeShape を入力に、「ループだけ」を JoinIR (loop_step/k_exit) に正規化する +//! - Loop PHI を関数引数に変換する +//! +//! **非責務**: +//! - if/else の PHI には触らない(If lowering の責務) +//! - If の Select/IfMerge などは別ロワー(if_select.rs / if_merge.rs)の責務 +//! //! ## 使用例 //! //! ```ignore diff --git a/src/mir/join_ir/lowering/mod.rs b/src/mir/join_ir/lowering/mod.rs index 17dd2f98..ae88f071 100644 --- a/src/mir/join_ir/lowering/mod.rs +++ b/src/mir/join_ir/lowering/mod.rs @@ -47,6 +47,34 @@ pub use stageb_funcscanner::lower_stageb_funcscanner_to_joinir; use crate::mir::join_ir::JoinInst; use crate::mir::{BasicBlockId, MirFunction}; +/// Phase 33-9.1: Loop lowering対象関数の判定 +/// +/// これらの関数は Phase 32/33 で LoopToJoinLowerer によって処理されます。 +/// If lowering (Select/IfMerge) の対象から除外することで、Loop/If の責務を明確に分離します。 +/// +/// ## 対象関数(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 { + const LOOP_LOWERED_FUNCTIONS: &[&str] = &[ + "Main.skip/1", + "FuncScannerBox.trim/1", + "FuncScannerBox.append_defs/2", + "Stage1UsingResolverBox.resolve_for_source/5", + "StageBBodyExtractorBox.build_body_src/2", + "StageBFuncScannerBox.scan_all_boxes/1", + ]; + + LOOP_LOWERED_FUNCTIONS.contains(&name) +} + /// Phase 33-7: Try to lower if/else to JoinIR Select/IfMerge instruction /// /// Scope: @@ -73,6 +101,13 @@ pub fn try_lower_if_to_joinir( return None; } + // 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; @@ -148,3 +183,40 @@ pub fn try_lower_if_to_joinir( result } + +#[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")); + } +}