refactor(mir): phase260 p0 edge-args plumbing (strangler) + ssot api + docs

This commit is contained in:
2025-12-21 04:34:22 +09:00
parent 4496b6243d
commit 4dfe3349bf
42 changed files with 1044 additions and 187 deletions

View File

@ -6,6 +6,7 @@
use super::{EffectMask, MirInstruction, SpannedInstRef, SpannedInstruction, ValueId};
use crate::ast::Span;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::runtime::get_global_ring0;
use std::collections::BTreeSet; // Phase 69-3: HashSet → BTreeSet for determinism
use std::fmt;
@ -42,6 +43,20 @@ impl fmt::Display for BasicBlockId {
}
}
/// Edge arguments for CFG edges (Phase 260 P0)
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EdgeArgs {
pub layout: JumpArgsLayout,
pub values: Vec<ValueId>,
}
/// Outgoing edge from a basic block
#[derive(Debug, Clone)]
pub struct OutEdge {
pub target: BasicBlockId,
pub args: Option<EdgeArgs>,
}
/// A basic block in SSA form
#[derive(Debug, Clone)]
pub struct BasicBlock {
@ -82,6 +97,8 @@ pub struct BasicBlock {
/// all the Jump args (not just the first one) so that exit PHI can correctly
/// merge carrier values from multiple exit paths.
pub jump_args: Option<Vec<ValueId>>,
/// Phase 260 P0: Layout for legacy jump_args (for consistency checks)
pub jump_args_layout: Option<JumpArgsLayout>,
}
impl BasicBlock {
@ -99,6 +116,7 @@ impl BasicBlock {
reachable: false,
sealed: false,
jump_args: None, // Phase 246-EX: No jump args by default
jump_args_layout: None, // Phase 260 P0: Unknown by default
}
}
@ -161,18 +179,23 @@ impl BasicBlock {
/// Update successors based on the terminator instruction
fn update_successors_from_terminator(&mut self) {
self.successors.clear();
self.successors = self.successors_from_terminator();
}
/// Compute successors from the terminator (SSOT for CFG verification)
pub fn successors_from_terminator(&self) -> BTreeSet<BasicBlockId> {
let mut successors = BTreeSet::new();
if let Some(ref terminator) = self.terminator {
match terminator {
MirInstruction::Branch {
then_bb, else_bb, ..
} => {
self.successors.insert(*then_bb);
self.successors.insert(*else_bb);
successors.insert(*then_bb);
successors.insert(*else_bb);
}
MirInstruction::Jump { target } => {
self.successors.insert(*target);
MirInstruction::Jump { target, .. } => {
successors.insert(*target);
}
MirInstruction::Return { .. } => {
// No successors for return
@ -184,6 +207,140 @@ impl BasicBlock {
_ => unreachable!("Non-terminator instruction in terminator position"),
}
}
successors
}
/// Enumerate all outgoing CFG edges
pub fn out_edges(&self) -> Vec<OutEdge> {
match self.terminator {
Some(MirInstruction::Branch {
then_bb,
else_bb,
ref then_edge_args,
ref else_edge_args,
..
}) => vec![
OutEdge {
target: then_bb,
args: then_edge_args.clone(),
},
OutEdge {
target: else_bb,
args: else_edge_args.clone(),
},
],
Some(MirInstruction::Jump {
target,
ref edge_args,
..
}) => vec![OutEdge {
target,
args: edge_args.clone().or_else(|| self.legacy_edge_args()),
}],
_ => Vec::new(),
}
}
/// Get edge args for a specific target (if present)
pub fn edge_args_to(&self, target: BasicBlockId) -> Option<EdgeArgs> {
self.out_edges()
.into_iter()
.find(|edge| edge.target == target)
.and_then(|edge| edge.args)
}
/// Set legacy jump args metadata (migration helper)
pub fn set_legacy_jump_args(&mut self, values: Vec<ValueId>, layout: Option<JumpArgsLayout>) {
self.jump_args = Some(values);
self.jump_args_layout = layout;
}
/// Clear legacy jump args metadata (migration helper)
pub fn clear_legacy_jump_args(&mut self) {
self.jump_args = None;
self.jump_args_layout = None;
}
/// Check if legacy jump args metadata exists
pub fn has_legacy_jump_args(&self) -> bool {
self.jump_args.is_some()
}
/// Access legacy jump args values (read-only, migration helper)
pub fn legacy_jump_args_values(&self) -> Option<&[ValueId]> {
self.jump_args.as_deref()
}
/// Access legacy jump args layout (read-only, migration helper)
pub fn legacy_jump_args_layout(&self) -> Option<JumpArgsLayout> {
self.jump_args_layout
}
/// Build edge args from legacy values with an explicit layout (migration helper)
pub fn legacy_edge_args_with_layout(&self, layout: JumpArgsLayout) -> Option<EdgeArgs> {
self.jump_args.as_ref().map(|values| EdgeArgs {
layout,
values: values.clone(),
})
}
/// Set jump terminator with edge args and legacy metadata (SSOT write helper)
pub fn set_jump_with_edge_args(&mut self, target: BasicBlockId, edge_args: Option<EdgeArgs>) {
let terminator = MirInstruction::Jump {
target,
edge_args: edge_args.clone(),
};
if !self.is_terminator(&terminator) {
panic!("Instruction is not a valid terminator: {:?}", terminator);
}
self.effects = self.effects | terminator.effects();
self.terminator = Some(terminator);
self.terminator_span = Some(Span::unknown());
if let Some(args) = edge_args {
self.jump_args = Some(args.values.clone());
self.jump_args_layout = Some(args.layout);
} else {
self.clear_legacy_jump_args();
}
self.update_successors_from_terminator();
}
/// Set branch terminator with per-edge args (clears legacy metadata)
pub fn set_branch_with_edge_args(
&mut self,
condition: ValueId,
then_bb: BasicBlockId,
then_edge_args: Option<EdgeArgs>,
else_bb: BasicBlockId,
else_edge_args: Option<EdgeArgs>,
) {
let terminator = MirInstruction::Branch {
condition,
then_bb,
else_bb,
then_edge_args,
else_edge_args,
};
if !self.is_terminator(&terminator) {
panic!("Instruction is not a valid terminator: {:?}", terminator);
}
self.effects = self.effects | terminator.effects();
self.terminator = Some(terminator);
self.terminator_span = Some(Span::unknown());
self.clear_legacy_jump_args();
self.update_successors_from_terminator();
}
fn legacy_edge_args(&self) -> Option<EdgeArgs> {
let values = self.jump_args.as_ref()?;
let layout = self.jump_args_layout?;
Some(EdgeArgs {
layout,
values: values.clone(),
})
}
/// Add a predecessor
@ -540,6 +697,8 @@ mod tests {
condition: ValueId::new(0),
then_bb,
else_bb,
then_edge_args: None,
else_edge_args: None,
};
bb.add_instruction(branch_inst);