phase29af(p4): layout consistency fail-fast

This commit is contained in:
2025-12-29 05:59:01 +09:00
parent 87fbe6b950
commit 7d2967cfbf
10 changed files with 135 additions and 63 deletions

View File

@ -2,7 +2,10 @@
## Current Focus: Phase 29afBoundary Hygiene SSOT 固定)
Next: `docs/development/current/main/phases/phase-29af/P4-LAYOUT-CONSISTENCY-CONTRACT-INSTRUCTIONS.md`
**2025-12-29: Phase 29af P4 完了**
- 目的: BoundaryCarrierLayout と header PHI の同順一致を strict/dev で Fail-Fast 固定(仕様不変)
- 入口: `src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs`
- 検証: `cargo build --release` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` / `./tools/smokes/v2/run.sh --profile quick` PASS
**2025-12-29: Phase 29af P3 完了**
- 目的: carrier の順序loop_var + carriersを merge 側 SSOT に統合(仕様不変)

View File

@ -8,7 +8,7 @@ Related:
## 直近JoinIR/selfhost
- **Phase 29af✅ P0P3 COMPLETE, Next: P4: Boundary hygiene / regression entrypoint / carrier layout SSOT**
- **Phase 29af✅ P0P4 COMPLETE: Boundary hygiene / regression entrypoint / carrier layout SSOT**
- 入口: `docs/development/current/main/phases/phase-29af/README.md`
- **Phase 29ae P1✅ COMPLETE: JoinIR Regression Pack (SSOT固定)**

View File

@ -1,62 +1,36 @@
# Phase 29af P4: Layout Consistency Contract — Instructions
Status: Ready for execution
Scope: carrier layout / header PHI の順序整合を Fail-Fast で固定(仕様不変)
Scope: BoundaryCarrierLayout と LoopHeaderPhiInfo::carrier_order の整合を Fail-Fast で固定(仕様不変)
## Goal
Phase 29af P3 で導入した `BoundaryCarrierLayout`order SSOTと、merge が生成する header PHI 側の order がズレた場合に、
JoinIR merge の入口で fail-fast できる状態にする。
- “BTreeMapの反復順” などの偶然に依存して順序が崩れたとき、即時に検知できる
- Pattern2/6/7/phase1883 の回帰パックを壊さず、将来の refactor を安全にする
BoundaryCarrierLayout と header PHI の順序がズレたときに、merge 入口で早期に検知する。
## Non-goals
- 既定挙動変更release 既定では挙動不変
- 挙動変更release 既定挙動の変更
- env var の追加
- ループ仕様の拡張PHI/edge_args の新設など)
## SSOT
- Carrier order SSOT: `src/mir/builder/control_flow/joinir/merge/boundary_carrier_layout.rs`
- Header PHI Entry/Latch contract: `docs/development/current/main/phases/phase-29ae/README.md`
- fixture/smoke の増加
## Implementation Steps
### Step 1: Boundary の “layout長” を実質的なチェックに強化
1) contract_checks にレイアウト整合性チェックを追加
- `src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs`
- boundary の順序と header PHI の順序が一致することを strict/dev で検証
対象: `src/mir/builder/control_flow/joinir/merge/contract_checks/boundary_hygiene.rs`
2) merge 入口でチェックを呼ぶ
- `src/mir/builder/control_flow/joinir/merge/coordinator.rs`
- prebuild_header_phis の直後で `verify_header_phi_layout(...)` を呼ぶ
`carrier_info` があるとき:
3) boundary_hygiene を強化
- `src/mir/builder/control_flow/joinir/merge/contract_checks/boundary_hygiene.rs`
- carrier_info の順序と BoundaryCarrierLayout の順序が同名同順で一致することを検証
- `boundary.loop_var_name == Some(carrier_info.loop_var_name)` を要求(名前不整合を fail-fast
- `BoundaryCarrierLayout::from_boundary(boundary).ordered_names()`
`["loop_var", ...carrier_info.carriers]`**同名同順** で一致することを要求
- `boundary.join_inputs.len() == boundary.host_inputs.len() == layout.len()` を要求
- 注: host_inputs の中身ValueId(0) placeholderは問わないSkipBinding があるため)
実行条件は既存と同じ(`joinir_strict` または `joinir_dev` のみ)。
### Step 2: Header PHI 側の order と BoundaryCarrierLayout を突合して fail-fast
新規チェック(案):
- `src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs`
- `verify_header_phi_layout(boundary: &JoinInlineBoundary, info: &LoopHeaderPhiInfo) -> Result<(), String>`
- `BoundaryCarrierLayout``ordered_names()``info.carrier_order` が一致することを要求
呼び出し場所(案):
- `src/mir/builder/control_flow/joinir/merge/coordinator.rs`
- `prebuild_header_phis` 後、rewrite/merge の前info が確定した直後)
### Step 3: docs 更新(迷子防止)
- `docs/development/current/main/phases/phase-29af/README.md`
- P4 として “order consistency contract” を追記し、入口ファイルを列挙
- `docs/development/current/main/10-Now.md`
- 次にやる P4 のリンクを追記
- `docs/development/current/main/30-Backlog.md`
- Phase 29af の “Next: P4” を追記
4) docs 更新
- `docs/development/current/main/phases/phase-29af/README.md`
- `docs/development/current/main/10-Now.md`
- `docs/development/current/main/30-Backlog.md`
## Verification
@ -66,6 +40,6 @@ JoinIR merge の入口で fail-fast できる状態にする。
## Acceptance Criteria
- strict/dev を有効にしたときのみ新しい fail-fast が働くrelease 既定挙動は不変)
- order mismatch を意図的に作ると、P4 の tag で freeze する(診断が安定
- 回帰パックphase29ae entrypointが PASS のまま
- strict/dev でズレを Fail-Fast できる
- quick 154/154 PASS不変
- JoinIR regression pack が PASS

View File

@ -0,0 +1,46 @@
# Phase 29af P5: Closeout — Instructions
Status: Ready for execution
Scope: Phase 29af の成果boundary hygiene / regression entrypoint / layout SSOT / consistency contractを締める仕様不変
## Goal
Phase 29af (P0P4) の SSOT と contract を “入口が迷わない状態” に確定し、JoinIR 側の回帰確認導線を固定する。
## Non-goals
- 挙動変更release 既定挙動の変更)
- env var の追加
- fixture/smoke の増加(回帰パックは既存を使う)
## Deliverables
1) Phase 29af README を “Complete” にする
- `docs/development/current/main/phases/phase-29af/README.md`
- Status: P0P4 complete
- Next: noneまたは次フェーズへのリンク
- Verification は `phase29ae_regression_pack_vm.sh` 1本に収束
2) Now/Backlog を 29af 完了へ更新
- `docs/development/current/main/10-Now.md`
- Current Focus: Phase 29af complete
- JoinIR 回帰確認のSSOT: `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
- `docs/development/current/main/30-Backlog.md`
- Phase 29af: ✅ COMPLETE
- 次の候補(例)を 1 行で明記Phase 29ag など)
3) Command SSOT の二重化を解消
- `docs/development/current/main/phases/phase-29ae/README.md`
- Commands: entrypoint script 1本のみ
## Verification
- `cargo build --release`
- `./tools/smokes/v2/run.sh --profile quick`
- `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
## Acceptance Criteria
- JoinIR 回帰確認が “1コマンド” で PASS
- quick が 154/154 PASS不変
- 29af の入口ドキュメントだけ見れば “どこを見れば良いか” が分かる

View File

@ -8,6 +8,7 @@ Goal: Pattern2 の boundary 情報の歪みを SSOT で整理し、将来の回
- P1: ✅ COMPLETEmerge `contract_checks` への集約)
- P2: ✅ COMPLETEJoinIR 回帰パックを 1 コマンドに収束)
- P3: ✅ COMPLETEBoundaryCarrierLayout SSOT
- P4: ✅ COMPLETElayout consistency contract
## Boundary Contract (SSOT)
@ -50,13 +51,18 @@ carrier の順序loop_var + carriersを merge 側の SSOT に統合する
- SSOT: `src/mir/builder/control_flow/joinir/merge/boundary_carrier_layout.rs`
- 適用: tail_call_policy / latch_incoming_recorder の order 統一
- contract_checks: `phase29af/boundary_hygiene/layout_len`strict/dev のみ)
- contract_checks: `phase29af/boundary_hygiene/layout_order`strict/dev のみ)
## P4: Layout Consistency ContractNext
## P4: Layout Consistency Contract
BoundaryCarrierLayout と header PHI 側の order を突合して、順序のズレを入口で fail-fast できる状態にする(仕様不変)。
BoundaryCarrierLayout と header PHI の順序一致を strict/dev で検証する(仕様不変)。
- 指示書: `docs/development/current/main/phases/phase-29af/P4-LAYOUT-CONSISTENCY-CONTRACT-INSTRUCTIONS.md`
- contract_checks: `src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs`
- 配線: `src/mir/builder/control_flow/joinir/merge/coordinator.rs`
## P5: CloseoutNext
P0P4 の SSOT/contract を確定し、入口README/Now/Backlogを締める。
## Verification

View File

@ -42,7 +42,4 @@ impl BoundaryCarrierLayout {
self.ordered_names.iter().position(|n| n == name)
}
pub fn len(&self) -> usize {
self.ordered_names.len()
}
}

View File

@ -38,17 +38,19 @@ pub(in crate::mir::builder::control_flow::joinir::merge) fn verify_boundary_hygi
}
if let Some(carrier_info) = &boundary.carrier_info {
let expected_len =
carrier_info.carriers.len() + if boundary.loop_var_name.is_some() { 1 } else { 0 };
let layout_len = BoundaryCarrierLayout::from_boundary(boundary).len();
if expected_len != layout_len {
let expected_names: Vec<&str> = std::iter::once(carrier_info.loop_var_name.as_str())
.chain(carrier_info.carriers.iter().map(|c| c.name.as_str()))
.collect();
let layout = BoundaryCarrierLayout::from_boundary(boundary);
let layout_names = layout.ordered_names();
if expected_names != layout_names {
return Err(error_tags::freeze_with_hint(
"phase29af/boundary_hygiene/layout_len",
"phase29af/boundary_hygiene/layout_order",
&format!(
"boundary carrier layout len {} does not match carrier_info len {}",
layout_len, expected_len
"boundary carrier order {:?} does not match carrier_info order {:?}",
layout_names, expected_names
),
"ensure loop_var + carriers ordering is consistent with carrier_info",
"ensure boundary carrier order matches carrier_info",
));
}

View File

@ -0,0 +1,39 @@
use crate::mir::builder::control_flow::joinir::merge::boundary_carrier_layout::BoundaryCarrierLayout;
use crate::mir::builder::control_flow::joinir::merge::loop_header_phi_info::LoopHeaderPhiInfo;
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
/// Phase 29af P4: Verify boundary carrier order matches header PHI order.
pub(in crate::mir::builder::control_flow::joinir::merge) fn verify_header_phi_layout(
boundary: &JoinInlineBoundary,
loop_header_phi_info: &LoopHeaderPhiInfo,
) -> Result<(), String> {
use crate::mir::join_ir::lowering::error_tags;
let strict = crate::config::env::joinir_strict_enabled()
|| crate::config::env::joinir_dev_enabled();
if !strict {
return Ok(());
}
let boundary_layout = BoundaryCarrierLayout::from_boundary(boundary);
let boundary_names = boundary_layout.ordered_names();
let header_names: Vec<&str> = loop_header_phi_info
.carrier_order
.iter()
.map(|name| name.as_str())
.collect();
if boundary_names != header_names {
return Err(error_tags::freeze_with_hint(
"phase29af/layout/header_phi_order",
&format!(
"boundary carrier order {:?} does not match header PHI order {:?}",
boundary_names, header_names
),
"ensure boundary carrier layout matches header PHI construction order",
));
}
Ok(())
}

View File

@ -15,6 +15,7 @@ mod exit_bindings;
mod carrier_inputs;
mod boundary_creation;
mod boundary_hygiene;
mod header_phi_layout;
mod entry_params;
mod entry_like_policy;
@ -23,6 +24,7 @@ pub(super) use terminator_targets::verify_all_terminator_targets_exist;
pub(super) use exit_bindings::verify_exit_bindings_have_exit_phis;
pub(super) use carrier_inputs::verify_carrier_inputs_complete;
pub(super) use boundary_hygiene::verify_boundary_hygiene;
pub(super) use header_phi_layout::verify_header_phi_layout;
pub(super) use entry_like_policy::is_entry_like_source;
pub(in crate::mir::builder::control_flow::joinir) use boundary_creation::verify_boundary_contract_at_creation;
pub(in crate::mir::builder::control_flow::joinir) use entry_params::run_all_pipeline_checks;

View File

@ -224,6 +224,9 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
&function_params,
debug,
)?;
if let Some(boundary) = boundary {
contract_checks::verify_header_phi_layout(boundary, &loop_header_phi_info)?;
}
// Phase 3: Remap ValueIds (with reserved PHI dsts protection)
// Phase 287 P0.2: Delegated to value_remapper module