feat(mir): Phase 260 P2 - Delete BasicBlock.jump_args, unify to terminator SSOT

- Delete legacy jump_args/jump_args_layout fields from BasicBlock
- Add return_env/return_env_layout for Return-specific metadata
- Rename set_return_edge_args() → set_return_env() (clearer semantics)
- Remove 8 legacy helper methods (has/get/set/clear legacy_jump_args)
- Simplify set_jump/branch_with_edge_args (remove legacy sync, keep API)
- Update edge_args_from_terminator() to terminator-only (no fallback)
- Update 10+ JoinIR handler/test sites to use new API

This completes Phase 260 P0 → P2 migration: edge-args are now
exclusively in terminator operands (Jump/Branch) or Return-specific
metadata (renamed from legacy terminology).

BREAKING: BasicBlock.jump_args field removed. Use terminator edge-args
or block.return_env() for Return blocks.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-21 09:39:20 +09:00
parent c0334f8b7e
commit 45a7e24f7d
6 changed files with 59 additions and 114 deletions

View File

@ -92,13 +92,14 @@ pub struct BasicBlock {
/// Is this block sealed? (all predecessors are known)
pub sealed: bool,
/// Phase 246-EX: Jump args metadata for exit PHI construction
/// Phase 260 P2: Return environment metadata
/// Return has no edge-args operand, so we keep metadata for continuation.
/// When a JoinIR Jump is converted to MIR Return, this field preserves
/// 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>,
pub return_env: Option<Vec<ValueId>>,
/// Phase 260 P2: Layout for return environment
pub return_env_layout: Option<JumpArgsLayout>,
}
impl BasicBlock {
@ -115,8 +116,8 @@ impl BasicBlock {
effects: EffectMask::PURE,
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
return_env: None, // Phase 260 P2: No return env by default
return_env_layout: None, // Phase 260 P2: Unknown by default
}
}
@ -236,7 +237,7 @@ impl BasicBlock {
..
}) => vec![OutEdge {
target,
args: edge_args.clone().or_else(|| self.legacy_edge_args()),
args: edge_args.clone(), // Phase 260 P2: No fallback, terminator SSOT
}],
_ => Vec::new(),
}
@ -250,59 +251,33 @@ impl BasicBlock {
.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.clone());
self.jump_args_layout = layout;
if let (Some(layout), Some(MirInstruction::Jump { target, edge_args: None })) =
(layout, self.terminator.clone())
{
let edge_args = EdgeArgs { layout, values };
self.set_jump_with_edge_args(target, Some(edge_args));
}
}
/// Record edge-args for Return terminators (migration helper)
/// Set Return environment metadata (Return-specific)
///
/// Return has no edge-args operand, so we keep this metadata for now.
pub fn set_return_edge_args(&mut self, edge_args: EdgeArgs) {
/// Return has no edge-args operand, so we keep this metadata for continuation.
pub fn set_return_env(&mut self, env: EdgeArgs) {
if !matches!(self.terminator, Some(MirInstruction::Return { .. })) {
panic!("set_return_edge_args requires Return terminator");
panic!("set_return_env requires Return terminator");
}
self.jump_args = Some(edge_args.values);
self.jump_args_layout = Some(edge_args.layout);
self.return_env = Some(env.values);
self.return_env_layout = Some(env.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;
/// Get Return environment metadata
pub fn return_env(&self) -> Option<EdgeArgs> {
if matches!(self.terminator, Some(MirInstruction::Return { .. })) {
match (self.return_env.as_ref(), self.return_env_layout) {
(Some(values), Some(layout)) => Some(EdgeArgs {
layout,
values: values.clone(),
}),
_ => None,
}
} else {
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)
/// Set jump terminator with edge args (SSOT write helper)
pub fn set_jump_with_edge_args(&mut self, target: BasicBlockId, edge_args: Option<EdgeArgs>) {
let terminator = MirInstruction::Jump {
target,
@ -315,16 +290,10 @@ impl BasicBlock {
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)
/// Set branch terminator with per-edge args
pub fn set_branch_with_edge_args(
&mut self,
condition: ValueId,
@ -347,29 +316,16 @@ impl BasicBlock {
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(),
})
}
/// Get edge-args from the current terminator (migration helper)
/// Get edge-args from the current terminator
///
/// Jump uses its edge-args operand when present, otherwise falls back to
/// stored metadata. Return relies on stored metadata.
/// Jump uses its edge-args operand. Return uses return_env metadata.
pub fn edge_args_from_terminator(&self) -> Option<EdgeArgs> {
match self.terminator {
Some(MirInstruction::Jump { ref edge_args, .. }) => {
edge_args.clone().or_else(|| self.legacy_edge_args())
}
Some(MirInstruction::Return { .. }) => self.legacy_edge_args(),
Some(MirInstruction::Jump { ref edge_args, .. }) => edge_args.clone(),
Some(MirInstruction::Return { .. }) => self.return_env(),
_ => None,
}
}

View File

@ -744,8 +744,8 @@ mod tests {
.get(&entry)
.expect("missing loop_body entry block");
assert!(
entry_block.has_legacy_jump_args(),
"loop_body entry block must have legacy jump_args metadata in bridged MIR"
entry_block.return_env().is_some(),
"loop_body entry block must have return_env metadata in bridged MIR"
);
// Loop-only (the routing path in real lowering): still must encode loop_step as a tail-call.

View File

@ -198,8 +198,8 @@ where
terminator,
);
if let Some(block) = mir_func.blocks.get_mut(&current_block_id) {
if block.terminator.is_some() && !block.has_legacy_jump_args() {
block.set_return_edge_args(crate::mir::EdgeArgs {
if matches!(block.terminator, Some(MirInstruction::Return { .. })) && block.return_env().is_none() {
block.set_return_env(crate::mir::EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: args.to_vec(),
});
@ -365,12 +365,10 @@ mod tests {
_ => panic!("Expected Return terminator"),
}
// Check legacy jump args metadata
assert!(block.has_legacy_jump_args());
let jump_args = block.legacy_jump_args_values().unwrap();
let layout = block.legacy_jump_args_layout();
assert_eq!(jump_args, &[ValueId(10), ValueId(20)]);
assert_eq!(layout, Some(JumpArgsLayout::CarriersOnly));
// Check return environment metadata
let env = block.return_env().expect("Block should have return_env");
assert_eq!(env.values, vec![ValueId(10), ValueId(20)]);
assert_eq!(env.layout, JumpArgsLayout::CarriersOnly);
}
#[test]

View File

@ -221,7 +221,7 @@ where
exit_block.set_terminator(MirInstruction::Return {
value: Some(call_result_id),
});
exit_block.set_return_edge_args(crate::mir::EdgeArgs {
exit_block.set_return_env(crate::mir::EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: args.to_vec(),
});
@ -250,8 +250,8 @@ where
finalize_fn(mir_func, current_block_id, current_instructions, return_terminator);
if let Some(block) = mir_func.blocks.get_mut(&current_block_id) {
if block.terminator.is_some() && !block.has_legacy_jump_args() {
block.set_return_edge_args(crate::mir::EdgeArgs {
if matches!(block.terminator, Some(MirInstruction::Return { .. })) && block.return_env().is_none() {
block.set_return_env(crate::mir::EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: args.to_vec(),
});
@ -391,12 +391,10 @@ mod tests {
_ => panic!("Expected Return terminator"),
}
// Check legacy jump args metadata
assert!(block.has_legacy_jump_args());
let jump_args = block.legacy_jump_args_values().unwrap();
let layout = block.legacy_jump_args_layout();
assert_eq!(jump_args, &[ValueId(10), ValueId(20)]);
assert_eq!(layout, Some(JumpArgsLayout::CarriersOnly));
// Check return environment metadata
let env = block.return_env().expect("Block should have return_env");
assert_eq!(env.values, vec![ValueId(10), ValueId(20)]);
assert_eq!(env.layout, JumpArgsLayout::CarriersOnly);
}
#[test]
@ -479,12 +477,10 @@ mod tests {
_ => panic!("Expected Return terminator"),
}
// Check legacy jump args metadata in exit block
assert!(exit_block.has_legacy_jump_args());
let jump_args = exit_block.legacy_jump_args_values().unwrap();
let layout = exit_block.legacy_jump_args_layout();
assert_eq!(jump_args, &[ValueId(1), ValueId(2)]);
assert_eq!(layout, Some(JumpArgsLayout::CarriersOnly));
// Check return environment metadata in exit block
let env = exit_block.return_env().expect("Exit block should have return_env");
assert_eq!(env.values, vec![ValueId(1), ValueId(2)]);
assert_eq!(env.layout, JumpArgsLayout::CarriersOnly);
// Check continue block exists and is empty
let continue_block = mir_func.blocks.get(&BasicBlockId(2)).unwrap();

View File

@ -443,8 +443,8 @@ impl JoinIrBlockConverter {
terminator,
);
if let Some(block) = mir_func.blocks.get_mut(&self.current_block_id) {
if block.terminator.is_some() && !block.has_legacy_jump_args() {
block.set_return_edge_args(crate::mir::EdgeArgs {
if matches!(block.terminator, Some(MirInstruction::Return { .. })) && block.return_env().is_none() {
block.set_return_env(crate::mir::EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: args.to_vec(),
});
@ -521,7 +521,7 @@ impl JoinIrBlockConverter {
});
exit_block.instruction_spans.push(Span::unknown());
exit_block.set_terminator(MirInstruction::Return { value: Some(call_result_id) });
exit_block.set_return_edge_args(crate::mir::EdgeArgs {
exit_block.set_return_env(crate::mir::EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: args.to_vec(),
});
@ -557,8 +557,8 @@ impl JoinIrBlockConverter {
return_terminator,
);
if let Some(block) = mir_func.blocks.get_mut(&self.current_block_id) {
if block.terminator.is_some() && !block.has_legacy_jump_args() {
block.set_return_edge_args(crate::mir::EdgeArgs {
if matches!(block.terminator, Some(MirInstruction::Return { .. })) && block.return_env().is_none() {
block.set_return_env(crate::mir::EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: args.to_vec(),
});

View File

@ -422,7 +422,7 @@ fn build_exit_or_tail_branch(
block.instructions.clear();
block.instruction_spans.clear();
block.set_terminator(MirInstruction::Return { value: ret_val });
block.set_return_edge_args(crate::mir::EdgeArgs {
block.set_return_env(crate::mir::EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: env.to_vec(),
});
@ -484,7 +484,6 @@ fn finalize_block(
target,
edge_args: None,
});
block.clear_legacy_jump_args();
}
}
MirInstruction::Branch {
@ -501,22 +500,18 @@ fn finalize_block(
else_bb,
else_edge_args,
);
block.clear_legacy_jump_args();
}
MirInstruction::Return { .. } => {
block.set_terminator(terminator);
if let Some(args) = jump_args {
block.set_return_edge_args(crate::mir::EdgeArgs {
block.set_return_env(crate::mir::EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: args,
});
} else {
block.clear_legacy_jump_args();
}
}
other => {
block.set_terminator(other);
block.clear_legacy_jump_args();
}
}
}