phase29ao(p8): ssot compose preserves edgeargs for valuejoin

This commit is contained in:
2025-12-30 05:51:55 +09:00
parent 0ad2a45383
commit 6a6276f3ac
8 changed files with 195 additions and 6 deletions

View File

@ -133,3 +133,47 @@ pub(crate) fn cleanup(
branches,
})
}
#[cfg(test)]
mod tests {
use super::cleanup;
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
use crate::mir::builder::control_flow::edgecfg::api::edge_stub::EdgeStub;
use crate::mir::builder::control_flow::edgecfg::api::exit_kind::ExitKind;
use crate::mir::builder::control_flow::edgecfg::api::frag::Frag;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::mir::ValueId;
use std::collections::BTreeMap;
#[test]
fn cleanup_preserves_edgeargs_for_return_exit() {
let main = Frag::new(BasicBlockId::new(1));
let cleanup_entry = BasicBlockId::new(2);
let args = EdgeArgs {
layout: JumpArgsLayout::ExprResultPlusCarriers,
values: vec![ValueId(30)],
};
let mut exits = BTreeMap::new();
exits.insert(
ExitKind::Return,
vec![EdgeStub {
from: cleanup_entry,
kind: ExitKind::Return,
target: None,
args: args.clone(),
}],
);
let cleanup_frag = Frag {
entry: cleanup_entry,
exits,
wires: vec![],
branches: vec![],
};
let composed =
cleanup(main, cleanup_frag, None, None).expect("cleanup ok");
assert_eq!(composed.wires.len(), 1);
assert_eq!(composed.wires[0].args, args);
assert!(composed.wires[0].target.is_none());
}
}

View File

@ -137,3 +137,93 @@ pub(crate) fn if_(
branches, // Phase 267 P0: header の BranchStub + t/e/join の branches
}
}
#[cfg(test)]
mod tests {
use super::if_;
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
use crate::mir::builder::control_flow::edgecfg::api::edge_stub::EdgeStub;
use crate::mir::builder::control_flow::edgecfg::api::exit_kind::ExitKind;
use crate::mir::builder::control_flow::edgecfg::api::frag::Frag;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::mir::value_id::ValueId;
use std::collections::BTreeMap;
#[test]
fn if_preserves_edgeargs_for_then_else_normal_exits() {
let header = BasicBlockId::new(1);
let then_entry = BasicBlockId::new(2);
let else_entry = BasicBlockId::new(3);
let join_entry = BasicBlockId::new(4);
let cond = ValueId(10);
let then_entry_args = EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: vec![],
};
let else_entry_args = EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: vec![],
};
let then_args = EdgeArgs {
layout: JumpArgsLayout::ExprResultPlusCarriers,
values: vec![ValueId(20)],
};
let else_args = EdgeArgs {
layout: JumpArgsLayout::ExprResultPlusCarriers,
values: vec![ValueId(21)],
};
let mut then_exits = BTreeMap::new();
then_exits.insert(
ExitKind::Normal,
vec![EdgeStub {
from: then_entry,
kind: ExitKind::Normal,
target: None,
args: then_args.clone(),
}],
);
let then_frag = Frag {
entry: then_entry,
exits: then_exits,
wires: vec![],
branches: vec![],
};
let mut else_exits = BTreeMap::new();
else_exits.insert(
ExitKind::Normal,
vec![EdgeStub {
from: else_entry,
kind: ExitKind::Normal,
target: None,
args: else_args.clone(),
}],
);
let else_frag = Frag {
entry: else_entry,
exits: else_exits,
wires: vec![],
branches: vec![],
};
let join_frag = Frag::new(join_entry);
let composed = if_(
header,
cond,
then_frag,
then_entry_args,
else_frag,
else_entry_args,
join_frag,
);
assert_eq!(composed.wires.len(), 2);
assert!(composed.wires.iter().any(|stub| {
stub.target == Some(join_entry) && stub.args == then_args
}));
assert!(composed.wires.iter().any(|stub| {
stub.target == Some(join_entry) && stub.args == else_args
}));
}
}

View File

@ -87,3 +87,44 @@ pub(crate) fn seq(a: Frag, b: Frag) -> Frag {
branches, // Phase 267 P0: a.branches + b.branches
}
}
#[cfg(test)]
mod tests {
use super::seq;
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
use crate::mir::builder::control_flow::edgecfg::api::edge_stub::EdgeStub;
use crate::mir::builder::control_flow::edgecfg::api::exit_kind::ExitKind;
use crate::mir::builder::control_flow::edgecfg::api::frag::Frag;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::mir::ValueId;
use std::collections::BTreeMap;
#[test]
fn seq_preserves_edgeargs_for_normal_exit() {
let a_entry = BasicBlockId::new(1);
let b_entry = BasicBlockId::new(2);
let args = EdgeArgs {
layout: JumpArgsLayout::ExprResultPlusCarriers,
values: vec![ValueId(10)],
};
let stub = EdgeStub {
from: a_entry,
kind: ExitKind::Normal,
target: None,
args: args.clone(),
};
let mut exits = BTreeMap::new();
exits.insert(ExitKind::Normal, vec![stub]);
let a = Frag {
entry: a_entry,
exits,
wires: vec![],
branches: vec![],
};
let b = Frag::new(b_entry);
let composed = seq(a, b);
assert_eq!(composed.wires.len(), 1);
assert_eq!(composed.wires[0].target, Some(b_entry));
assert_eq!(composed.wires[0].args, args);
}
}

View File

@ -397,16 +397,21 @@ mod tests {
use crate::mir::basic_block::EdgeArgs;
use crate::mir::builder::control_flow::edgecfg::api::{EdgeStub, ExitKind, Frag};
use crate::mir::builder::control_flow::plan::CorePhiInfo;
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::facts::feature_facts::{
LoopFeatureFacts, ValueJoinFacts,
};
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::facts::loop_facts::LoopFacts;
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::facts::scan_shapes::{
ConditionShape, StepShape,
};
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::facts::skeleton_facts::{
SkeletonFacts, SkeletonKind,
};
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::normalize::canonicalize_loop_facts;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use std::collections::BTreeMap;