refactor(mir): phase260 p0 edge-args plumbing (strangler) + ssot api + docs
This commit is contained in:
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user