feat(joinir): Add Phase 40 implementation templates and integration points
Phase 35-39整理(C): JoinIR Frontend拡張雛形作成 - ast_lowerer.rs: extract_if_in_loop_modified_vars() template (~80 lines) - ast_lowerer.rs: extract_assigned_vars_from_body() template (~80 lines) - ast_lowerer.rs: lower_loop_case_a_simple() integration point marked - join_ir_vm_bridge.rs: convert_join_function_to_mir() extension template (~100 lines) Templates include: - Detailed purpose and implementation plan - Integration points in existing code - Example usage (array_ext.filter) - Links to Phase 39 design docs - TODO(Phase 40-1/2/3/4) markers Effect: Phase 40 implementation ready to start (追加箇所明確、実装漏れ防止) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -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<String>`: 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<String>,
|
||||
/// ) -> HashSet<String> {
|
||||
/// // 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::<HashSet<_>>();
|
||||
///
|
||||
/// // 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<String>,
|
||||
) -> HashSet<String> {
|
||||
// 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<String>`: 代入された変数名全て
|
||||
///
|
||||
/// # 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<String> {
|
||||
/// 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<String> {
|
||||
// TODO(Phase 40-1): Implement recursive AST assignment detection
|
||||
unimplemented!("Phase 40-1: Recursive AST assignment detection")
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AstToJoinIrLowerer {
|
||||
|
||||
@ -166,9 +166,112 @@ pub(crate) fn convert_joinir_to_mir(join_module: &JoinModule) -> Result<MirModul
|
||||
}
|
||||
|
||||
/// JoinFunction → MirFunction 変換
|
||||
///
|
||||
/// # Phase 40拡張予定: Loop Exit PHI for If-in-loop
|
||||
///
|
||||
/// ## Current Implementation (Phase 34)
|
||||
///
|
||||
/// - Header PHI: ループ開始時の変数(ループ不変変数含む)
|
||||
/// - Exit PHI: ループ終了時の変数(単純パターンのみ)
|
||||
///
|
||||
/// ## Phase 40 Extension Required
|
||||
///
|
||||
/// ### Problem
|
||||
///
|
||||
/// 現在、if-in-loopで修正される変数のloop exit PHIが生成されない。
|
||||
///
|
||||
/// ```nyash,ignore
|
||||
/// local out = new ArrayBox()
|
||||
/// loop(i < n) {
|
||||
/// if fn(arr[i]) { out.push(arr[i]) } // ← out修正
|
||||
/// i = i + 1
|
||||
/// }
|
||||
/// // Missing: phi out_exit = (out_header, out_if_modified)
|
||||
/// ```
|
||||
///
|
||||
/// ### Solution (Phase 40-1)
|
||||
///
|
||||
/// JoinIR Frontend AST loweringで検出したif-in-loop修正変数を
|
||||
/// JoinModule metadataに格納し、MIR loweringで読み取る。
|
||||
///
|
||||
/// ### Implementation Plan
|
||||
///
|
||||
/// 1. JoinModule metadataに`if_in_loop_modified_vars: HashSet<String>`追加
|
||||
/// 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<MirFunction, JoinIrVmBridgeError> {
|
||||
// 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 に変換
|
||||
|
||||
Reference in New Issue
Block a user