2025-12-27 05:45:12 +09:00
|
|
|
|
# Phase 188.3: Nested loop lowering (1-level) — make Pattern 6 real
|
|
|
|
|
|
|
2025-12-27 06:22:59 +09:00
|
|
|
|
**Date**: 2025-12-27
|
|
|
|
|
|
**Status**: In progress (Phase 2 done: selection / Phase 3: lowering)
|
2025-12-27 05:45:12 +09:00
|
|
|
|
**Prereq**: Phase 188.2 Option A is complete (StepTree depth SSOT + strict Fail-Fast)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Goal
|
|
|
|
|
|
|
|
|
|
|
|
`max_loop_depth == 2`(1-level nested loop)を **JoinIR lowering で実際に通す**。
|
|
|
|
|
|
|
|
|
|
|
|
- 既知の事実: `LoopForm (=LoopShape)` にはネスト情報が無いので、**LoopFormベースの Pattern6 検出/ルーティングでは実装できない**
|
|
|
|
|
|
- 実装は **StepTree(AST側)**を SSOT として扱う(Phase 188.2 Option A を継続)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-27 06:22:59 +09:00
|
|
|
|
## Definition: `max_loop_depth` (SSOT)
|
|
|
|
|
|
|
|
|
|
|
|
`StepTreeFeatures.max_loop_depth` は「その関数(or 評価対象ブロック)の中で、最も深い `loop{}` ネストの深さ」を表す。
|
|
|
|
|
|
|
|
|
|
|
|
- loop が無い: `0`(※StepTree実装に依存。現状の運用では “loopがある前提”で扱う)
|
|
|
|
|
|
- loop が 1 段: `1`
|
|
|
|
|
|
- loop の中に loop が 1 つ: `2`
|
|
|
|
|
|
- `loop{ loop{ loop{ ... } } }`: `3`
|
|
|
|
|
|
|
|
|
|
|
|
Phase 188.2 の strict ガードは「depth > 2 を明示エラー」にしている。
|
|
|
|
|
|
これは言語仕様の制限ではなく、「JoinIR lowering の実装範囲(compiler capability)」の制限。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-27 05:45:12 +09:00
|
|
|
|
## Scope (minimal)
|
|
|
|
|
|
|
|
|
|
|
|
対応するのは “NestedLoop Minimal” の 1形だけに限定する。
|
|
|
|
|
|
|
|
|
|
|
|
- depth: `max_loop_depth == 2` のみ
|
|
|
|
|
|
- inner loop: Pattern1相当(break/continue 無し)
|
|
|
|
|
|
- outer loop: Pattern1相当(break/continue 無し)を優先
|
|
|
|
|
|
- それ以外:
|
|
|
|
|
|
- strict mode: 明示エラー(Phase 188.2 の depth check とは別タグで良い)
|
|
|
|
|
|
- non-strict mode: 既存の fallback 経路に任せる(ただし silent fallback を増やさない)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-27 06:22:59 +09:00
|
|
|
|
## Current Code Status (reality)
|
|
|
|
|
|
|
|
|
|
|
|
Phase 188.3 は “選択ロジック(Pattern6選定)” まで実装済みで、lowering が未実装(stub)な状態。
|
|
|
|
|
|
|
|
|
|
|
|
- Selection SSOT: `src/mir/builder/control_flow/joinir/routing.rs` の `choose_pattern_kind()`
|
|
|
|
|
|
- cheap check → StepTree → AST validation
|
|
|
|
|
|
- `max_loop_depth == 2` かつ “Pattern6 lowerable” のときだけ `Pattern6NestedLoopMinimal` を返す
|
|
|
|
|
|
- Lowering stub: `src/mir/builder/control_flow/joinir/patterns/pattern6_nested_minimal.rs`
|
|
|
|
|
|
- 現在は `Err("[Pattern6] ... not yet implemented")` で Fail-Fast
|
|
|
|
|
|
|
|
|
|
|
|
この README のゴールは、stub を “実装済み” にして fixture を通すこと。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-27 05:45:12 +09:00
|
|
|
|
## SSOT (what to rely on)
|
|
|
|
|
|
|
|
|
|
|
|
- nesting depth SSOT: `StepTreeFeatures.max_loop_depth`
|
|
|
|
|
|
- depth > 2: strict mode で `control_tree/nested_loop/depth_exceeded`(Phase 188.2)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Scope & Variable Model (SSOT)
|
|
|
|
|
|
|
|
|
|
|
|
Nyash の変数スコープ方針に合わせて、nested loop lowering でも以下を SSOT として固定する。
|
|
|
|
|
|
|
|
|
|
|
|
### Visibility (read)
|
|
|
|
|
|
|
|
|
|
|
|
- inner loop から outer の binding は参照できる(lexical scope: “1つ上は見える”)
|
|
|
|
|
|
- ただし JoinIR lowering では「見える」を **明示的な引数/継続で表現**する(暗黙キャプチャを増やさない)
|
|
|
|
|
|
|
|
|
|
|
|
### Mutation (write-back)
|
|
|
|
|
|
|
|
|
|
|
|
Phase 188.3 では段階的に進める:
|
|
|
|
|
|
|
2025-12-27 06:22:59 +09:00
|
|
|
|
- **P188.3 (minimal)**: “最小の write-back” を **明示的な carrier** として許す
|
|
|
|
|
|
- inner loop が outer 変数を更新する場合、その変数は **carrier として引数で受けて、`k_inner_exit(...)` で返す**
|
|
|
|
|
|
- 対応範囲は最小(fixtureが要求する 1 carrier 程度)に限定する
|
|
|
|
|
|
- **P188.4+ (generalize)**: write-back を一般化(複数 carrier / 代入形 / break/continue を含む形)
|
2025-12-27 05:45:12 +09:00
|
|
|
|
|
2025-12-27 06:22:59 +09:00
|
|
|
|
この分離により、write-back の複雑さ(複数 carrier / break / continue / PHI の再接続)を Phase 188.3 に持ち込まずに済む。
|
2025-12-27 05:45:12 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Lowering sketch (how it should look)
|
|
|
|
|
|
|
|
|
|
|
|
Nested loop は JoinIR の「tail recursion + continuation」を再帰的に合成して表現する。
|
|
|
|
|
|
|
|
|
|
|
|
- outer: `outer_step(state..., k_outer_exit)`
|
|
|
|
|
|
- inner: `inner_step(state..., k_inner_exit)`
|
|
|
|
|
|
- inner が終わったら `k_inner_exit(...)` で outer の“残り”へ戻る
|
|
|
|
|
|
|
|
|
|
|
|
この `k_inner_exit` がスコープ境界として働くので、将来の write-back もここに集約できる。
|
|
|
|
|
|
|
2025-12-27 06:22:59 +09:00
|
|
|
|
### Minimal function graph (recommended)
|
|
|
|
|
|
|
|
|
|
|
|
Phase 188.3 の最小形は「outer の loop_step の中で inner の loop_step を呼び、inner が終わったら k_inner_exit で outer に戻る」。
|
|
|
|
|
|
|
|
|
|
|
|
推奨の JoinIR 関数群(概念):
|
|
|
|
|
|
|
|
|
|
|
|
- `main(i0, sum0)`:
|
|
|
|
|
|
- `Call(loop_step, [i0, sum0])`
|
|
|
|
|
|
- `Ret 0`(statement-position loop の場合)
|
|
|
|
|
|
- `loop_step(i, sum)`(outer の step。canonical name は `loop_step` に寄せる):
|
|
|
|
|
|
- `exit_cond = !(i < N_outer)`
|
|
|
|
|
|
- `Jump(k_exit, [sum], cond=exit_cond)`
|
|
|
|
|
|
- `Call(inner_step, [j0, i, sum])`
|
|
|
|
|
|
- `inner_step(j, i_outer, sum)`:
|
|
|
|
|
|
- `exit_cond = !(j < N_inner)`
|
|
|
|
|
|
- `Jump(k_inner_exit, [i_outer, sum], cond=exit_cond)`
|
|
|
|
|
|
- `sum_next = sum + 1`(fixture の最小形)
|
|
|
|
|
|
- `j_next = j + 1`
|
|
|
|
|
|
- `Call(inner_step, [j_next, i_outer, sum_next])`
|
|
|
|
|
|
- `k_inner_exit(i, sum)`:
|
|
|
|
|
|
- `i_next = i + 1`
|
|
|
|
|
|
- `Call(loop_step, [i_next, sum])`
|
|
|
|
|
|
- `k_exit(sum)`(canonical name `k_exit`):
|
|
|
|
|
|
- `Ret sum`
|
|
|
|
|
|
|
|
|
|
|
|
重要:
|
|
|
|
|
|
- **carrier はグローバル扱いしない**。`sum` は引数で運んで戻す。
|
|
|
|
|
|
- merge 側の “loop_step 関数の選定” を壊さないため、`inner_step` と `k_inner_exit` は boundary の `continuation_func_ids` に含めて除外する(詳細は指示書)。
|
|
|
|
|
|
|
2025-12-27 05:45:12 +09:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Deliverables
|
|
|
|
|
|
|
|
|
|
|
|
1. **Fixture + integration smoke(exit code SSOT)**
|
|
|
|
|
|
- 1-level nested loop を最小で再現する `.hako` を追加
|
|
|
|
|
|
- integration で実行し、exit code で判定(stdout比較はしない)
|
|
|
|
|
|
|
|
|
|
|
|
2. **StepTree-based lowering implementation**
|
|
|
|
|
|
- StepTree を辿って、inner loop を outer loop の中で正しく lowering できるようにする
|
|
|
|
|
|
- 入口は “StepTree→JoinIR” のどこか(LoopFormベースの router は使わない)
|
|
|
|
|
|
|
|
|
|
|
|
3. **Docs update**
|
|
|
|
|
|
- Phase 188.1 の “Pattern6 specification” が design であることは維持
|
|
|
|
|
|
- Phase 188.3 で “実装済み/未実装の境界” を明確に書く
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Acceptance Criteria
|
|
|
|
|
|
|
|
|
|
|
|
- `./tools/smokes/v2/run.sh --profile quick` が常にグリーン維持
|
|
|
|
|
|
- integration selfhost が FAIL=0 を維持
|
|
|
|
|
|
- 追加した nested loop fixture が PASS(JoinIR lowering が使われたことをログ/タグで確認可能)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-27 06:22:59 +09:00
|
|
|
|
## Instructions (handoff)
|
|
|
|
|
|
|
|
|
|
|
|
実装者(Claude Code)向けの手順書は `docs/development/current/main/phases/phase-188.3/P1-INSTRUCTIONS.md` を参照。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-27 05:45:12 +09:00
|
|
|
|
## Next (schedule)
|
|
|
|
|
|
|
|
|
|
|
|
- **Phase 188.3**: depth=2 の最小形を “確実に通す” + PoC fixture を smoke 固定
|
|
|
|
|
|
- **Phase 188.4+**: write-back(outer carrier reconnection)と “再帰 lowering の一般化(depthを増やしても壊れない)” を docs-first で設計してから実装
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Out of Scope
|
|
|
|
|
|
|
|
|
|
|
|
- nested loop + break/continue の一般対応
|
|
|
|
|
|
- LoopRegion を使った MIR-level nesting SSOT(Option B)
|