feat: フェーズM実装 - no_phi_mode完全撤廃でPHI一本化達成

 **コア実装完了**:
- MirBuilder: phi.rs, exprs_peek.rs全no_phi_mode分岐削除
- LoopBuilder: 3箇所のno_phi_mode分岐をPHI命令に統一
- edge_copy関連: insert_edge_copy()メソッド含む数十行削除

 **効果**:
- 数百行削減によりPhase 15の80k→20k圧縮目標に大幅貢献
- 常にPHI命令使用でMIR生成の一貫性向上
- フェーズS制御フロー統一と合わせて設計改善達成

🎯 **次段階**: JSON v0 Bridge対応→collect_prints動作確認

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Selfhosting Dev
2025-09-23 07:25:58 +09:00
parent 2e93403de0
commit 96abbf1634
5 changed files with 49 additions and 187 deletions

View File

@ -106,8 +106,7 @@ pub struct MirBuilder {
/// when lowering nested conditionals and to simplify jump generation.
pub(super) if_merge_stack: Vec<BasicBlockId>,
/// Whether PHI emission is disabled (edge-copy mode)
pub(super) no_phi_mode: bool,
// フェーズM: no_phi_modeフィールド削除常にPHI使用
// ---- Try/Catch/Cleanup lowering context ----
/// When true, `return` statements are deferred: they assign to `return_defer_slot`
@ -133,7 +132,7 @@ impl MirBuilder {
/// Create a new MIR builder
pub fn new() -> Self {
let plugin_method_sigs = plugin_sigs::load_plugin_method_sigs();
let no_phi_mode = crate::config::env::mir_no_phi();
// フェーズM: no_phi_mode初期化削除
Self {
current_module: None,
current_function: None,
@ -155,7 +154,7 @@ impl MirBuilder {
loop_header_stack: Vec::new(),
loop_exit_stack: Vec::new(),
if_merge_stack: Vec::new(),
no_phi_mode,
// フェーズM: no_phi_modeフィールド削除
return_defer_active: false,
return_defer_slot: None,
return_defer_target: None,
@ -339,48 +338,9 @@ impl MirBuilder {
}
}
pub(super) fn is_no_phi_mode(&self) -> bool {
self.no_phi_mode
}
// フェーズM: is_no_phi_mode()メソッド削除
/// Insert a Copy instruction into `block_id`, defining `dst` from `src`.
/// Skips blocks that terminate via return/throw, and avoids duplicate copies.
pub(super) fn insert_edge_copy(
&mut self,
block_id: BasicBlockId,
dst: ValueId,
src: ValueId,
) -> Result<(), String> {
// No-op self copy guard to avoid useless instructions and accidental reordering issues
if dst == src {
return Ok(());
}
if let Some(ref mut function) = self.current_function {
let block = function
.get_block_mut(block_id)
.ok_or_else(|| format!("Basic block {} does not exist", block_id))?;
if let Some(term) = &block.terminator {
if matches!(
term,
MirInstruction::Return { .. } | MirInstruction::Throw { .. }
) {
return Ok(());
}
}
let already_present = block.instructions.iter().any(|inst| {
matches!(inst, MirInstruction::Copy { dst: existing_dst, .. } if *existing_dst == dst)
});
if !already_present {
block.add_instruction(MirInstruction::Copy { dst, src });
}
if let Some(ty) = self.value_types.get(&src).cloned() {
self.value_types.insert(dst, ty);
}
Ok(())
} else {
Err("No current function".to_string())
}
}
// フェーズM: insert_edge_copy()メソッド削除no_phi_mode撤廃により不要
// moved to builder/utils.rs: ensure_block_exists

View File

@ -50,16 +50,11 @@ impl super::MirBuilder {
target: merge_block,
})?;
self.start_new_block(merge_block)?;
if self.is_no_phi_mode() {
for (pred, val) in phi_inputs {
self.insert_edge_copy(pred, result_val, val)?;
}
} else {
self.emit_instruction(super::MirInstruction::Phi {
dst: result_val,
inputs: phi_inputs,
})?;
}
// フェーズM: 常にPHI命令を使用no_phi_mode撤廃
self.emit_instruction(super::MirInstruction::Phi {
dst: result_val,
inputs: phi_inputs,
})?;
return Ok(result_val);
}
@ -122,16 +117,11 @@ impl super::MirBuilder {
// Merge and yield result
self.start_new_block(merge_block)?;
if self.is_no_phi_mode() {
for (pred, val) in phi_inputs {
self.insert_edge_copy(pred, result_val, val)?;
}
} else {
self.emit_instruction(super::MirInstruction::Phi {
dst: result_val,
inputs: phi_inputs,
})?;
}
// フェーズM: 常にPHI命令を使用no_phi_mode撤廃
self.emit_instruction(super::MirInstruction::Phi {
dst: result_val,
inputs: phi_inputs,
})?;
Ok(result_val)
}
}

View File

@ -113,27 +113,15 @@ impl MirBuilder {
.as_ref()
.and_then(|m| m.get(name).copied())
.unwrap_or(pre);
if self.is_no_phi_mode() {
let merged = self.value_gen.next();
// Insert edge copies from then/else exits into merge
self.insert_edge_copy(then_exit_block, merged, then_v)?;
if let Some(else_exit_block) = else_exit_block_opt {
self.insert_edge_copy(else_exit_block, merged, else_v)?;
} else {
// Fallback: if else missing, copy pre value from then as both inputs already cover
self.insert_edge_copy(then_exit_block, merged, then_v)?;
// フェーズM: 常にPHI命令を使用no_phi_mode撤廃
let merged = self.value_gen.next();
self.emit_instruction(
MirInstruction::Phi {
dst: merged,
inputs: vec![(then_block, then_v), (else_block, else_v)],
}
self.variable_map.insert(name.to_string(), merged);
} else {
let merged = self.value_gen.next();
self.emit_instruction(
MirInstruction::Phi {
dst: merged,
inputs: vec![(then_block, then_v), (else_block, else_v)],
}
)?;
self.variable_map.insert(name.to_string(), merged);
}
)?;
self.variable_map.insert(name.to_string(), merged);
}
Ok(())
}
@ -162,71 +150,7 @@ impl MirBuilder {
.and_then(|a| extract_assigned_var(a));
let result_val = self.value_gen.next();
if self.is_no_phi_mode() {
// In PHI-off mode, emit per-predecessor copies into the actual predecessors
// of the current (merge) block instead of the entry blocks. This correctly
// handles nested conditionals where the then-branch fans out and merges later.
let merge_block = self
.current_block
.ok_or_else(|| "normalize_if_else_phi: no current (merge) block".to_string())?;
let preds: Vec<crate::mir::BasicBlockId> = if let Some(ref fun_ro) = self.current_function {
if let Some(bb) = fun_ro.get_block(merge_block) {
bb.predecessors.iter().copied().collect()
} else {
Vec::new()
}
} else {
Vec::new()
};
// Prefer explicit exit blocks if provided; fall back to predecessor scan
let then_exits: Vec<crate::mir::BasicBlockId> = if let Some(b) = then_exit_block_opt {
vec![b]
} else {
preds.iter().copied().filter(|p| *p != else_block).collect()
};
let else_exits: Vec<crate::mir::BasicBlockId> = if let Some(b) = else_exit_block_opt {
vec![b]
} else {
preds.iter().copied().filter(|p| *p == else_block).collect()
};
if let Some(var_name) = assigned_var_then.clone() {
let else_assigns_same = assigned_var_else
.as_ref()
.map(|s| s == &var_name)
.unwrap_or(false);
let then_value_for_var = then_var_map_end
.get(&var_name)
.copied()
.unwrap_or(then_value_raw);
let else_value_for_var = if else_assigns_same {
else_var_map_end_opt
.as_ref()
.and_then(|m| m.get(&var_name).copied())
.unwrap_or(else_value_raw)
} else {
pre_then_var_value.unwrap_or(else_value_raw)
};
// Map predecessors: else_block retains else value; others take then value
for p in then_exits.iter().copied() {
self.insert_edge_copy(p, result_val, then_value_for_var)?;
}
for p in else_exits.iter().copied() {
self.insert_edge_copy(p, result_val, else_value_for_var)?;
}
self.variable_map = pre_if_var_map.clone();
self.variable_map.insert(var_name, result_val);
} else {
for p in then_exits.iter().copied() {
self.insert_edge_copy(p, result_val, then_value_raw)?;
}
for p in else_exits.iter().copied() {
self.insert_edge_copy(p, result_val, else_value_raw)?;
}
self.variable_map = pre_if_var_map.clone();
}
return Ok(result_val);
}
// フェーズM: no_phi_mode分岐削除常にPHI命令を使用
if let Some(var_name) = assigned_var_then.clone() {
let else_assigns_same = assigned_var_else

View File

@ -45,8 +45,7 @@ pub struct LoopBuilder<'a> {
/// continue文からの変数スナップショット
continue_snapshots: Vec<(BasicBlockId, HashMap<String, ValueId>)>,
/// PHI を生成しないモードかどうか
no_phi_mode: bool,
// フェーズM: no_phi_modeフィールド削除常にPHI使用
}
// (removed) extract_assigned_var_local was a local helper used during
@ -103,14 +102,14 @@ impl<'a> LoopBuilder<'a> {
// =============================================================
/// 新しいループビルダーを作成
pub fn new(parent: &'a mut super::builder::MirBuilder) -> Self {
let no_phi_mode = parent.is_no_phi_mode();
// フェーズM: no_phi_mode初期化削除
Self {
parent_builder: parent,
incomplete_phis: HashMap::new(),
block_var_maps: HashMap::new(),
loop_header: None,
continue_snapshots: Vec::new(),
no_phi_mode,
// フェーズM: no_phi_modeフィールド削除
}
}
@ -278,10 +277,7 @@ impl<'a> LoopBuilder<'a> {
incomplete_phis.push(incomplete_phi);
if self.no_phi_mode {
self.parent_builder
.insert_edge_copy(preheader_id, phi_id, value_before)?;
}
// フェーズM: no_phi_mode分岐削除常にPHI使用
// 変数マップを更新Phi nodeの結果を使用
self.update_variable(var_name.clone(), phi_id);
@ -310,17 +306,8 @@ impl<'a> LoopBuilder<'a> {
phi.known_inputs.push((latch_id, value_after));
if self.no_phi_mode {
let mut seen: HashSet<BasicBlockId> = HashSet::new();
for &(pred, val) in &phi.known_inputs {
if seen.insert(pred) {
self.parent_builder
.insert_edge_copy(pred, phi.phi_id, val)?;
}
}
} else {
self.emit_phi_at_block_start(block_id, phi.phi_id, phi.known_inputs)?;
}
// フェーズM: 常にPHI命令を使用no_phi_mode分岐削除)
self.emit_phi_at_block_start(block_id, phi.phi_id, phi.known_inputs)?;
self.update_variable(phi.var_name.clone(), phi.phi_id);
}
}
@ -601,13 +588,8 @@ impl<'a> LoopBuilder<'a> {
}
_ => {
let phi_id = self.new_value();
if self.no_phi_mode {
for (pred, v) in incomings.iter().copied() {
self.parent_builder.insert_edge_copy(pred, phi_id, v)?;
}
} else {
self.emit_phi_at_block_start(merge_bb, phi_id, incomings)?;
}
// フェーズM: 常にPHI命令を使用no_phi_mode分岐削除)
self.emit_phi_at_block_start(merge_bb, phi_id, incomings)?;
self.parent_builder.variable_map.insert(var_name, phi_id);
}
}