feat(joinir): Phase 61-4-F ToplevelOps and production path integration
Phase 61-4-F: Loop-outside If JoinIR production path Changes: - F.1: Add ToplevelOps struct implementing PhiBuilderOps for MirBuilder - Enables emit_toplevel_phis() to emit PHI instructions via MirBuilder - Uses insert_phi_at_head_spanned for proper PHI placement - ~70 lines, thin wrapper following box theory - F.2: Integrate production path with emit_toplevel_phis - Replace TODO with actual PHI emission call - Build IfShape from branch blocks - Log PHI count on dry-run - Add IfToplevelTest.* to try_lower_if_to_joinir allowed list - Fixes function name guard that blocked testing Note: Pattern matching currently only supports return patterns (IfMerge/IfSelect). Local variable assignment patterns fall back to existing PHI generation, which correctly produces valid MIR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -1,6 +1,79 @@
|
||||
use super::{MirBuilder, ValueId};
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::control_form::IfShape;
|
||||
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
|
||||
use crate::mir::phi_core::phi_builder_box::PhiBuilderOps;
|
||||
use crate::mir::{BasicBlockId, ConstValue, MirInstruction};
|
||||
|
||||
/// Phase 61-4-F: MirBuilder 用 PhiBuilderOps 実装
|
||||
///
|
||||
/// ループ外 if の JoinIR 経路で emit_toplevel_phis() を呼ぶためのラッパー。
|
||||
struct ToplevelOps<'a>(&'a mut MirBuilder);
|
||||
|
||||
impl<'a> PhiBuilderOps for ToplevelOps<'a> {
|
||||
fn new_value(&mut self) -> ValueId {
|
||||
self.0.next_value_id()
|
||||
}
|
||||
|
||||
fn emit_phi(
|
||||
&mut self,
|
||||
block: BasicBlockId,
|
||||
dst: ValueId,
|
||||
inputs: Vec<(BasicBlockId, ValueId)>,
|
||||
) -> Result<(), String> {
|
||||
// merge ブロックの先頭に PHI を挿入
|
||||
if let (Some(func), Some(_cur_bb)) = (self.0.current_function.as_mut(), self.0.current_block)
|
||||
{
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
func,
|
||||
block,
|
||||
dst,
|
||||
inputs,
|
||||
self.0.current_span,
|
||||
);
|
||||
} else {
|
||||
self.0.emit_instruction(MirInstruction::Phi { dst, inputs })?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_var(&mut self, name: String, value: ValueId) {
|
||||
self.0.variable_map.insert(name, value);
|
||||
}
|
||||
|
||||
fn get_block_predecessors(&self, block: BasicBlockId) -> Vec<BasicBlockId> {
|
||||
if let Some(ref func) = self.0.current_function {
|
||||
func.blocks
|
||||
.get(&block)
|
||||
.map(|bb| bb.predecessors.iter().copied().collect())
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_void(&mut self) -> ValueId {
|
||||
let void_id = self.0.next_value_id();
|
||||
let _ = self.0.emit_instruction(MirInstruction::Const {
|
||||
dst: void_id,
|
||||
value: ConstValue::Void,
|
||||
});
|
||||
void_id
|
||||
}
|
||||
|
||||
fn set_current_block(&mut self, block: BasicBlockId) -> Result<(), String> {
|
||||
self.0.current_block = Some(block);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn block_exists(&self, block: BasicBlockId) -> bool {
|
||||
if let Some(ref func) = self.0.current_function {
|
||||
func.blocks.contains_key(&block)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MirBuilder {
|
||||
/// Lower an if/else using a structured IfForm (header→then/else→merge).
|
||||
@ -178,15 +251,37 @@ impl MirBuilder {
|
||||
);
|
||||
}
|
||||
|
||||
// 本番経路が有効な場合のみ success = true
|
||||
// Phase 61-4-F: 本番経路 - emit_toplevel_phis でPHI生成
|
||||
if joinir_toplevel {
|
||||
joinir_success = true;
|
||||
// TODO: Phase 61-4-E 本番経路のPHI生成
|
||||
// 現時点では dry-run 的動作(フォールバック経路を使用)
|
||||
// IfShape 構築
|
||||
let if_shape = IfShape {
|
||||
cond_block: pre_branch_bb,
|
||||
then_block,
|
||||
else_block: Some(else_block),
|
||||
merge_block,
|
||||
};
|
||||
|
||||
// PHI 生成
|
||||
let phi_count = {
|
||||
let mut ops = ToplevelOps(self);
|
||||
crate::mir::loop_builder::IfInLoopPhiEmitter::emit_toplevel_phis(
|
||||
&phi_spec,
|
||||
&pre_if_var_map,
|
||||
&then_var_map_end,
|
||||
else_var_map_end_opt.as_ref(),
|
||||
&mut ops,
|
||||
&if_shape,
|
||||
)?
|
||||
};
|
||||
|
||||
if joinir_dryrun {
|
||||
eprintln!("[Phase 61-4] ⚠️ Production path not yet implemented, using fallback");
|
||||
eprintln!(
|
||||
"[Phase 61-4] ✅ Production path: {} PHIs generated via JoinIR",
|
||||
phi_count
|
||||
);
|
||||
}
|
||||
joinir_success = false; // フォールバック使用
|
||||
|
||||
joinir_success = true;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
|
||||
@ -157,6 +157,7 @@ pub fn try_lower_if_to_joinir(
|
||||
func.signature.name.starts_with("IfSelectTest.") ||
|
||||
func.signature.name.starts_with("IfSelectLocalTest.") || // Phase 33-10 test
|
||||
func.signature.name.starts_with("IfMergeTest.") ||
|
||||
func.signature.name.starts_with("IfToplevelTest.") || // Phase 61-4: loop-outside if test
|
||||
func.signature.name.starts_with("Stage1JsonScannerTestBox.") || // Phase 33-5 test
|
||||
|
||||
// Stage-1 rollout (env-controlled)
|
||||
|
||||
Reference in New Issue
Block a user