phase29aa(p7): deterministic ReleaseStrong values ordering

This commit is contained in:
2025-12-28 05:59:22 +09:00
parent ec1a84c465
commit d3cf73f2ae
4 changed files with 66 additions and 13 deletions

View File

@ -17,9 +17,13 @@
- Selfcheck: Case 3.9部分一致→cleanup/ Case 3.10intersection空→no cleanupPASS
- 検証: 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.11values が昇順であることを検証PASS
- 検証: quick 154/154 PASS / selfcheck PASS
**2025-12-27: Phase 29aa P4 完了**
- 目的: Jump の直列チェーン(単一 predecessorを通して ReturnCleanup を成立させるcleanup は Return block のみ)

View File

@ -1,6 +1,6 @@
# Phase 29aa: RC insertion safety expansionCFG-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 = v1PASS
- selfcheck Case 3.10intersection 空 → 全ブロック 0 cleanupPASS
- selfcheck Case 3.11values が昇順であることを検証PASS
- 既定OFF維持featureなしは no-op

View File

@ -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);
}
}
}
}
}
}

View File

@ -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;