phase29ao(p8): ssot compose preserves edgeargs for valuejoin

This commit is contained in:
2025-12-30 05:51:55 +09:00
parent 0ad2a45383
commit 6a6276f3ac
8 changed files with 195 additions and 6 deletions

View File

@ -18,8 +18,8 @@ Scope: Repo root の旧リンク互換。現行の入口は `docs/development/cu
**CorePlan migration 道筋 SSOT**
`docs/development/current/main/design/coreplan-migration-roadmap-ssot.md` が移行タスクの Done 判定の入口。
**Next implementation (Phase 29ao P8)**
`docs/development/current/main/phases/phase-29ao/P8-VALUEJOIN-EDGEARGS-COMPOSE-PRESERVE-INSTRUCTIONS.md`
**Next implementation (Phase 29ao P9)**
`docs/development/current/main/phases/phase-29ao/README.md`
**2025-12-29: Phase 29am P0 COMPLETE (CorePlan If/Exit lowerer/verifier)**
CorePlan の If/Exit を lowerer/verifier で扱えるようにして、CorePlan 移行の土台を作った。

View File

@ -2,7 +2,7 @@
## Current Focus: Phase 29aoCorePlan composition
Next: Phase 29ao P8ValueJoin: EdgeArgs compose preservation SSOT
Next: Phase 29ao P9ValueJoin minimal wire
指示書: `docs/development/current/main/phases/phase-29ao/P8-VALUEJOIN-EDGEARGS-COMPOSE-PRESERVE-INSTRUCTIONS.md`
運用ルール: integration filter で phase143_* は回さないJoinIR 回帰は phase29ae pack のみ)
運用ルール: phase286_pattern9_* は legacy pack (SKIP) を使う
@ -48,6 +48,11 @@ Next: Phase 29ao P8ValueJoin: EdgeArgs compose preservation SSOT
- 変更: `src/mir/builder/control_flow/plan/normalizer/value_join_args.rs` / `src/mir/builder/control_flow/plan/normalizer/mod.rs` / `src/mir/builder/control_flow/plan/verifier.rs` / `docs/development/current/main/phases/phase-29ao/README.md` / `docs/development/current/main/10-Now.md` / `docs/development/current/main/30-Backlog.md` / `CURRENT_TASK.md`
- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
**2025-12-30: Phase 29ao P8 完了**
- 目的: compose::seq/if_/cleanup が EdgeArgs(layout+values) を保持することをテストで固定
- 変更: `src/mir/builder/control_flow/edgecfg/api/compose/seq.rs` / `src/mir/builder/control_flow/edgecfg/api/compose/if_.rs` / `src/mir/builder/control_flow/edgecfg/api/compose/cleanup.rs` / `docs/development/current/main/phases/phase-29ao/README.md` / `docs/development/current/main/10-Now.md` / `docs/development/current/main/30-Backlog.md` / `CURRENT_TASK.md`
- 検証: `cargo test --release -p nyash-rust` / `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
**2025-12-29: Phase 29an P15 完了**
- 目的: P0P14 の成果を closeout 形式でまとめ、次フェーズPhase 29ao入口を固定
- 変更: `docs/development/current/main/phases/phase-29an/README.md` / `docs/development/current/main/10-Now.md` / `docs/development/current/main/30-Backlog.md` / `CURRENT_TASK.md`

View File

@ -15,7 +15,7 @@ Related:
- **Phase 29aoactive: CorePlan composition from Skeleton/Feature**
- 入口: `docs/development/current/main/phases/phase-29ao/README.md`
- 状況: P0/P1/P2/P3/P4/P5/P6/P7 ✅ 完了 / Next: P8
- 状況: P0/P1/P2/P3/P4/P5/P6/P7/P8 ✅ 完了 / Next: P9
- Next 指示書: `docs/development/current/main/phases/phase-29ao/P8-VALUEJOIN-EDGEARGS-COMPOSE-PRESERVE-INSTRUCTIONS.md`
- **Phase 29af✅ COMPLETE: Boundary hygiene / regression entrypoint / carrier layout SSOT**

View File

@ -58,7 +58,11 @@ GateSSOT:
- 指示書: `docs/development/current/main/phases/phase-29ao/P7-VALUEJOIN-EDGEARGS-LAYOUT-VERIFY-INSTRUCTIONS.md`
- ねらい: `ExprResultPlusCarriers` の語彙と最小検証を PlanVerifier に追加(未接続)
## P8: compose が EdgeArgs を保持することの検証(仕様不変)✅
- 指示書: `docs/development/current/main/phases/phase-29ao/P8-VALUEJOIN-EDGEARGS-COMPOSE-PRESERVE-INSTRUCTIONS.md`
- ねらい: compose::seq/if_/cleanup が EdgeArgs(layout+values) を保持することをテストで固定
## Nextplanned
- P8: ValueJoin の前提固定compose が EdgeArgs を壊さないことをテストでSSOT化
- 指示書: `docs/development/current/main/phases/phase-29ao/P8-VALUEJOIN-EDGEARGS-COMPOSE-PRESERVE-INSTRUCTIONS.md`
- P9: ValueJoin の最小 wirestrict/dev Fail-Fast 付き

View File

