From d3cf73f2ae8b7c4bd7b6dc582322ac26f1ccd397 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sun, 28 Dec 2025 05:59:22 +0900 Subject: [PATCH] phase29aa(p7): deterministic ReleaseStrong values ordering --- docs/development/current/main/10-Now.md | 6 ++- .../current/main/phases/phase-29aa/README.md | 5 +- src/bin/rc_insertion_selfcheck.rs | 47 +++++++++++++++++++ src/mir/passes/rc_insertion.rs | 21 +++++---- 4 files changed, 66 insertions(+), 13 deletions(-) diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index acf566ba..1f5a932e 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -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 のみ) diff --git a/docs/development/current/main/phases/phase-29aa/README.md b/docs/development/current/main/phases/phase-29aa/README.md index 64c594df..6e96f4ca 100644 --- a/docs/development/current/main/phases/phase-29aa/README.md +++ b/docs/development/current/main/phases/phase-29aa/README.md @@ -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) diff --git a/src/bin/rc_insertion_selfcheck.rs b/src/bin/rc_insertion_selfcheck.rs index 5cd604d4..eb0688ff 100644 --- a/src/bin/rc_insertion_selfcheck.rs +++ b/src/bin/rc_insertion_selfcheck.rs @@ -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); + } + } + } + } + } +} diff --git a/src/mir/passes/rc_insertion.rs b/src/mir/passes/rc_insertion.rs index 27374bed..6383ce72 100644 --- a/src/mir/passes/rc_insertion.rs +++ b/src/mir/passes/rc_insertion.rs @@ -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 = { - 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 = 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) -> Vec { + values.sort_unstable(); + values.dedup(); + values +} + #[cfg(feature = "rc-insertion-minimal")] fn apply_rc_plan( insts: Vec, @@ -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;