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 super::{MirBuilder, ValueId};
|
||||||
use crate::ast::ASTNode;
|
use crate::ast::ASTNode;
|
||||||
|
use crate::mir::control_form::IfShape;
|
||||||
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
|
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 {
|
impl MirBuilder {
|
||||||
/// Lower an if/else using a structured IfForm (header→then/else→merge).
|
/// 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 {
|
if joinir_toplevel {
|
||||||
joinir_success = true;
|
// IfShape 構築
|
||||||
// TODO: Phase 61-4-E 本番経路のPHI生成
|
let if_shape = IfShape {
|
||||||
// 現時点では dry-run 的動作(フォールバック経路を使用)
|
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 {
|
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 => {
|
None => {
|
||||||
|
|||||||
@ -157,6 +157,7 @@ pub fn try_lower_if_to_joinir(
|
|||||||
func.signature.name.starts_with("IfSelectTest.") ||
|
func.signature.name.starts_with("IfSelectTest.") ||
|
||||||
func.signature.name.starts_with("IfSelectLocalTest.") || // Phase 33-10 test
|
func.signature.name.starts_with("IfSelectLocalTest.") || // Phase 33-10 test
|
||||||
func.signature.name.starts_with("IfMergeTest.") ||
|
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
|
func.signature.name.starts_with("Stage1JsonScannerTestBox.") || // Phase 33-5 test
|
||||||
|
|
||||||
// Stage-1 rollout (env-controlled)
|
// Stage-1 rollout (env-controlled)
|
||||||
|
|||||||
Reference in New Issue
Block a user