phase29aa(p7): deterministic ReleaseStrong values ordering
This commit is contained in:
@ -17,9 +17,13 @@
|
||||
- Selfcheck: Case 3.9(部分一致→cleanup)/ Case 3.10(intersection空→no cleanup)PASS
|
||||
- 検証: quick 154/154 PASS / selfcheck PASS
|
||||
|
||||
**2025-12-28: Phase 29aa P7 進行中**
|
||||
**2025-12-28: Phase 29aa P7 完了** ✅
|
||||
- 目的: ReleaseStrong の `values` 順序を決定的にする(HashSet/HashMap 由来の非決定性排除)
|
||||
- 入口: `docs/development/current/main/phases/phase-29aa/README.md`
|
||||
- Contract: `sort_unstable()` + `dedup()` で ValueId 昇順に固定
|
||||
- ヘルパー関数 `sorted_release_values` で全 ReleaseStrong 生成箇所(2箇所)を統一
|
||||
- Selfcheck: Case 3.11(values が昇順であることを検証)PASS
|
||||
- 検証: quick 154/154 PASS / selfcheck PASS
|
||||
|
||||
**2025-12-27: Phase 29aa P4 完了** ✅
|
||||
- 目的: Jump の直列チェーン(単一 predecessor)を通して ReturnCleanup を成立させる(cleanup は Return block のみ)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Phase 29aa: RC insertion safety expansion(CFG-aware design)
|
||||
|
||||
Status: P7 Ready (Deterministic ReleaseStrong ordering)
|
||||
Status: P7 Complete (Deterministic ReleaseStrong ordering)
|
||||
Scope: Phase 29z の単一block限定実装から、誤releaseを起こさない形で CFG-aware に拡張するための設計を固める。
|
||||
|
||||
Entry:
|
||||
@ -108,6 +108,5 @@ P7 SSOT:
|
||||
- Acceptance:
|
||||
- quick 154/154 PASS 維持
|
||||
- `cargo run --bin rc_insertion_selfcheck --features rc-insertion-minimal` PASS
|
||||
- selfcheck Case 3.9(部分一致 → Return block に 1 cleanup、intersection = v1)PASS
|
||||
- selfcheck Case 3.10(intersection 空 → 全ブロック 0 cleanup)PASS
|
||||
- selfcheck Case 3.11(values が昇順であることを検証)PASS
|
||||
- 既定OFF維持(featureなしは no-op)
|
||||
|
||||
@ -527,5 +527,52 @@ fn main() {
|
||||
"branch_no_cleanup",
|
||||
);
|
||||
|
||||
// Case 3.11: ReleaseStrong values are sorted (deterministic ordering)
|
||||
// P7: 複数 ptr に異なる順序で store し、ReturnCleanup の values が昇順になることを検証
|
||||
let ptr1 = ValueId::new(3111);
|
||||
let ptr2 = ValueId::new(3112);
|
||||
let v_high = ValueId::new(100); // 大きい index
|
||||
let v_low = ValueId::new(50); // 小さい index
|
||||
|
||||
let mut block = BasicBlock::new(BasicBlockId::new(0));
|
||||
block.instructions = vec![
|
||||
MirInstruction::Store { value: v_high, ptr: ptr1 }, // 先に v100 を store
|
||||
MirInstruction::Store { value: v_low, ptr: ptr2 }, // 後に v50 を store
|
||||
];
|
||||
block.instruction_spans = vec![Span::unknown(), Span::unknown()];
|
||||
block.terminator = Some(MirInstruction::Return { value: None });
|
||||
block.terminator_span = Some(Span::unknown());
|
||||
let entry = block.id;
|
||||
let module = build_module_with_block(block, "selfcheck_sorted_values", "selfcheck_mod3p11");
|
||||
|
||||
// 関数全体の ReleaseStrong が昇順であることを検証
|
||||
assert_release_inserted(module.clone(), "selfcheck_sorted_values", entry, 1, "sorted_values_count");
|
||||
assert_all_release_values_sorted(module, "selfcheck_sorted_values", "sorted_values_order");
|
||||
|
||||
println!("[PASS] rc_insertion_selfcheck");
|
||||
}
|
||||
|
||||
fn assert_all_release_values_sorted(
|
||||
mut module: MirModule,
|
||||
func_name: &str,
|
||||
label: &str,
|
||||
) {
|
||||
let _stats = insert_rc_instructions(&mut module);
|
||||
let func = module.get_function(func_name).expect("function exists");
|
||||
|
||||
for (bid, bb) in &func.blocks {
|
||||
for inst in &bb.instructions {
|
||||
if let MirInstruction::ReleaseStrong { values } = inst {
|
||||
for window in values.windows(2) {
|
||||
if window[0] > window[1] {
|
||||
eprintln!(
|
||||
"[FAIL] {}: block {:?} values not sorted: {:?} > {:?}",
|
||||
label, bid, window[0], window[1]
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,13 +429,8 @@ fn plan_rc_insertion_for_block(
|
||||
}
|
||||
|
||||
if matches!(terminator, Some(MirInstruction::Return { .. })) && !ptr_to_value.is_empty() {
|
||||
let release_values: Vec<ValueId> = {
|
||||
let mut set = HashSet::new();
|
||||
for v in ptr_to_value.values() {
|
||||
set.insert(*v);
|
||||
}
|
||||
set.into_iter().collect()
|
||||
};
|
||||
// P7: HashSet 削除、sort+dedup は apply 側のヘルパーで処理される
|
||||
let release_values: Vec<ValueId> = ptr_to_value.values().copied().collect();
|
||||
if !release_values.is_empty() {
|
||||
plan.drops.push(DropSite {
|
||||
at: DropPoint::BeforeTerminator,
|
||||
@ -448,6 +443,14 @@ fn plan_rc_insertion_for_block(
|
||||
(plan, ptr_to_value)
|
||||
}
|
||||
|
||||
/// P7: ReleaseStrong の values を決定的順序(ValueId 昇順)にする
|
||||
#[cfg(feature = "rc-insertion-minimal")]
|
||||
fn sorted_release_values(mut values: Vec<ValueId>) -> Vec<ValueId> {
|
||||
values.sort_unstable();
|
||||
values.dedup();
|
||||
values
|
||||
}
|
||||
|
||||
#[cfg(feature = "rc-insertion-minimal")]
|
||||
fn apply_rc_plan(
|
||||
insts: Vec<MirInstruction>,
|
||||
@ -490,7 +493,7 @@ fn apply_rc_plan(
|
||||
for drop_site in drops_before_instr[idx].drain(..) {
|
||||
let _ = drop_site.reason;
|
||||
new_insts.push(MirInstruction::ReleaseStrong {
|
||||
values: drop_site.values,
|
||||
values: sorted_release_values(drop_site.values),
|
||||
});
|
||||
new_spans.push(span.clone());
|
||||
stats.release_inserted += 1;
|
||||
@ -510,7 +513,7 @@ fn apply_rc_plan(
|
||||
for drop_site in drops_before_terminator {
|
||||
let _ = drop_site.reason;
|
||||
new_insts.push(MirInstruction::ReleaseStrong {
|
||||
values: drop_site.values,
|
||||
values: sorted_release_values(drop_site.values),
|
||||
});
|
||||
new_spans.push(span.clone());
|
||||
stats.release_inserted += 1;
|
||||
|
||||
Reference in New Issue
Block a user