/*! * MIR Loop Builder - SSA形式でのループ構築専用モジュール * * Sealed/Unsealed blockとPhi nodeを使った正しいループ実装 * Based on Gemini's recommendation for proper SSA loop handling */ use super::{ MirInstruction, BasicBlockId, ValueId, ConstValue }; use crate::ast::ASTNode; use std::collections::HashMap; /// 不完全なPhi nodeの情報 #[derive(Debug, Clone)] struct IncompletePhi { /// Phi nodeの結果ValueId phi_id: ValueId, /// 変数名 var_name: String, /// 既知の入力値 (predecessor block id, value) known_inputs: Vec<(BasicBlockId, ValueId)>, } /// ループビルダー - SSA形式でのループ構築を管理 pub struct LoopBuilder<'a> { /// 親のMIRビルダーへの参照 parent_builder: &'a mut super::builder::MirBuilder, /// ループ内で追跡する変数の不完全Phi node incomplete_phis: HashMap>, /// ブロックごとの変数マップ(スコープ管理) #[allow(dead_code)] block_var_maps: HashMap>, } impl<'a> LoopBuilder<'a> { /// 新しいループビルダーを作成 pub fn new(parent: &'a mut super::builder::MirBuilder) -> Self { Self { parent_builder: parent, incomplete_phis: HashMap::new(), block_var_maps: HashMap::new(), } } /// SSA形式でループを構築 pub fn build_loop( &mut self, condition: ASTNode, body: Vec, ) -> Result { // 1. ブロックの準備 let preheader_id = self.current_block()?; let header_id = self.new_block(); let body_id = self.new_block(); let after_loop_id = self.new_block(); // 2. Preheader -> Header へのジャンプ self.emit_jump(header_id)?; let _ = self.add_predecessor(header_id, preheader_id); // 3. Headerブロックの準備(unsealed状態) self.set_current_block(header_id)?; let _ = self.mark_block_unsealed(header_id); // 4. ループ変数のPhi nodeを準備 // ここでは、ループ内で変更される可能性のある変数を事前に検出するか、 // または変数アクセス時に遅延生成する self.prepare_loop_variables(header_id, preheader_id)?; // 5. 条件評価(Phi nodeの結果を使用) let condition_value = self.build_expression_with_phis(condition)?; // 6. 条件分岐 self.emit_branch(condition_value, body_id, after_loop_id)?; let _ = self.add_predecessor(body_id, header_id); let _ = self.add_predecessor(after_loop_id, header_id); // 7. ループボディの構築 self.set_current_block(body_id)?; // Optional safepoint per loop-iteration if std::env::var("NYASH_BUILDER_SAFEPOINT_LOOP").ok().as_deref() == Some("1") { self.emit_safepoint()?; } // ボディをビルド for stmt in body { self.build_statement(stmt)?; } // latchブロックのスナップショットを保存(phi入力解決用) let latch_snapshot = self.get_current_variable_map(); self.block_var_maps.insert(body_id, latch_snapshot); // 8. Latchブロック(ボディの最後)からHeaderへ戻る let latch_id = self.current_block()?; self.emit_jump(header_id)?; let _ = self.add_predecessor(header_id, latch_id); // 9. Headerブロックをシール(全predecessors確定) self.seal_block(header_id, latch_id)?; // 10. ループ後の処理 self.set_current_block(after_loop_id)?; // void値を返す let void_dst = self.new_value(); self.emit_const(void_dst, ConstValue::Void)?; Ok(void_dst) } /// ループ変数の準備(事前検出または遅延生成) fn prepare_loop_variables( &mut self, header_id: BasicBlockId, preheader_id: BasicBlockId, ) -> Result<(), String> { // 現在の変数マップから、ループで使用される可能性のある変数を取得 let current_vars = self.get_current_variable_map(); // preheader時点のスナップショット(後でphi入力の解析に使う) self.block_var_maps.insert(preheader_id, current_vars.clone()); // 各変数に対して不完全なPhi nodeを作成 let mut incomplete_phis = Vec::new(); for (var_name, &value_before) in ¤t_vars { let phi_id = self.new_value(); // 不完全なPhi nodeを作成(preheaderからの値のみ設定) let incomplete_phi = IncompletePhi { phi_id, var_name: var_name.clone(), known_inputs: vec![(preheader_id, value_before)], }; incomplete_phis.push(incomplete_phi); // 変数マップを更新(Phi nodeの結果を使用) self.update_variable(var_name.clone(), phi_id); } // 不完全なPhi nodeを記録 self.incomplete_phis.insert(header_id, incomplete_phis); Ok(()) } /// ブロックをシールし、不完全なPhi nodeを完成させる fn seal_block( &mut self, block_id: BasicBlockId, latch_id: BasicBlockId, ) -> Result<(), String> { // 不完全なPhi nodeを取得 if let Some(incomplete_phis) = self.incomplete_phis.remove(&block_id) { for mut phi in incomplete_phis { // Latchブロックでの変数の値を取得 let value_after = self.get_variable_at_block(&phi.var_name, latch_id) .ok_or_else(|| format!("Variable {} not found at latch block", phi.var_name))?; // Phi nodeの入力を完成させる phi.known_inputs.push((latch_id, value_after)); // 完成したPhi nodeを発行 self.emit_phi_at_block_start(block_id, phi.phi_id, phi.known_inputs)?; // 重要: ループ外から参照される変数はPhi結果に束縛し直す self.update_variable(phi.var_name.clone(), phi.phi_id); } } // ブロックをシール済みとしてマーク self.mark_block_sealed(block_id)?; Ok(()) } // --- ヘルパーメソッド(親ビルダーへの委譲) --- fn current_block(&self) -> Result { self.parent_builder.current_block .ok_or_else(|| "No current block".to_string()) } fn new_block(&mut self) -> BasicBlockId { self.parent_builder.block_gen.next() } fn new_value(&mut self) -> ValueId { self.parent_builder.value_gen.next() } fn set_current_block(&mut self, block_id: BasicBlockId) -> Result<(), String> { self.parent_builder.start_new_block(block_id) } fn emit_jump(&mut self, target: BasicBlockId) -> Result<(), String> { self.parent_builder.emit_instruction(MirInstruction::Jump { target }) } fn emit_branch( &mut self, condition: ValueId, then_bb: BasicBlockId, else_bb: BasicBlockId, ) -> Result<(), String> { self.parent_builder.emit_instruction(MirInstruction::Branch { condition, then_bb, else_bb, }) } fn emit_safepoint(&mut self) -> Result<(), String> { self.parent_builder.emit_instruction(MirInstruction::Safepoint) } fn emit_const(&mut self, dst: ValueId, value: ConstValue) -> Result<(), String> { self.parent_builder.emit_instruction(MirInstruction::Const { dst, value }) } fn emit_phi_at_block_start( &mut self, block_id: BasicBlockId, dst: ValueId, inputs: Vec<(BasicBlockId, ValueId)>, ) -> Result<(), String> { // Phi nodeをブロックの先頭に挿入 if let Some(ref mut function) = self.parent_builder.current_function { if let Some(block) = function.get_block_mut(block_id) { // Phi命令は必ずブロックの先頭に配置 let phi_inst = MirInstruction::Phi { dst, inputs }; block.instructions.insert(0, phi_inst); Ok(()) } else { Err(format!("Block {} not found", block_id)) } } else { Err("No current function".to_string()) } } fn add_predecessor(&mut self, block: BasicBlockId, pred: BasicBlockId) -> Result<(), String> { if let Some(ref mut function) = self.parent_builder.current_function { if let Some(block) = function.get_block_mut(block) { block.add_predecessor(pred); Ok(()) } else { Err(format!("Block {} not found", block)) } } else { Err("No current function".to_string()) } } fn mark_block_unsealed(&mut self, _block_id: BasicBlockId) -> Result<(), String> { // ブロックはデフォルトでunsealedなので、特に何もしない // (既にBasicBlock::newでsealed: falseに初期化されている) Ok(()) } fn mark_block_sealed(&mut self, block_id: BasicBlockId) -> Result<(), String> { if let Some(ref mut function) = self.parent_builder.current_function { if let Some(block) = function.get_block_mut(block_id) { block.seal(); Ok(()) } else { Err(format!("Block {} not found", block_id)) } } else { Err("No current function".to_string()) } } fn get_current_variable_map(&self) -> HashMap { self.parent_builder.variable_map.clone() } fn update_variable(&mut self, name: String, value: ValueId) { self.parent_builder.variable_map.insert(name, value); } fn get_variable_at_block(&self, name: &str, block_id: BasicBlockId) -> Option { // まずブロックごとのスナップショットを優先 if let Some(map) = self.block_var_maps.get(&block_id) { if let Some(v) = map.get(name) { return Some(*v); } } // フォールバック:現在の変数マップ(単純ケース用) self.parent_builder.variable_map.get(name).copied() } fn build_expression_with_phis(&mut self, expr: ASTNode) -> Result { // Phi nodeの結果を考慮しながら式を構築 self.parent_builder.build_expression(expr) } fn build_statement(&mut self, stmt: ASTNode) -> Result { self.parent_builder.build_expression(stmt) } }