phase29aa(p5): multi-pred return join when states match
This commit is contained in:
@ -280,6 +280,101 @@ fn main() {
|
||||
"jump_chain_single_pred",
|
||||
);
|
||||
|
||||
// Case 3.7: Multi-predecessor Return with MATCHING states
|
||||
// P5: すべての incoming end_state が完全一致する場合のみ ReturnCleanup を成立させる
|
||||
let ptr = ValueId::new(370);
|
||||
let v_shared = ValueId::new(23); // 同じValueIdを両predecessorで使用
|
||||
|
||||
let mut block_a = BasicBlock::new(BasicBlockId::new(0));
|
||||
block_a.instructions = vec![MirInstruction::Store { value: v_shared, ptr }];
|
||||
block_a.instruction_spans = vec![Span::unknown()];
|
||||
block_a.terminator = Some(MirInstruction::Jump {
|
||||
target: BasicBlockId::new(2),
|
||||
edge_args: None,
|
||||
});
|
||||
block_a.terminator_span = Some(Span::unknown());
|
||||
|
||||
let mut block_b = BasicBlock::new(BasicBlockId::new(1));
|
||||
block_b.instructions = vec![MirInstruction::Store { value: v_shared, ptr }];
|
||||
block_b.instruction_spans = vec![Span::unknown()];
|
||||
block_b.terminator = Some(MirInstruction::Jump {
|
||||
target: BasicBlockId::new(2),
|
||||
edge_args: None,
|
||||
});
|
||||
block_b.terminator_span = Some(Span::unknown());
|
||||
|
||||
let mut block_ret = BasicBlock::new(BasicBlockId::new(2));
|
||||
block_ret.instructions = vec![];
|
||||
block_ret.instruction_spans = vec![];
|
||||
block_ret.terminator = Some(MirInstruction::Return { value: None });
|
||||
block_ret.terminator_span = Some(Span::unknown());
|
||||
|
||||
let module = build_module_with_blocks(
|
||||
vec![block_a, block_b, block_ret],
|
||||
BasicBlockId::new(0),
|
||||
"selfcheck_multi_pred_return_match",
|
||||
"selfcheck_mod3p7",
|
||||
);
|
||||
assert_release_counts_in_blocks(
|
||||
module,
|
||||
"selfcheck_multi_pred_return_match",
|
||||
1, // 全体で1(Return blockのみ)
|
||||
&[
|
||||
(BasicBlockId::new(0), 0), // Jump block: cleanup禁止
|
||||
(BasicBlockId::new(1), 0), // Jump block: cleanup禁止
|
||||
(BasicBlockId::new(2), 1), // Return block: multi-pred join成功
|
||||
],
|
||||
"multi_pred_return_match",
|
||||
);
|
||||
|
||||
// Case 3.8: Multi-predecessor Return with MISMATCHING states (negative test)
|
||||
// P5: state不一致 → join state を作らない → ReturnCleanup なし
|
||||
let ptr = ValueId::new(380);
|
||||
let v1 = ValueId::new(24);
|
||||
let v2 = ValueId::new(25); // 異なるValueId → state不一致
|
||||
|
||||
let mut block_a = BasicBlock::new(BasicBlockId::new(0));
|
||||
block_a.instructions = vec![MirInstruction::Store { value: v1, ptr }];
|
||||
block_a.instruction_spans = vec![Span::unknown()];
|
||||
block_a.terminator = Some(MirInstruction::Jump {
|
||||
target: BasicBlockId::new(2),
|
||||
edge_args: None,
|
||||
});
|
||||
block_a.terminator_span = Some(Span::unknown());
|
||||
|
||||
let mut block_b = BasicBlock::new(BasicBlockId::new(1));
|
||||
block_b.instructions = vec![MirInstruction::Store { value: v2, ptr }]; // v2 != v1 → 不一致
|
||||
block_b.instruction_spans = vec![Span::unknown()];
|
||||
block_b.terminator = Some(MirInstruction::Jump {
|
||||
target: BasicBlockId::new(2),
|
||||
edge_args: None,
|
||||
});
|
||||
block_b.terminator_span = Some(Span::unknown());
|
||||
|
||||
let mut block_ret = BasicBlock::new(BasicBlockId::new(2));
|
||||
block_ret.instructions = vec![];
|
||||
block_ret.instruction_spans = vec![];
|
||||
block_ret.terminator = Some(MirInstruction::Return { value: None });
|
||||
block_ret.terminator_span = Some(Span::unknown());
|
||||
|
||||
let module = build_module_with_blocks(
|
||||
vec![block_a, block_b, block_ret],
|
||||
BasicBlockId::new(0),
|
||||
"selfcheck_multi_pred_return_mismatch",
|
||||
"selfcheck_mod3p8",
|
||||
);
|
||||
assert_release_counts_in_blocks(
|
||||
module,
|
||||
"selfcheck_multi_pred_return_mismatch",
|
||||
0, // 全体で0(join stateを作らないのでcleanupなし)
|
||||
&[
|
||||
(BasicBlockId::new(0), 0), // Jump block: cleanup禁止
|
||||
(BasicBlockId::new(1), 0), // Jump block: cleanup禁止
|
||||
(BasicBlockId::new(2), 0), // Return block: state不一致 → join失敗
|
||||
],
|
||||
"multi_pred_return_mismatch",
|
||||
);
|
||||
|
||||
// Case 4: Jump terminator should NOT inject block-end cleanup (unsafe cross-block)
|
||||
let ptr = ValueId::new(400);
|
||||
let v1 = ValueId::new(30);
|
||||
|
||||
Reference in New Issue
Block a user