feat(mir): Phase 69-3 Fix MIR non-determinism with BTreeSet
Replace HashSet with BTreeSet for CFG predecessors/successors: - BasicBlock.predecessors: HashSet → BTreeSet - BasicBlock.successors: HashSet → BTreeSet - LoopFormOps.get_block_predecessors(): returns BTreeSet - BasicBlock.dominates(): takes &[BTreeSet<BasicBlockId>] This ensures deterministic PHI generation and test stability. Test results: - loop_with_continue_and_break tests: now deterministic (3/3 same output) - loopform tests: 14/14 PASS (no regressions) - merge_exit_with_classification tests: 3/3 PASS Technical changes (6 files): - basic_block.rs: BTreeSet types + new() initialization - loopform_builder.rs: trait signature + 2 mock implementations - phi_ops.rs: return type - json_v0_bridge/loop_.rs: return type Same pattern as Phase 25.1 (MirFunction.blocks HashMap → BTreeMap). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -68,12 +68,13 @@ impl IfInLoopPhiEmitter {
|
||||
if_shape: &IfShape,
|
||||
) -> Result<usize, String> {
|
||||
let mut phi_count = 0;
|
||||
let trace_on = std::env::var("HAKO_JOINIR_IF_IN_LOOP_TRACE").ok().as_deref() == Some("1");
|
||||
let trace_on = std::env::var("HAKO_JOINIR_IF_IN_LOOP_TRACE")
|
||||
.ok()
|
||||
.as_deref()
|
||||
== Some("1");
|
||||
|
||||
if trace_on {
|
||||
eprintln!(
|
||||
"[Phase 61-3] IfInLoopPhiEmitter::emit_header_phis start"
|
||||
);
|
||||
eprintln!("[Phase 61-3] IfInLoopPhiEmitter::emit_header_phis start");
|
||||
eprintln!("[Phase 61-3] header_phis: {:?}", phi_spec.header_phis);
|
||||
eprintln!("[Phase 61-3] carrier_names: {:?}", carrier_names);
|
||||
}
|
||||
@ -99,10 +100,7 @@ impl IfInLoopPhiEmitter {
|
||||
};
|
||||
|
||||
// Then値: snapshot から取得、なければ pre_val
|
||||
let then_val = then_snapshot
|
||||
.get(var_name)
|
||||
.copied()
|
||||
.unwrap_or(pre_val);
|
||||
let then_val = then_snapshot.get(var_name).copied().unwrap_or(pre_val);
|
||||
|
||||
// Else値: snapshot から取得、なければ pre_val(片腕 PHI パターン)
|
||||
let else_val = else_snapshot_opt
|
||||
@ -181,8 +179,10 @@ impl IfInLoopPhiEmitter {
|
||||
if_shape: &IfShape,
|
||||
) -> Result<usize, String> {
|
||||
let mut phi_count = 0;
|
||||
let trace_on =
|
||||
std::env::var("HAKO_JOINIR_IF_TOPLEVEL_TRACE").ok().as_deref() == Some("1");
|
||||
let trace_on = std::env::var("HAKO_JOINIR_IF_TOPLEVEL_TRACE")
|
||||
.ok()
|
||||
.as_deref()
|
||||
== Some("1");
|
||||
|
||||
if trace_on {
|
||||
eprintln!("[Phase 61-4] IfInLoopPhiEmitter::emit_toplevel_phis start");
|
||||
|
||||
@ -203,7 +203,8 @@ impl<'a> LoopBuilder<'a> {
|
||||
// Phase 62-B: JoinIRIfPhiSelector箱化(-60行の簡潔化)
|
||||
let joinir_result = if crate::config::env::joinir_if_select_enabled() {
|
||||
if let Some(ref func) = self.parent_builder.current_function {
|
||||
let selector = super::JoinIRIfPhiSelector::new(func, pre_branch_bb, carrier_names.clone());
|
||||
let selector =
|
||||
super::JoinIRIfPhiSelector::new(func, pre_branch_bb, carrier_names.clone());
|
||||
selector.try_lower()
|
||||
} else {
|
||||
super::JoinIRResult {
|
||||
|
||||
@ -395,7 +395,7 @@ impl<'a> LoopBuilder<'a> {
|
||||
merge_block.add_instruction(MirInstruction::Phi {
|
||||
dst: phi_id,
|
||||
inputs: final_inputs,
|
||||
type_hint: None, // Phase 63-6
|
||||
type_hint: None, // Phase 63-6
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,16 +172,17 @@ impl<'a> LoopFormOps for LoopBuilder<'a> {
|
||||
fn get_block_predecessors(
|
||||
&self,
|
||||
block: BasicBlockId,
|
||||
) -> std::collections::HashSet<BasicBlockId> {
|
||||
) -> std::collections::BTreeSet<BasicBlockId> {
|
||||
// 📦 Hotfix 6: Get actual CFG predecessors for PHI validation
|
||||
// Phase 69-3: Changed to BTreeSet for determinism
|
||||
if let Some(ref func) = self.parent_builder.current_function {
|
||||
if let Some(bb) = func.blocks.get(&block) {
|
||||
bb.predecessors.clone()
|
||||
} else {
|
||||
std::collections::HashSet::new() // Non-existent blocks have no predecessors
|
||||
std::collections::BTreeSet::new() // Non-existent blocks have no predecessors
|
||||
}
|
||||
} else {
|
||||
std::collections::HashSet::new()
|
||||
std::collections::BTreeSet::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user