fix(joinir): stabilize Phase 256 merge (jump_args, DCE, func names)

This commit is contained in:
2025-12-20 11:01:48 +09:00
parent 2c4268b691
commit 1028bd419c
11 changed files with 499 additions and 50 deletions

View File

@ -0,0 +1,169 @@
# Phase 256: JoinIR Contract Questions (for ChatGPT Pro)
目的: Phase 256 の詰まりJump/continuation/params/jump_args の暗黙契約)を、設計として固めるための相談メモ。
---
## Q1. SSOT をどこに置くべき?
JoinIR の「意味論 SSOT」をどこに置くべきか。
- A) Structured JoinIR を SSOT として維持し、bridge/merge が意味解釈する
- B) Normalized JoinIR を SSOT とし、Structured→Normalized の正規化箱を必須化する
判断材料として、現在の層の境界と責務:
- Pattern lowererStructured JoinIR 生成)
- `join_ir_vm_bridge`JoinIR→MIR 変換)
- mergeMIR inline + PHI/ExitLine wiring
---
## Q2. `JoinInst::Jump` の正規形(不変条件)
現状の詰まりは `Jump` が層を跨ぐときに「tail call 等価」になったり「Return 化」になったりして、continuation が失われる点にある。
相談したい:
- `JoinInst::Jump { cont, args, cond }` を SSOT 的にどう定義するべきか?
- cond 付き Jump は JoinIR 語彙として残すべきか?それとも IfMerge に寄せるべきか?
最小コードJoinIR 命令):
```rust
// src/mir/join_ir/mod.rs
pub enum JoinInst {
// ...
Jump {
cont: JoinContId,
args: Vec<VarId>,
cond: Option<VarId>,
},
Call {
func: JoinFuncId,
args: Vec<VarId>,
dst: Option<VarId>,
k_next: Option<JoinContId>,
},
Ret { value: Option<VarId> },
// ...
}
```
---
## Q3. boundary/params/jump_args の順序契約をどこで固定する?
Phase 256 では、次の対応関係が暗黙で、崩れると SSA undef / PHI wiring fail-fast になりやすい。
- `JoinInlineBoundary.join_inputs``JoinModule.entry.params`
- `exit_bindings` ↔ ExitLine の carrier PHI reconnect
- `jump_args`tail call args metadata↔ ExitLine の latch incoming 復元
最小コードboundary:
```rust
// src/mir/join_ir/lowering/inline_boundary.rs
pub struct JoinInlineBoundary {
pub join_inputs: Vec<ValueId>,
pub host_inputs: Vec<ValueId>,
pub loop_invariants: Vec<(String, ValueId)>,
pub exit_bindings: Vec<LoopExitBinding>,
pub expr_result: Option<ValueId>,
pub loop_var_name: Option<String>,
pub continuation_func_ids: std::collections::BTreeSet<String>,
// ...
}
```
契約の fail-fast は現在ここで行っている:
```rust
// src/mir/builder/control_flow/joinir/merge/contract_checks.rs
pub(in crate::mir::builder::control_flow::joinir) fn run_all_pipeline_checks(
join_module: &crate::mir::join_ir::JoinModule,
boundary: &JoinInlineBoundary,
) -> Result<(), String> {
verify_boundary_entry_params(join_module, boundary)?;
// ...
Ok(())
}
```
相談したい:
- この順序契約は「boundary」「normalizer」「bridge」「merge」のどの層が SSOT になるべきか?
- fail-fast の責務をどこに置くべきか(今は conversion_pipeline 直前)?
---
## Q4. continuation の識別: `JoinFuncId` vs `String`(関数名)
Phase 256 P1.7 で「continuation 関数が merge で見つからず SSA undef」になった。
原因は bridge 側と merge 側の “関数名 SSOT” 不一致。
現状の暫定 SSOT は `canonical_names`:
```rust
// src/mir/join_ir/lowering/canonical_names.rs
pub const K_EXIT: &str = "k_exit";
pub const K_EXIT_LEGACY: &str = "join_func_2";
pub const LOOP_STEP: &str = "loop_step";
pub const MAIN: &str = "main";
```
相談したい:
- continuation を `JoinFuncId` で保持し、bridge で 1 回だけ名前解決するべきか?
- それとも `String` を SSOT にして “MirModule key” と一致させ続けるべきか?
- 併存するなら、変換境界(片方→片方)をどこに置くべきか?
---
## Q5. 正規化 shadow`join_func_N`)との共存戦略
normalized_shadow 側は `join_func_2` のような命名を使う箇所がある。
この legacy をいつ・どう統一するべきか(または統一しないなら境界をどう明文化するか)。
---
## Q6. `jump_args` は MIR のどの層の SSOT か?
観測:
- ExitLine/merge 側は `BasicBlock.jump_args` を「exit/carry 値の SSOT」として参照する。
- bridge 側で tail call / Jump を生成するときに `jump_args` を落とし忘れると、ExitLine が fallback 経路へ入りやすく、
SSA/dominance の破綻につながる。
最小コードMIR basic block:
```rust
// src/mir/mod.rs
pub struct BasicBlock {
pub instructions: Vec<MirInstruction>,
pub instruction_spans: Vec<Span>,
pub terminator: Option<MirInstruction>,
pub jump_args: Option<Vec<ValueId>>,
// ...
}
```
相談したい:
- `jump_args` は terminatorJump/Branch/Return/Callに埋め込むべきか、それとも BasicBlock の外部メタのままでよいか?
- `jump_args` の契約順序・長さ・expr_result の有無・invariants の混在)をどこで固定するべきか?
---
## Q7. Optimizer/DCE の不変条件spans 同期と jump_args
観測:
- DCE が `jump_args` だけで使われる値を “unused” とみなすと、Copy/Const が消えて merge が壊れる。
- DCE が `instructions` だけを削って `instruction_spans` を同期しないと、SPAN MISMATCH が発生しデバッグが困難になる。
相談したい:
- `jump_args` は “use” として扱うのが SSOT として正しいか?
- spans 同期は「各パスの責務」か、それとも `BasicBlock` の API例: spanned filterに閉じ込めるべきか
---
## 観測された失敗例(短く)
- SSA undef関数名不一致で continuation が merge 対象にならず到達不能/未定義が露出)
- ExitLine: `jump_args` の長さ契約ミスマッチcarriers と invariants の混在)
- `JoinInst::Jump` が bridge で “Return 化” され、continuation の意味が落ちる疑い
- DCE が `jump_args` 由来の use を落とし、Copy が消えて SSA/dominance が崩れる