refactor(edgecfg): add Frag/ExitKind API entrypoint (Phase 264 design-first)
Phase 264 P0: EdgeCFG Fragment 入口API作成(実装置換なし) - 入口フォルダ作成: src/mir/builder/control_flow/edgecfg/api/ - コア型定義: ExitKind, EdgeStub, Frag - 合成関数シグネチャ: seq, if_, loop_, cleanup(中身TODO、pub(crate)) - 最小テスト: 3個のユニットテスト追加(frag.rs) - ドキュメント連動: edgecfg-fragments.md に実装入口追記 制約遵守: - 既存 pattern6/7/8 未改変 - merge/EdgeCFG 未改変 - 既存LoopId使用(control_form.rs に PartialOrd, Ord 追加) - MIR側EdgeArgs使用(JoinIRと混線回避) - BTreeMap採用(決定的順序保証、Phase 69-3 教訓) 次フェーズ: Phase 265 で Pattern8 適用時に compose::loop_ を実装 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
142
docs/development/current/main/design/edgecfg-fragments.md
Normal file
142
docs/development/current/main/design/edgecfg-fragments.md
Normal file
@ -0,0 +1,142 @@
|
||||
# EdgeCFG Flow Fragments(Frag / ExitKind)— Structured→CFG lowering SSOT
|
||||
|
||||
Status: Draft(design SSOT candidate)
|
||||
Last updated: 2025-12-21
|
||||
|
||||
Related:
|
||||
- North star(CFG/ABI): `docs/development/current/main/design/join-explicit-cfg-construction.md`
|
||||
- Catch/Cleanup/Async: `docs/development/current/main/design/exception-cleanup-async.md`
|
||||
|
||||
## 目的(なぜ必要?)
|
||||
|
||||
EdgeCFG(block-parameterized CFG / edge-args SSOT)が固まると、次に残る “泥沼” はここだけになる:
|
||||
|
||||
- **構造化制御(if/loop + catch/cleanup)→ CFG** の lowering で起きる **exit 配線問題**
|
||||
- 「pattern番号で推測分岐」が増殖しやすい領域(長期的には消したい)
|
||||
|
||||
この文書は「pattern番号の列挙」を設計の中心にしないために、Structured→CFG の lowering を
|
||||
**合成代数(fragment composition)**として SSOT 化する。
|
||||
|
||||
結論(本書の北極星):
|
||||
|
||||
- “分岐の中心” は pattern番号ではなく **ExitKind** と **Frag(fragment)** に置く
|
||||
- 値の合流は EdgeCFG の **block params + edge-args** で表し、PHI/推測/メタに逃げない
|
||||
- pattern は「Extractor(形の認識)/ Plan(最小要件の抽出)」までに縮退し、merge/配線層へ逆流させない
|
||||
|
||||
## “フロー” は 2 層ある(混ぜると崩れる)
|
||||
|
||||
1. **CFG層(EdgeCFG / plumbing)**
|
||||
- terminator 語彙: `Jump/Branch/Return/Invoke`
|
||||
- edge-args: terminator operand が SSOT
|
||||
- out_edges の参照点が SSOT(複数 edge 前提)
|
||||
|
||||
2. **Structured→CFG lowering 層(flow composition)**
|
||||
- `if/loop/catch/cleanup/seq` を “Frag の合成” として書く
|
||||
- 難しさの本体は **exit(脱出)の種類** と **ネスト** と **合流**
|
||||
|
||||
## コア概念(最小の強い箱)
|
||||
|
||||
### ExitKind(脱出の種類を一次概念にする)
|
||||
|
||||
最低限の ExitKind:
|
||||
|
||||
- `Normal`(fallthrough)
|
||||
- `Break(loop_id)` / `Continue(loop_id)`
|
||||
- `Return`
|
||||
- `Unwind`(Invoke.err / catch へ)
|
||||
- `Cancel`(async の drop/cancel 用。今は予約)
|
||||
|
||||
### EdgeStub(未配線の脱出エッジ)
|
||||
|
||||
“どこへ飛ぶべきか未確定” な edge を表す。最終的に EdgeCFG の terminator edge に落ちる。
|
||||
|
||||
例(概念):
|
||||
|
||||
- `from: BlockId`
|
||||
- `kind: ExitKind`
|
||||
- `args: EdgeArgs`(ターゲット params に対応する値。target が未確定でも “役割” はここで決める)
|
||||
|
||||
### Frag(fragment)
|
||||
|
||||
```text
|
||||
Frag = { entry_block, exits: Map<ExitKind, Vec<EdgeStub>> }
|
||||
```
|
||||
|
||||
- `entry_block`: 断片の入口
|
||||
- `exits`: 断片から外へ出る未配線 edge の集合
|
||||
|
||||
## 合成則(pattern列挙を写像へ落とす)
|
||||
|
||||
### seq(a, b)
|
||||
|
||||
- `a.exits[Normal]` を `b.entry` へ接続する(edge-args を必要に応じて写像)
|
||||
- それ以外の exit は上位へ伝搬する
|
||||
|
||||
### if(cond, t, e)
|
||||
|
||||
- header に `Branch(cond, t.entry, e.entry)` を置く
|
||||
- `t.Normal` と `e.Normal` は join へ集める(必要なら join block params を作る)
|
||||
- `Break/Continue/Return/Unwind` は上位へ伝搬
|
||||
|
||||
### loop(body)
|
||||
|
||||
- header / latch / after を組み、`Continue` を header に戻す
|
||||
- `Break` を after へ出す
|
||||
- `Return/Unwind` は上位へ伝搬
|
||||
|
||||
### cleanup(body, cleanup_block)(finally の後継)
|
||||
|
||||
狙い: “脱出 edge 正規化”
|
||||
|
||||
- body の全 exit(Normal/Break/Continue/Return/Unwind/Cancel)を cleanup 経由へリライトする
|
||||
- cleanup 後に “元の exit” を再発射する(ExitTag + payload を block params で運ぶ)
|
||||
|
||||
重要: 例外 edge(Invoke.err)も漏れなく cleanup に寄せる。
|
||||
|
||||
## pattern は最終的に消える?(設計としての答え)
|
||||
|
||||
消える(実装の中心概念から降格する)。
|
||||
|
||||
- pattern番号は **回帰テスト名/症状ラベル**としては残して良い
|
||||
- 実装の中心は `Frag/ExitKind/join(block params)` の合成則になる
|
||||
- 各 pattern 実装は “Extractor(形の認識)→ Frag 合成呼び出し” の薄い層へ縮退する
|
||||
|
||||
## 実装の入口(SSOT API を先に作る)
|
||||
|
||||
目的: “どこを触ればいいか” を 1 箇所に固定し、推測・部分続行・場当たり分岐を減らす。
|
||||
|
||||
推奨の入口:
|
||||
|
||||
- `EdgeCFG` の plumbing API(既存): `BasicBlock::out_edges()` 等
|
||||
- Structured→CFG の入口 API(新規): `Frag` / `ExitKind` / `compose::{seq, if_, loop_ , cleanup}` 等
|
||||
|
||||
物理配置(案):
|
||||
|
||||
- `src/mir/builder/control_flow/edgecfg/api/`(または `.../joinir/api/` に併設してもよい)
|
||||
- `frag.rs` / `exit_kind.rs` / `compose.rs` / `patch.rs`
|
||||
|
||||
## verify(Fail-Fast の置き場所)
|
||||
|
||||
- **NormalizeBox 直後**: terminator 語彙固定・edge-args 長さ一致・cond付きJump禁止など “意味SSOT” を確定
|
||||
- **merge直前**: boundary/ABI/edge-args の矛盾を即死させ “配線SSOT” を確定
|
||||
- **--verify**: PHI predecessor / CFG cache 整合 / edge-args の長さ一致を常設
|
||||
|
||||
## 直近の導入ステップ(最小で始める)
|
||||
|
||||
1. `Frag/ExitKind/EdgeStub` の型を追加(docs+code 入口 SSOT)
|
||||
2. `seq/if/loop` の合成だけ実装(cleanup/Invoke は後段)
|
||||
3. 既存 pattern のうち 1 本だけ `Frag` 合成に寄せる(Pattern8 推奨)
|
||||
4. 2 本目で再利用が見えたら "pattern番号での枝刈り" を削って合成側へ寄せる
|
||||
|
||||
## 実装入口(コード SSOT)
|
||||
|
||||
**Phase 264 で入口API を作成完了**
|
||||
|
||||
- 物理配置: `src/mir/builder/control_flow/edgecfg/api/`
|
||||
- コア型: `ExitKind`, `EdgeStub`, `Frag`
|
||||
- 合成関数: `seq`, `if_`, `loop_`, `cleanup`(シグネチャのみ、中身TODO)
|
||||
- 検証: `verify_frag_invariants`(空実装)
|
||||
|
||||
次フェーズ(Phase 265+)で既存 pattern への適用を開始。
|
||||
現時点では既存 pattern6/7/8 や merge/EdgeCFG は未改変(入口だけ用意)。
|
||||
|
||||
Reference in New Issue
Block a user