@ -133,3 +133,47 @@ pub(crate) fn cleanup(
branches,
})
}
#[cfg(test)]
mod tests {
use super::cleanup;
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
use crate::mir::builder::control_flow::edgecfg::api::edge_stub::EdgeStub;
use crate::mir::builder::control_flow::edgecfg::api::exit_kind::ExitKind;
use crate::mir::builder::control_flow::edgecfg::api::frag::Frag;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::mir::ValueId;
use std::collections::BTreeMap;
#[test]
fn cleanup_preserves_edgeargs_for_return_exit() {
let main = Frag::new(BasicBlockId::new(1));
let cleanup_entry = BasicBlockId::new(2);
let args = EdgeArgs {
layout: JumpArgsLayout::ExprResultPlusCarriers,
values: vec![ValueId(30)],
};
let mut exits = BTreeMap::new();
exits.insert(
ExitKind::Return,
vec![EdgeStub {
from: cleanup_entry,
kind: ExitKind::Return,
target: None,
args: args.clone(),
}],
);
let cleanup_frag = Frag {
entry: cleanup_entry,
exits,
wires: vec![],
branches: vec![],
};
let composed =
cleanup(main, cleanup_frag, None, None).expect("cleanup ok");
assert_eq!(composed.wires.len(), 1);
assert_eq!(composed.wires[0].args, args);
assert!(composed.wires[0].target.is_none());
}
}

View File

@ -137,3 +137,93 @@ pub(crate) fn if_(
branches, // Phase 267 P0: header の BranchStub + t/e/join の branches
}
}
#[cfg(test)]
mod tests {
use super::if_;
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
use crate::mir::builder::control_flow::edgecfg::api::edge_stub::EdgeStub;
use crate::mir::builder::control_flow::edgecfg::api::exit_kind::ExitKind;
use crate::mir::builder::control_flow::edgecfg::api::frag::Frag;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::mir::value_id::ValueId;
use std::collections::BTreeMap;
#[test]
fn if_preserves_edgeargs_for_then_else_normal_exits() {
let header = BasicBlockId::new(1);
let then_entry = BasicBlockId::new(2);
let else_entry = BasicBlockId::new(3);
let join_entry = BasicBlockId::new(4);
let cond = ValueId(10);
let then_entry_args = EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: vec![],
};
let else_entry_args = EdgeArgs {
layout: JumpArgsLayout::CarriersOnly,
values: vec![],
};
let then_args = EdgeArgs {
layout: JumpArgsLayout::ExprResultPlusCarriers,
values: vec![ValueId(20)],
};
let else_args = EdgeArgs {
layout: JumpArgsLayout::ExprResultPlusCarriers,
values: vec![ValueId(21)],
};
let mut then_exits = BTreeMap::new();
then_exits.insert(
ExitKind::Normal,
vec![EdgeStub {
from: then_entry,
kind: ExitKind::Normal,
target: None,
args: then_args.clone(),
}],
);
let then_frag = Frag {
entry: then_entry,
exits: then_exits,
wires: vec![],
branches: vec![],
};
let mut else_exits = BTreeMap::new();
else_exits.insert(
ExitKind::Normal,
vec![EdgeStub {
from: else_entry,
kind: ExitKind::Normal,
target: None,
args: else_args.clone(),
}],
);
let else_frag = Frag {
entry: else_entry,
exits: else_exits,
wires: vec![],
branches: vec![],
};
let join_frag = Frag::new(join_entry);
let composed = if_(
header,
cond,
then_frag,
then_entry_args,
else_frag,
else_entry_args,
join_frag,
);
assert_eq!(composed.wires.len(), 2);
assert!(composed.wires.iter().any(|stub| {
stub.target == Some(join_entry) && stub.args == then_args
}));
assert!(composed.wires.iter().any(|stub| {
stub.target == Some(join_entry) && stub.args == else_args
}));
}
}

View File

@ -87,3 +87,44 @@ pub(crate) fn seq(a: Frag, b: Frag) -> Frag {
branches, // Phase 267 P0: a.branches + b.branches
}
}
#[cfg(test)]
mod tests {
use super::seq;
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
use crate::mir::builder::control_flow::edgecfg::api::edge_stub::EdgeStub;
use crate::mir::builder::control_flow::edgecfg::api::exit_kind::ExitKind;
use crate::mir::builder::control_flow::edgecfg::api::frag::Frag;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::mir::ValueId;
use std::collections::BTreeMap;
#[test]
fn seq_preserves_edgeargs_for_normal_exit() {
let a_entry = BasicBlockId::new(1);
let b_entry = BasicBlockId::new(2);
let args = EdgeArgs {
layout: JumpArgsLayout::ExprResultPlusCarriers,
values: vec![ValueId(10)],
};
let stub = EdgeStub {
from: a_entry,
kind: ExitKind::Normal,
target: None,
args: args.clone(),
};
let mut exits = BTreeMap::new();
exits.insert(ExitKind::Normal, vec![stub]);
let a = Frag {
entry: a_entry,
exits,
wires: vec![],
branches: vec![],
};
let b = Frag::new(b_entry);
let composed = seq(a, b);
assert_eq!(composed.wires.len(), 1);
assert_eq!(composed.wires[0].target, Some(b_entry));
assert_eq!(composed.wires[0].args, args);
}
}

View File

@ -397,16 +397,21 @@ mod tests {
use crate::mir::basic_block::EdgeArgs;
use crate::mir::builder::control_flow::edgecfg::api::{EdgeStub, ExitKind, Frag};
use crate::mir::builder::control_flow::plan::CorePhiInfo;
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::facts::feature_facts::{
LoopFeatureFacts, ValueJoinFacts,
};
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::facts::loop_facts::LoopFacts;
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::facts::scan_shapes::{
ConditionShape, StepShape,
};
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::facts::skeleton_facts::{
SkeletonFacts, SkeletonKind,
};
#[cfg(debug_assertions)]
use crate::mir::builder::control_flow::plan::normalize::canonicalize_loop_facts;
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use std::collections::BTreeMap;