feat(joinir): Phase 259 P0 complete - Pattern8 final fixes + docs (pre-block-params migration)
Phase 259 P0: Pattern8 (BoolPredicateScan) 完全完了 is_integer/1 を Pattern8 で受理し、VM/LLVM EXE 両方で動作確認完了。 次の大工事(block-parameterized CFG への移行)前のマイルストーンとして記録。 ## Key Fixes Applied 1. **skipped_entry_redirects** (instruction_rewriter.rs) - k_exit のスキップ時、entry block 参照を exit_block_id へリダイレクト - BasicBlockId not found エラーを根治 2. **loop_var_name** (pattern8_scan_bool_predicate.rs) - merge_entry_block 選択に使用(`Some(parts.loop_var.clone())`) - 未設定時の誤った entry block 選択を修正 3. **loop_invariants** (pattern8_scan_bool_predicate.rs) - PHI-free 不変量パラメータ(`[(me, me_host), (s, s_host)]`) - loop_var_name 設定時、BoundaryInjector が join_inputs Copy を全スキップするため必要 - Pattern6 と同じ設計(header PHI で不変量を保持) 4. **expr_result** (pattern8_scan_bool_predicate.rs) - k_exit からの返り値を明示設定(`Some(join_exit_value)`) - Pattern7 style(推測ではなく明示) 5. **Smoke test scripts** - set +e パターンで exit code 7 をキャプチャ - LLVM EXE スクリプトにコメント追加(tools/build_llvm.sh 経由の明記) ## Contract Documentation - join-explicit-cfg-construction.md に Pattern8 契約の具体例を追加 - "pattern増でも推測増にしない" の実例として記録 - loop_var_name / loop_invariants / expr_result / jump_args_layout の契約を明示 - 20-Decisions.md に正規化(Semantic/Plumbing)の分離方針を追記 - DOCS_LAYOUT.md に重要ドキュメントへの参照を追加 ## Test Results - ✅ VM smoke test: `[PASS] phase259_p0_is_integer_vm` (exit 7) - ✅ LLVM EXE: tools/build_llvm.sh 経由で exit 7 確認 - ✅ --verify: PASS ## Next FAIL (Phase 260+) - Function: `Main.main/0` in `apps/examples/json_lint/main.hako` - Error: `[cf_loop/pattern2] Failed to extract break condition from loop body` - Pattern: Nested loop(外側 loop + 内側 loop with break) 🚀 次の大工事: block-parameterized CFG への移行を開始します。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -3,13 +3,52 @@
|
||||
## Next (planned)
|
||||
|
||||
- Phase 259: `StringUtils.is_integer/1`(nested-if + loop)を JoinIR で受理して `--profile quick` を進める
|
||||
- Phase 260: block-parameterized CFG へ向けた “edge-args terminator 併存導入”(大工事 / Strangler)
|
||||
- Phase 259.x: Me receiver SSOT(`variable_map["me"]`)を API 化して `"this"`/`"me"` 混同を構造で潰す
|
||||
- Phase 141 P2+: Call/MethodCall 対応(effects + typing を分離して段階投入、ANF を前提に順序固定)
|
||||
- Phase 143-loopvocab P3+: 条件スコープ拡張(impure conditions 対応)
|
||||
- 詳細: `docs/development/current/main/30-Backlog.md`
|
||||
|
||||
## Phase 260(大工事)ロードマップ(要約)
|
||||
|
||||
- P0: edge-args を MIR terminator operand として **併存導入**(Branch を含むので参照点は `out_edges()` 系に一本化)
|
||||
- P1: terminator更新APIを一本化し、successors/preds 同期漏れを構造で潰す
|
||||
- P2: `BasicBlock.jump_args` を削除(terminator operand を SSOT 化)
|
||||
- P3: spans を `Vec<Spanned<_>>` に収束(段階導入)
|
||||
|
||||
## Current First FAIL (SSOT)
|
||||
|
||||
- `json_lint_vm / StringUtils.is_integer/1`(Phase 259)
|
||||
- **Before Phase 259 P0**: `json_lint_vm / StringUtils.is_integer/1`
|
||||
- **After Phase 259 P0**: `json_lint_vm / Main.main/0 nested-loop with break`
|
||||
|
||||
### Next FAIL Details
|
||||
|
||||
- **Test**: `json_lint_vm`
|
||||
- **Function**: `Main.main/0`
|
||||
- **Error**: `[cf_loop/pattern2] Failed to extract break condition from loop body`
|
||||
- **Pattern**: Nested loop(外側 `loop(i < cases.length())` 内で内側 `loop(j < valid.length())` + break)
|
||||
- **Reproduce**:
|
||||
```bash
|
||||
./target/release/hakorune --backend vm apps/examples/json_lint/main.hako
|
||||
```
|
||||
- **Note**: is_integer/1 自体は Pattern8 で解決済み。残りは nested-loop 処理の問題(Phase 260+)
|
||||
|
||||
## 2025-12-21:Phase 259 P0(Pattern8 BoolPredicateScan)✅
|
||||
|
||||
- Phase 259 README: `docs/development/current/main/phases/phase-259/README.md`
|
||||
- Result: `StringUtils.is_integer/1` を Pattern8(新規)で受理
|
||||
- Fixtures:
|
||||
- `apps/tests/phase259_p0_is_integer_min.hako`(expected exit 7)
|
||||
- Smokes:
|
||||
- `tools/smokes/v2/profiles/integration/apps/phase259_p0_is_integer_vm.sh` ✅ PASS
|
||||
- `tools/smokes/v2/profiles/integration/apps/phase259_p0_is_integer_llvm_exe.sh`(LLVM harness 要設定)
|
||||
- Key Implementation:
|
||||
- `src/mir/builder/control_flow/joinir/patterns/pattern8_scan_bool_predicate.rs`(新規)
|
||||
- `src/mir/join_ir/lowering/scan_bool_predicate_minimal.rs`(新規)
|
||||
- Design Decision: Pattern8 を新設(Pattern6 拡張ではなく分離)
|
||||
- Pattern6: "見つける" scan(返り値: Integer)
|
||||
- Pattern8: "全部検証する" predicate scan(返り値: Boolean)
|
||||
- Note: json_lint_vm はまだ FAIL だが、is_integer 自体は解決済み。残りは nested-loop with break パターン(Pattern2 の別問題)
|
||||
|
||||
## 2025-12-20:Phase 258(index_of_string/2 dynamic window scan)✅
|
||||
|
||||
|
||||
@ -15,6 +15,9 @@
|
||||
- continuation の識別は ID を SSOT(String は debug/serialize 用)とし、`join_func_N` の legacy は alias で隔離する。
|
||||
- `jump_args` は意味論の SSOT なので、最終的には MIR terminator operand に統合して DCE/CFG から自然に追える形へ収束させる(Phase 256 を緑に戻した後に段階導入)。
|
||||
- 上記の収束先(north star)を “Join-Explicit CFG Construction” と命名し、段階移行(案1→案2→必要なら案3)で進める。
|
||||
- 正規化(normalized)を **Semantic/Plumbing** に分離し、`NormalizeBox`(意味SSOT)/ `AbiBox`(役割SSOT)/ `EdgeArgsPlumbingBox`(配線SSOT)の最小セットで “推測禁止 + Fail-Fast” を維持する。
|
||||
- spans は並行 Vec を最終的に廃止し、`Vec<Spanned<_>>` へ収束(段階導入: 編集APIの一本化 → 内部表現切替)。
|
||||
- edge-args の参照 API は `Jump` だけでなく `Branch` を含むため、単発 `edge_args()` ではなく `out_edges()`/`edge_args_to(target)` のような “複数 edge” 前提の参照点を SSOT にする。
|
||||
|
||||
2025‑09‑08
|
||||
- ループ制御は既存命令(Branch/Jump/Phi)で表現し、新命令は導入しない。
|
||||
|
||||
@ -23,6 +23,8 @@ Scope: `docs/development/current/` 以下の「置き場所ルール」と、SSO
|
||||
|
||||
- 原則: Phase 依存のログ/作業記録は置かない(それは phases へ)。
|
||||
- 例: JoinIR の設計、Boundary/ExitLine の契約、Loop パターン空間、runtime/box 解決の地図。
|
||||
- よく参照する設計SSOT:
|
||||
- Join-Explicit CFG Construction(north star): `docs/development/current/main/design/join-explicit-cfg-construction.md`
|
||||
|
||||
### `docs/development/current/main/investigations/`(調査ログ)
|
||||
|
||||
@ -30,6 +32,8 @@ Scope: `docs/development/current/` 以下の「置き場所ルール」と、SSO
|
||||
|
||||
- 原則: “結論” は `10-Now.md` / `20-Decisions.md` / 該当 design doc に反映し、調査ログ自体は参照用に残す。
|
||||
- 原則: 調査ログを SSOT にしない(参照元を明記して“歴史化”できる形にする)。
|
||||
- よく参照する調査ログ:
|
||||
- Phase 259: block-parameterized CFG / ABI/contract 相談パケット: `docs/development/current/main/investigations/phase-259-block-parameterized-cfg-consult.md`
|
||||
|
||||
### `docs/development/current/main/phases/`(Phaseログ)
|
||||
|
||||
@ -78,4 +82,3 @@ Moved to: docs/development/current/main/phases/phase-131/131-03-llvm-lowering-in
|
||||
- 新しい Phase 文書は `main/phases/` に入れる(`main/` 直下に増やさない)。
|
||||
- 設計図(SSOT)は `main/design/` に寄せる(Phase の完了サマリと混ぜない)。
|
||||
- `10-Now.md` は「現状の要約+正本リンク」に徹し、詳細ログの本文は抱え込まない。
|
||||
|
||||
|
||||
@ -27,6 +27,45 @@ Related:
|
||||
- `jump_args` が IR の外側メタ扱いだと、DCE/最適化が “use” を見落としやすい
|
||||
- spans が並行 Vec だと、パスが 1 箇所でも取りこぼすと SPAN MISMATCH になる
|
||||
|
||||
## 方針の核(Phase 259+)
|
||||
|
||||
“正規化(normalized)” を 2 つに分けて SSOT を縮退させる:
|
||||
|
||||
1. **Semantic Normalization(意味SSOT)**
|
||||
- terminator 語彙を固定し、意味の揺れを禁止する
|
||||
- 例: `cond 付き Jump` を **正規形から禁止**し、`Branch` に落とす
|
||||
2. **Plumbing Normalization(配線SSOT)**
|
||||
- edge-args / CFG successor / spans など「壊れやすい配線」を IR 構造に閉じ込める
|
||||
- 目標: “忘れると壊れるメタ” を減らし、変換を写像に縮退させる
|
||||
|
||||
これにより、パターン追加が「意味SSOTに従う局所変更」になり、merge/optimizer 側の推測や補正が増殖しにくくなる。
|
||||
|
||||
### 具体例: Pattern8 契約(Phase 259 P0)
|
||||
|
||||
Pattern8(BoolPredicateScan)の実装で明示した契約要素("pattern増でも推測増にしない"の実例):
|
||||
|
||||
- **`loop_var_name`**: merge_entry_block 選択に使用(`Some(parts.loop_var.clone())`)
|
||||
- 未設定だと誤った entry block が選ばれる
|
||||
- **`loop_invariants`**: PHI-free 不変量パラメータ(`[(me, me_host), (s, s_host)]`)
|
||||
- `loop_var_name` 設定時、BoundaryInjector が ALL join_inputs Copy をスキップするため必要
|
||||
- 不変量は header PHI で持つ(Pattern6 と同じ設計)
|
||||
- **`expr_result`**: k_exit からの返り値を明示(`Some(join_exit_value)`)
|
||||
- Pattern7 style(推測ではなく明示設定)
|
||||
- **`jump_args_layout`**: ExprResultPlusCarriers(carriers=0)
|
||||
- Pattern8 は carriers なし、expr_result のみ
|
||||
- **`exit_bindings`**: Empty
|
||||
- carriers なしなので binding も不要
|
||||
|
||||
これらを「boundary builder で明示」することで、merge 側の推測を完全に排除。
|
||||
|
||||
## 最小の箱(Box)構成(小さく強く)
|
||||
|
||||
- `NormalizeBox`(意味SSOT): Structured → Normalized、terminator 語彙の固定、Fail-Fast verify
|
||||
- `AbiBox`(役割/順序SSOT): `JoinAbi`(sig/roles/special/alias)で暗黙 ABI を封印し、pack/unpack を一箇所に集約
|
||||
- `EdgeArgsPlumbingBox`(配線SSOT): edge-args を terminator operand に寄せる段階導入、CFG/spans の同期点を一本化
|
||||
|
||||
増やす基準: 同じ不変条件を 2 箇所以上で守り始めたら箱を追加し、参照点を 1 箇所に縮退させる。
|
||||
|
||||
## 移行戦略(段階導入 / Strangler)
|
||||
|
||||
原則:
|
||||
@ -38,7 +77,7 @@ Related:
|
||||
狙い: 推測をなくし、順序/役割の SSOT を 1 箇所へ寄せる。
|
||||
|
||||
- boundary に `jump_args_layout` のような **layout SSOT** を持たせ、collector/rewriter が推測しない
|
||||
- `JoinInst::Jump` を terminator 語彙として正規化(cond 付きは `Branch` へ寄せる)
|
||||
- terminator 語彙を固定し、`cond 付き Jump` を `Branch` へ寄せる(正規形から禁止)
|
||||
- continuation の識別は **ID SSOT**(String は debug/serialize のみに縮退)
|
||||
|
||||
受け入れ:
|
||||
@ -49,7 +88,11 @@ Related:
|
||||
|
||||
狙い: `jump_args` を “意味データ” として IR に埋め込み、DCE/CFG が自然に追える形へ収束する。
|
||||
|
||||
- `jump_args` を BasicBlock 外メタから terminator operand へ寄せる(段階導入: 互換フィールド併存→移行)
|
||||
- `jump_args` を BasicBlock メタから terminator operand へ寄せる(段階導入: 互換フィールド併存→移行→削除)
|
||||
- “参照 API” は Branch を含むので **複数 edge を前提**にする(単発 `edge_args()` は曖昧になりやすい)
|
||||
- 例: `block.out_edges()` / `block.edge_args_to(target)`
|
||||
- terminator operand 側は `Vec<ValueId>` だけでなく **意味(layout)**も同梱する
|
||||
- 例: `EdgeArgs { layout: JumpArgsLayout, values: Vec<ValueId> }`
|
||||
- spans は `Vec<Spanned<_>>` へ(API で不変条件を守る)
|
||||
|
||||
受け入れ:
|
||||
@ -66,3 +109,15 @@ Related:
|
||||
|
||||
- 新パターン/新機能は「新しい Contract で記述できる場合のみ」追加する
|
||||
- Contract の導入中は “機能追加より SSOT 固め” を優先する(泥沼デバッグの再発防止)
|
||||
|
||||
## API の作り方(迷子防止)
|
||||
|
||||
Strangler 期間は “読む側だけ寄せる” と取りこぼしが起きやすい。読む側/書く側を両方とも API に閉じ込める。
|
||||
|
||||
- **読む側(参照点の一本化)**
|
||||
- `out_edges()` のように edge を列挙できる API を SSOT にする(`Jump`/`Branch` を同じ形で扱える)
|
||||
- 旧メタ(`jump_args`)は API 内部でのみ参照し、外部は見ない
|
||||
- **書く側(terminator 更新の一本化)**
|
||||
- `set_terminator(...)` のような入口に寄せ、successors/preds の同期漏れを構造で潰す
|
||||
- **verify(Fail-Fast)**
|
||||
- terminator から計算した successors と、キャッシュ `block.successors` の一致をチェックして “同期漏れ” を即死させる
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
Status: Active
|
||||
Scope: `StringUtils.is_integer/1`(nested-if + loop)を JoinIR で受理して `--profile quick` を進める。
|
||||
Status: ✅ P0 Complete
|
||||
Scope: `StringUtils.is_integer/1`(nested-if + loop)を JoinIR で受理して `--profile quick` を進める。
|
||||
Related:
|
||||
- Now: `docs/development/current/main/10-Now.md`
|
||||
- Phase 258: `docs/development/current/main/phases/phase-258/README.md`
|
||||
@ -7,9 +7,51 @@ Related:
|
||||
|
||||
# Phase 259: `StringUtils.is_integer/1` (nested-if + loop)
|
||||
|
||||
## P0 Result (2025-12-21)
|
||||
|
||||
- **is_integer/1**: Pattern8 で認識・実行成功 ✅
|
||||
- **VM smoke test**: `[PASS] phase259_p0_is_integer_vm` ✅
|
||||
- **Exit code**: 7(is_integer("123") == true)
|
||||
- **json_lint_vm**: まだ FAIL(別問題: nested-loop with break / Pattern2)
|
||||
|
||||
### Key Fixes Applied
|
||||
|
||||
1. `expr_result = Some(join_exit_value)` - Pattern7 style で明示設定
|
||||
2. `loop_var_name = Some(parts.loop_var.clone())` - merge_entry_block 選択用
|
||||
3. `loop_invariants = [(me, me_host), (s, s_host)]` - PHI-free 不変量パラメータ
|
||||
4. `skipped_entry_redirects` - k_exit のスキップ時ブロック参照リダイレクト
|
||||
|
||||
## Current Status (SSOT)
|
||||
|
||||
- Current first FAIL: `json_lint_vm / StringUtils.is_integer/1`
|
||||
- ✅ is_integer/1 は Pattern8 で解決
|
||||
- ❌ json_lint_vm は別の nested-loop with break パターンで失敗中(Phase 260+)
|
||||
|
||||
### Next FAIL (Phase 260+)
|
||||
|
||||
- **Function**: `Main.main/0` in `apps/examples/json_lint/main.hako`
|
||||
- **Error**: `[cf_loop/pattern2] Failed to extract break condition from loop body`
|
||||
- **Pattern**: Nested loop(外側 `loop(i < cases.length())` 内で内側 `loop(j < valid.length())` + break)
|
||||
- **AST Structure**:
|
||||
```
|
||||
loop(i < cases.length()) {
|
||||
local s = ...
|
||||
local ok = 0
|
||||
local j = 0
|
||||
loop(j < valid.length()) { // ← 内側ループ
|
||||
if (s == valid.get(j)) {
|
||||
ok = 1
|
||||
break // ← Pattern2 が抽出失敗
|
||||
}
|
||||
j = j + 1
|
||||
}
|
||||
if (ok == 1) { print("OK") } else { print("ERROR") }
|
||||
i = i + 1
|
||||
}
|
||||
```
|
||||
- **Reproduce**:
|
||||
```bash
|
||||
./target/release/hakorune --backend vm apps/examples/json_lint/main.hako
|
||||
```
|
||||
- Shape summary(ログ由来):
|
||||
- prelude: nested-if to compute `start` (handles leading `"-"`)
|
||||
- loop: `loop(i < s.length()) { if not this.is_digit(s.substring(i, i+1)) { return false } i = i + 1 }`
|
||||
|
||||
Reference in New Issue
Block a user