diff --git a/src/mir/join_ir/frontend/ast_lowerer.rs b/src/mir/join_ir/frontend/ast_lowerer.rs index 2ef2ab6f..e19f852e 100644 --- a/src/mir/join_ir/frontend/ast_lowerer.rs +++ b/src/mir/join_ir/frontend/ast_lowerer.rs @@ -20,7 +20,7 @@ //! - **A/B テスト可能**: 既存経路と新経路の両方で実行して比較検証 use crate::mir::join_ir::{ConstValue, JoinFunction, JoinFuncId, JoinInst, JoinModule, VarId}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; /// Phase 34-5: 式から値を抽出する際のコンテキスト /// @@ -334,7 +334,24 @@ impl AstToJoinIrLowerer { /// - k_exit: 結果を return /// /// Phase 34-7.4b: Local ノード処理(同名再宣言 = 再代入) + /// ループ本体lowering(Phase 34実装) + /// + /// # Phase 40拡張予定 + /// + /// この関数に以下を追加: + /// 1. `extract_if_in_loop_modified_vars()`呼び出し + /// 2. 検出された変数をloop exit PHI生成に使用 + /// + /// ```rust,ignore + /// // TODO(Phase 40-1): Add if-in-loop variable tracking + /// // let loop_vars = self.get_loop_carried_vars(&loop_ctx); + /// // let modified_in_if = self.extract_if_in_loop_modified_vars(&loop_body, &loop_vars); + /// // Pass modified_in_if to create_exit_function() for PHI generation + /// ``` fn lower_loop_case_a_simple(&mut self, program_json: &serde_json::Value) -> JoinModule { + // TODO(Phase 40-1): Add if-in-loop variable tracking here + // Integration point for extract_if_in_loop_modified_vars() + // 1. Program(JSON) から defs を取得 let defs = program_json["defs"] .as_array() @@ -1228,6 +1245,166 @@ impl AstToJoinIrLowerer { _ => panic!("Unsupported expr type: {}", expr_type), } } + + // ======================================== + // Phase 40拡張予定: If-in-loop AST Lowering + // ======================================== + + /// Phase 40-1で実装予定: ループ内if文の変数追跡 + /// + /// # Purpose + /// + /// array_ext.filter等のif-in-loopパターンで、ループ内で修正される変数を + /// 追跡し、ループ出口PHI生成に使用する。 + /// + /// # Implementation Plan (Phase 40-1) + /// + /// ## Input + /// - `loop_body`: ループ本体AST(JSON v0形式) + /// - `loop_vars`: ループで使用される変数(Header PHIで定義) + /// + /// ## Output + /// - `HashSet`: if分岐内で修正された変数名セット + /// + /// ## Logic + /// 1. Recursive AST walk (helper: `extract_assigned_vars_from_body`) + /// 2. Detect assignments in if branches only + /// 3. Filter for variables in `loop_vars` (loop-carried variables) + /// 4. Return set of modified variable names + /// + /// ## Integration Point + /// - Call from: `lower_loop_case_a_simple()` or similar loop lowering + /// - Use output for: Loop exit PHI generation in `create_exit_function()` + /// + /// # Example + /// + /// ```nyash,ignore + /// local out = new ArrayBox() // loop_vars = {out, i} + /// local i = 0 + /// loop(i < n) { + /// if fn(arr[i]) { // ← この中の代入を検出 + /// out.push(arr[i]) // ← out修正検出 + /// } + /// i = i + 1 + /// } + /// // Result: extract_if_in_loop_modified_vars() = {out} + /// // → Loop exit PHI: phi out_exit = (out_header, out_loop_modified) + /// ``` + /// + /// # Replaces (Phase 40-1削除対象) + /// + /// - `if_phi::collect_assigned_vars()` (32 lines) + /// - Current callsites: loop_builder.rs:1069, 1075 + /// - この関数実装でcallsites削除可能 + /// + /// # See Also + /// + /// - Design: `docs/.../phase-39-if-phi-level2/joinir_extension_design.md` + /// - A/B test: array_ext.filter (Primary representative function) + /// + /// # TODO(Phase 40-1) + /// + /// ```rust,ignore + /// fn extract_if_in_loop_modified_vars( + /// &mut self, + /// loop_body: &serde_json::Value, + /// loop_vars: &HashSet, + /// ) -> HashSet { + /// // Step 1: Recursive AST walk + /// let all_assigned = self.extract_assigned_vars_from_body(loop_body); + /// + /// // Step 2: Filter for if-statement assignments only + /// let if_assigned = all_assigned.iter() + /// .filter(|var| self.is_assigned_in_if_branch(loop_body, var)) + /// .cloned() + /// .collect::>(); + /// + /// // Step 3: Filter for loop-carried variables + /// if_assigned.intersection(loop_vars).cloned().collect() + /// } + /// ``` + #[allow(dead_code)] + fn extract_if_in_loop_modified_vars( + &mut self, + _loop_body: &serde_json::Value, + _loop_vars: &HashSet, + ) -> HashSet { + // TODO(Phase 40-1): Implement if-in-loop variable tracking + // See: docs/.../phase-39-if-phi-level2/joinir_extension_design.md + unimplemented!("Phase 40-1: If-in-loop variable tracking for array_ext.filter") + } + + /// Phase 40-1で実装予定: 再帰的AST走査(代入検出) + /// + /// # Purpose + /// + /// AST bodyを再帰的に走査し、代入文を検出する。 + /// + /// # Implementation Plan + /// + /// ## Recursive Descent + /// - Handle: "Local" assignments (`local x = ...` or `x = ...`) + /// - Handle: Nested blocks (`{ ... }`) + /// - Handle: If/Loop bodies (recursive call) + /// + /// ## Return + /// - `HashSet`: 代入された変数名全て + /// + /// # Example + /// + /// ```json + /// { + /// "type": "Block", + /// "body": [ + /// {"type": "Local", "name": "x", "expr": ...}, // x assigned + /// {"type": "If", "cond": ..., "then": [ + /// {"type": "Local", "name": "y", "expr": ...} // y assigned + /// ]} + /// ] + /// } + /// ``` + /// Result: {x, y} + /// + /// # TODO(Phase 40-1) + /// + /// ```rust,ignore + /// fn extract_assigned_vars_from_body( + /// &mut self, + /// body: &serde_json::Value, + /// ) -> HashSet { + /// let mut assigned = HashSet::new(); + /// + /// if let Some(stmts) = body.get("body").and_then(|b| b.as_array()) { + /// for stmt in stmts { + /// match stmt.get("type").and_then(|t| t.as_str()) { + /// Some("Local") => { + /// if let Some(name) = stmt.get("name").and_then(|n| n.as_str()) { + /// assigned.insert(name.to_string()); + /// } + /// } + /// Some("If") => { + /// // Recursive: then/else branches + /// if let Some(then_body) = stmt.get("then") { + /// assigned.extend(self.extract_assigned_vars_from_body(then_body)); + /// } + /// } + /// // ... other cases ... + /// _ => {} + /// } + /// } + /// } + /// + /// assigned + /// } + /// ``` + #[allow(dead_code)] + fn extract_assigned_vars_from_body( + &mut self, + _body: &serde_json::Value, + ) -> HashSet { + // TODO(Phase 40-1): Implement recursive AST assignment detection + unimplemented!("Phase 40-1: Recursive AST assignment detection") + } } impl Default for AstToJoinIrLowerer { diff --git a/src/mir/join_ir_vm_bridge.rs b/src/mir/join_ir_vm_bridge.rs index e718c376..02ad98a4 100644 --- a/src/mir/join_ir_vm_bridge.rs +++ b/src/mir/join_ir_vm_bridge.rs @@ -166,9 +166,112 @@ pub(crate) fn convert_joinir_to_mir(join_module: &JoinModule) -> Result`追加 +/// 2. AST lowering時に`extract_if_in_loop_modified_vars()`結果をmetadataに格納 +/// 3. MIR lowering時にmetadataから読み取り、loop exit PHI生成 +/// +/// ### Code Location +/// +/// この関数内で以下を追加: +/// +/// ```rust,ignore +/// // TODO(Phase 40-1): Generate loop exit PHI for if-in-loop modified variables +/// if let Some(modified_vars) = join_func.metadata.get("if_in_loop_modified_vars") { +/// for var_name in modified_vars.as_array().unwrap() { +/// let var_name_str = var_name.as_str().unwrap(); +/// +/// // Get header value (loop entry) +/// let header_value = self.get_var_value_at_header(var_name_str); +/// +/// // Get exit value (loop body last modification) +/// let exit_value = self.get_var_value_at_exit(var_name_str); +/// +/// // Emit PHI at loop exit block +/// self.emit_phi( +/// exit_block_id, +/// var_name_str, +/// vec![header_value, exit_value], +/// ); +/// } +/// } +/// ``` +/// +/// ### Example (array_ext.filter) +/// +/// ```nyash,ignore +/// // Input AST +/// local out = new ArrayBox() +/// local i = 0 +/// loop(i < arr.len()) { +/// if fn(arr[i]) { out.push(arr[i]) } // out modified in if +/// i = i + 1 +/// } +/// return out +/// +/// // JoinIR (Phase 40) +/// entry(): +/// out_init = new ArrayBox +/// i_init = 0 +/// call loop_step(i_init, out_init, arr) +/// +/// loop_step(i, out, arr): +/// exit_cond = i >= arr.len() +/// jump k_exit(out) if exit_cond // ← out needs PHI at k_exit +/// elem = arr[i] +/// should_push = fn(elem) +/// out_next = select(should_push, out.push(elem), out) // conditional modification +/// i_next = i + 1 +/// call loop_step(i_next, out_next, arr) +/// +/// k_exit(out_final): +/// ret out_final +/// +/// // MIR (Phase 40) +/// // At loop exit block: +/// %out_exit = phi [%out_init, entry], [%out_next, loop_step] // ← Phase 40で生成 +/// ``` +/// +/// # See Also +/// +/// - AST lowering: `ast_lowerer.rs::extract_if_in_loop_modified_vars()` +/// - Design: `docs/.../phase-39-if-phi-level2/joinir_extension_design.md` fn convert_join_function_to_mir( join_func: &crate::mir::join_ir::JoinFunction, ) -> Result { + // TODO(Phase 40-1): Generate loop exit PHI for if-in-loop modified variables + // See comment above for implementation details + // Integration point: After loop body lowering, before exit block finalization + // Phase 27-shortterm S-4.4: skip_ws パターン対応版 // - Call (tail call): MIR Call に変換 // - Jump (conditional exit): Branch + Return に変換