//! Phase 27.14: FuncScannerBox._append_defs loop の JoinIR lowering //! //! 目的: FuncScanner の最も簡単な配列結合ループを JoinIR に変換 //! //! ## 対象ループ //! - ファイル: `lang/src/compiler/entry/func_scanner.hako` //! - 関数: `FuncScannerBox._append_defs(dst, defs_box)` //! - 行数: 293-300 //! //! ## ループ構造 //! ```hako //! method _append_defs(dst, defs_box) { //! if defs_box == null { return } //! local i = 0 //! loop(i < defs_box.length()) { //! dst.push(defs_box.get(i)) //! i = i + 1 //! } //! } //! ``` //! //! ## LoopForm ケース: Case A (動的条件 `i < defs_box.length()`) //! //! ## Pinned / Carrier / Exit //! - **Pinned**: `dst` (ArrayBox), `defs_box` (ArrayBox), `n` (Integer = defs_box.length()) //! - **Carrier**: `i` (Integer) //! - **Exit**: none (void return, dst は破壊的変更) //! //! ## 想定 JoinIR 構造 //! ```text //! fn append_defs_entry(dst, defs_box, n) -> void { //! let i_init = 0; //! loop_step(dst, defs_box, n, i_init) //! } //! //! fn loop_step(dst, defs_box, n, i) -> void { //! if i >= n { return } //! let item = defs_box.get(i) //! dst.push(item) //! let next_i = i + 1 //! loop_step(dst, defs_box, n, next_i) //! } //! ``` use crate::mir::join_ir::lowering::common::{ dispatch_lowering, ensure_entry_has_succs, has_array_method, has_const_int, has_loop_increment, log_fallback, }; use crate::mir::join_ir::lowering::value_id_ranges::funcscanner_append_defs as vid; use crate::mir::join_ir::JoinModule; use crate::mir::loop_form::LoopForm; use crate::mir::query::{MirQuery, MirQueryBox}; /// Phase 27.14: FuncScannerBox._append_defs の JoinIR lowering(public dispatcher) /// /// 環境変数 `NYASH_JOINIR_LOWER_FROM_MIR=1` に応じて、 /// MIR-based 版または handwritten 版を選択する。 /// /// ## トグル制御: /// - **OFF (デフォルト)**: `lower_handwritten()` を使用 /// - **ON**: `lower_from_mir()` を使用 /// /// ## Shared Builder Pattern /// 両方の実装が `build_funcscanner_append_defs_joinir()` を呼び出す共通パターン。 pub fn lower_funcscanner_append_defs_to_joinir( module: &crate::mir::MirModule, ) -> Option { dispatch_lowering( "funcscanner_append_defs", module, lower_from_mir, lower_handwritten, ) } /// Phase 27.14: Common JoinIR builder for FuncScannerBox._append_defs /// /// This function generates the JoinIR for the append_defs loop, shared by both: /// - lower_handwritten (always uses this) /// - lower_from_mir (uses this after CFG sanity checks pass) /// /// ## 簡略化方針 /// Phase 27.14 の最小実装として、最も単純な JoinIR を生成する: /// - ArrayBox.length() → dst.push(item) の基本パターン /// - null チェックは省略(MIR 側で既に処理済み前提) fn build_funcscanner_append_defs_joinir(module: &crate::mir::MirModule) -> Option { use crate::mir::join_ir::*; // Phase 27.14: ターゲット関数が存在するかチェック let _target_func = module.functions.get("FuncScannerBox._append_defs/2")?; eprintln!("[joinir/funcscanner_append_defs/build] Phase 27.14 implementation"); eprintln!("[joinir/funcscanner_append_defs/build] Generating JoinIR for _append_defs loop"); eprintln!("[joinir/funcscanner_append_defs/build] Using ValueId range: 9000-10999 (via value_id_ranges)"); // Step 1: JoinModule を構築 let mut join_module = JoinModule::new(); // append_defs_entry 関数(entry): // fn append_defs_entry(dst, defs_box, n) -> void { // let i_init = 0; // loop_step(dst, defs_box, n, i_init) // } let entry_id = JoinFuncId::new(0); let dst_param = vid::entry(0); // 9000 let defs_box_param = vid::entry(1); // 9001 let n_param = vid::entry(2); // 9002 let mut entry_func = JoinFunction::new( entry_id, "append_defs_entry".to_string(), vec![dst_param, defs_box_param, n_param], ); let i_init = vid::entry(10); // 9010 // i_init = 0 entry_func.body.push(JoinInst::Compute(MirLikeInst::Const { dst: i_init, value: ConstValue::Integer(0), })); // loop_step(dst, defs_box, n, i_init) let loop_step_id = JoinFuncId::new(1); entry_func.body.push(JoinInst::Call { func: loop_step_id, args: vec![dst_param, defs_box_param, n_param, i_init], k_next: None, dst: None, }); join_module.entry = Some(entry_id); join_module.add_function(entry_func); // Phase 27.14: loop_step の Pinned/Carrier 構造を明示 // FuncScanner _append_defs ループの場合: // - Pinned: dst (ArrayBox), defs_box (ArrayBox), n (Integer) // - Carrier: i (Integer) // - Exit: none (void return) let dst_loop = vid::loop_step(0); // 10000 - Pinned let defs_box_loop = vid::loop_step(1); // 10001 - Pinned let n_loop = vid::loop_step(2); // 10002 - Pinned let i_loop = vid::loop_step(3); // 10003 - Carrier let _header_shape = LoopHeaderShape::new_manual( vec![dst_loop, defs_box_loop, n_loop], // Pinned vec![i_loop], // Carrier ); // loop_step 関数: // fn loop_step(dst, defs_box, n, i) -> void { // if i >= n { return } // let item = defs_box.get(i) // dst.push(item) // let next_i = i + 1 // loop_step(dst, defs_box, n, next_i) // } let mut loop_step_func = JoinFunction::new( loop_step_id, "loop_step".to_string(), vec![dst_loop, defs_box_loop, n_loop, i_loop], ); let cmp_result = vid::loop_step(10); // 10010 let item_value = vid::loop_step(11); // 10011 let next_i = vid::loop_step(12); // 10012 let const_1 = vid::loop_step(13); // 10013 // cmp_result = (i >= n) loop_step_func .body .push(JoinInst::Compute(MirLikeInst::Compare { dst: cmp_result, op: CompareOp::Ge, lhs: i_loop, rhs: n_loop, })); // Phase 27.14: Exit φ の意味を LoopExitShape で明示 // FuncScanner _append_defs ループ脱出時は void 返却(dst は破壊的変更済み) let _exit_shape = LoopExitShape::new_manual(vec![]); // exit_args = [] (void) // if i >= n { return } (void) loop_step_func.body.push(JoinInst::Jump { cont: JoinContId::new(0), args: vec![], // ← LoopExitShape.exit_args に対応 (void) cond: Some(cmp_result), }); // item = defs_box.get(i) loop_step_func .body .push(JoinInst::Compute(MirLikeInst::BoxCall { dst: Some(item_value), box_name: "ArrayBox".to_string(), method: "get".to_string(), args: vec![defs_box_loop, i_loop], })); // dst.push(item) - 破壊的変更(戻り値なし) loop_step_func .body .push(JoinInst::Compute(MirLikeInst::BoxCall { dst: None, // push は戻り値なし box_name: "ArrayBox".to_string(), method: "push".to_string(), args: vec![dst_loop, item_value], })); // const_1 = 1 loop_step_func .body .push(JoinInst::Compute(MirLikeInst::Const { dst: const_1, value: ConstValue::Integer(1), })); // next_i = i + 1 loop_step_func .body .push(JoinInst::Compute(MirLikeInst::BinOp { dst: next_i, op: BinOpKind::Add, lhs: i_loop, rhs: const_1, })); // loop_step(dst, defs_box, n, next_i) - tail recursion loop_step_func.body.push(JoinInst::Call { func: loop_step_id, args: vec![dst_loop, defs_box_loop, n_loop, next_i], k_next: None, dst: None, }); join_module.add_function(loop_step_func); eprintln!("[joinir/funcscanner_append_defs/build] ✅ JoinIR construction completed"); eprintln!( "[joinir/funcscanner_append_defs/build] Functions: {}", join_module.functions.len() ); Some(join_module) } /// Phase 27.14: MIR-based lowering for FuncScannerBox._append_defs /// /// CFG sanity checks + MIR パターンマッチング → 成功なら `build_funcscanner_append_defs_joinir()` 呼び出し /// /// ## CFG Sanity Checks (軽量パターンマッチ): /// 1. Entry block に後続がある /// 2. Entry block 付近に以下の命令がある: /// - `Const { value: Integer(0) }` (初期 i = 0) /// - `BoxCall { box_name: "ArrayBox", method: "length" }` (n = defs_box.length()) /// 3. ループ本体付近に: /// - `BoxCall { box_name: "ArrayBox", method: "get" }` (defs_box.get(i)) /// - `BoxCall { box_name: "ArrayBox", method: "push" }` (dst.push(item)) /// - `BinOp { op: Add }` (next_i = i + 1) /// /// ## Graceful Degradation /// 上記パターンが検出できない場合は `log_fallback()` → `lower_handwritten()` に戻る。 fn lower_from_mir(module: &crate::mir::MirModule) -> Option { eprintln!("[joinir/funcscanner_append_defs/mir] Starting MIR-based lowering"); // Step 1: FuncScannerBox._append_defs/2 を探す let target_func = module.functions.get("FuncScannerBox._append_defs/2")?; eprintln!("[joinir/funcscanner_append_defs/mir] Found FuncScannerBox._append_defs/2"); eprintln!( "[joinir/funcscanner_append_defs/mir] MIR blocks: {}", target_func.blocks.len() ); // Step 2: MirQueryBox を作成 let query = MirQueryBox::new(target_func); let entry = target_func.entry_block; // CFG Check 1: Entry block has successors if !ensure_entry_has_succs(&query, entry) { log_fallback("funcscanner_append_defs", "entry block has no successors"); return lower_handwritten(module); } // CFG Check 2: Entry block contains expected patterns // Pattern 1: i = 0 (初期化) if !has_const_int(&query, entry, 0) { log_fallback( "funcscanner_append_defs", "Const(0) not found in entry block", ); return lower_handwritten(module); } // Pattern 2: defs_box.length() の検出 // Check entry block and its immediate successors for length() call let has_length_call = has_array_method(&query, entry, "length") || query .succs(entry) .iter() .any(|&succ| has_array_method(&query, succ, "length")); if !has_length_call { log_fallback( "funcscanner_append_defs", "ArrayBox.length() not found in entry or successors", ); return lower_handwritten(module); } // Pattern 3: ループ本体での配列操作検出 // Check all blocks for array operations (get/push) and loop increment let all_blocks: Vec<_> = target_func.blocks.keys().copied().collect(); let has_get_call = all_blocks .iter() .any(|&bb| has_array_method(&query, bb, "get")); if !has_get_call { log_fallback( "funcscanner_append_defs", "ArrayBox.get() not found in function body", ); return lower_handwritten(module); } let has_push_call = all_blocks .iter() .any(|&bb| has_array_method(&query, bb, "push")); if !has_push_call { log_fallback( "funcscanner_append_defs", "ArrayBox.push() not found in function body", ); return lower_handwritten(module); } let has_increment = all_blocks.iter().any(|&bb| has_loop_increment(&query, bb)); if !has_increment { log_fallback( "funcscanner_append_defs", "loop increment (i + 1) not found in function body", ); return lower_handwritten(module); } eprintln!("[joinir/funcscanner_append_defs/mir] CFG sanity checks passed ✅"); eprintln!("[joinir/funcscanner_append_defs/mir] Found: length(), get(), push(), i+1"); // Phase 31: LoopToJoinLowerer 統一箱経由に移行 if crate::mir::join_ir::env_flag_is_1("NYASH_JOINIR_LOWER_GENERIC") { use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer; let header = query.succs(entry).get(0).copied().unwrap_or(entry); let succs_header = query.succs(header); let body = succs_header.get(0).copied().unwrap_or(header); let exit = succs_header.get(1).copied().unwrap_or(header); let loop_form = LoopForm { preheader: entry, header, body, latch: body, exit, continue_targets: vec![body], break_targets: vec![exit], }; if crate::mir::join_ir::lowering::common::case_a::is_simple_case_a_loop(&loop_form) { eprintln!( "[joinir/funcscanner_append_defs/generic-hook] detected simple Case A loop (LoopToJoinLowerer)" ); let lowerer = LoopToJoinLowerer::new(); if let Some(jm) = lowerer.lower_case_a_for_append_defs(target_func, &loop_form) { eprintln!( "[joinir/funcscanner_append_defs/generic-hook] LoopToJoinLowerer produced JoinIR, returning early" ); return Some(jm); } eprintln!( "[joinir/funcscanner_append_defs/generic-hook] LoopToJoinLowerer returned None, falling back to handwritten/MIR path" ); } } // Phase 27.14: Generate JoinIR using shared builder // CFG checks passed, so we can use build_funcscanner_append_defs_joinir() directly eprintln!("[joinir/funcscanner_append_defs/mir] Calling build_funcscanner_append_defs_joinir() after CFG validation"); build_funcscanner_append_defs_joinir(module) } /// Phase 27.14: Handwritten lowering wrapper for FuncScannerBox._append_defs /// /// This is a thin wrapper that calls the shared build_funcscanner_append_defs_joinir() function. /// Maintains the handwritten lowering path as the baseline reference. fn lower_handwritten(module: &crate::mir::MirModule) -> Option { eprintln!("[joinir/funcscanner_append_defs/handwritten] Using handwritten lowering path"); build_funcscanner_append_defs_joinir(module) }