feat(edgecfg): Phase 268-270 savepoint (if_form adoption + Pattern9 minimal loop SSOT)
This commit is contained in:
273
docs/development/current/main/phases/phase-269/README.md
Normal file
273
docs/development/current/main/phases/phase-269/README.md
Normal file
@ -0,0 +1,273 @@
|
||||
# Phase 269: Pattern8 への Frag 適用(test-only + 最小 fixture)
|
||||
|
||||
Status: 🚧 進行中(P0)
|
||||
Date: 2025-12-21
|
||||
|
||||
## 目的
|
||||
|
||||
**EdgeCFG Fragment を Pattern8 に適用し、NormalizedShadow への適用パターンを確立**
|
||||
|
||||
- **P0**: Pattern8 の Frag 版 lowerer を test-only で作成(既存実装と並走)
|
||||
- **P1 以降**: 既存 Pattern8 を段階的に置換(将来フェーズ)
|
||||
|
||||
## 実装範囲(重要:スコープ境界)
|
||||
|
||||
### ✅ 触る(P0 スコープ)
|
||||
- `pattern8_scan_bool_predicate.rs` に Frag 版 lowerer を追加(test-only)
|
||||
- EdgeCFG Fragment API(compose::loop_(), emit_frag())を使用
|
||||
- 最小 fixture(`phase269_p0_pattern8_frag_min.hako`)を作成
|
||||
- 最小 smoke test(VM のみ)を作成
|
||||
|
||||
### ❌ 触らない(P0 スコープ外)
|
||||
- 既存 Pattern8 本体(`cf_loop_pattern8_bool_predicate_impl()`)は維持
|
||||
- Pattern6/7 は触らない
|
||||
- JoinIR merge 層は触らない
|
||||
- LLVM backend は P1 以降
|
||||
|
||||
## 実装戦略(Phase 268 パターン踏襲)
|
||||
|
||||
### アーキテクチャ図
|
||||
```
|
||||
pattern8_scan_bool_predicate.rs (Pattern8 層)
|
||||
↓ 新規追加(test-only)
|
||||
lower_pattern8_frag() (Frag 版 lowerer)
|
||||
↓ 内部で使用
|
||||
Frag 構築 + compose::loop_() + emit_frag() (EdgeCFG Fragment API)
|
||||
↓ 最終的に呼び出し
|
||||
set_branch_with_edge_args() / set_jump_with_edge_args() (Phase 260 SSOT)
|
||||
```
|
||||
|
||||
### P0 実装順序
|
||||
|
||||
1. **Phase 269 README 作成**(このファイル)
|
||||
- 設計境界と適用順を SSOT 化
|
||||
- "どの層を触る/触らない" を明記
|
||||
|
||||
2. **Pattern8 Frag 版 lowerer 作成**(test-only)
|
||||
- `#[cfg(test)] pub(crate) fn lower_pattern8_frag()` として実装
|
||||
- JoinModule から MIR terminator を生成
|
||||
- unit test で MIR terminator 生成を確認
|
||||
|
||||
3. **最小 fixture + smoke test**(VM のみ)
|
||||
- `apps/tests/phase269_p0_pattern8_frag_min.hako`
|
||||
- `tools/smokes/v2/profiles/integration/apps/phase269_p0_pattern8_frag_vm.sh`
|
||||
- PASS を確認(既存 quick 45/46 を悪化させない)
|
||||
|
||||
4. **docs 更新**
|
||||
- `10-Now.md` に Phase 269 P0 追記
|
||||
- `30-Backlog.md` に Phase 269 項目追加
|
||||
|
||||
## Pattern8 の構造理解
|
||||
|
||||
### 検出基準(Phase 259 P0 固定形式)
|
||||
1. Loop condition: `i < s.length()`
|
||||
2. Loop body has if statement:
|
||||
- Condition: `not this.method(...)` (UnaryOp::Not + MethodCall)
|
||||
- Then branch: `return false` (early exit)
|
||||
3. Loop body has step: `i = i + 1`
|
||||
4. Post-loop: `return true`
|
||||
|
||||
### 既存実装の処理フロー
|
||||
```rust
|
||||
// 1. Extract pattern parts
|
||||
let parts = extract_bool_predicate_scan_parts(condition, body)?;
|
||||
|
||||
// 2. Get host ValueIds
|
||||
let s_host = variable_map[haystack];
|
||||
let i_host = variable_map[loop_var];
|
||||
let me_host = build_me_expression()?;
|
||||
|
||||
// 3. Create JoinModule
|
||||
let join_module = lower_scan_bool_predicate_minimal(...);
|
||||
|
||||
// 4. Build boundary
|
||||
let boundary = JoinInlineBoundaryBuilder::new()
|
||||
.with_inputs(join_inputs, host_inputs)
|
||||
.with_loop_invariants(loop_invariants)
|
||||
.with_exit_bindings(exit_bindings)
|
||||
.with_carrier_info(carrier_info)
|
||||
.with_loop_var_name(Some(loop_var))
|
||||
.with_expr_result(Some(join_exit_value))
|
||||
.build();
|
||||
|
||||
// 5. Execute JoinIRConversionPipeline
|
||||
let result = JoinIRConversionPipeline::execute(self, join_module, Some(&boundary), ...)?;
|
||||
```
|
||||
|
||||
## P0 Frag 版 lowerer 設計
|
||||
|
||||
### 目的
|
||||
- JoinModule から MIR terminator を生成する部分を Frag 化
|
||||
- 既存の JoinModule 生成・boundary 構築は維持
|
||||
- emit_frag() による terminator 生成を導入
|
||||
|
||||
### 実装方針
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
pub(crate) fn lower_pattern8_frag(
|
||||
builder: &mut MirBuilder,
|
||||
join_module: JoinModule,
|
||||
boundary: &JoinInlineBoundary,
|
||||
debug: bool,
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
// 1. JoinModule から必要な情報を取得
|
||||
// - loop_step function (loop body)
|
||||
// - k_exit function (return true)
|
||||
|
||||
// 2. Loop body Frag 構築
|
||||
// - loop_step の処理を Frag で表現
|
||||
// - early return (return false) は Return exit として扱う
|
||||
|
||||
// 3. compose::loop_() で合成
|
||||
// - loop_id, header, after, body_frag
|
||||
|
||||
// 4. emit_frag() で MIR terminator に変換
|
||||
|
||||
// 5. result 返却(expr_result)
|
||||
Ok(boundary.expr_result)
|
||||
}
|
||||
```
|
||||
|
||||
### Unit Test 設計
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_pattern8_frag_lowering() {
|
||||
// 1. Create minimal JoinModule
|
||||
// 2. Create boundary
|
||||
// 3. Call lower_pattern8_frag()
|
||||
// 4. Verify MIR terminator generation
|
||||
// - Branch terminator exists
|
||||
// - Jump terminator exists
|
||||
// - Return terminator exists (early exit)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 最小 fixture 設計
|
||||
|
||||
### `phase269_p0_pattern8_frag_min.hako`
|
||||
|
||||
Phase 259 の `is_integer_min.hako` の縮小版:
|
||||
|
||||
```nyash
|
||||
static box StringUtils {
|
||||
is_digit(ch) {
|
||||
return ch == "0" or ch == "1"
|
||||
}
|
||||
|
||||
is_integer(s) {
|
||||
if s.length() == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
local i = 0
|
||||
loop(i < s.length()) {
|
||||
if not this.is_digit(s.substring(i, i + 1)) {
|
||||
return false
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
return StringUtils.is_integer("01") ? 7 : 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Smoke Test 設計
|
||||
|
||||
`tools/smokes/v2/profiles/integration/apps/phase269_p0_pattern8_frag_vm.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cd "$(dirname "$0")/../../../../../.."
|
||||
HAKORUNE_BIN="${HAKORUNE_BIN:-./target/release/hakorune}"
|
||||
set +e
|
||||
$HAKORUNE_BIN apps/tests/phase269_p0_pattern8_frag_min.hako > /tmp/phase269_out.txt 2>&1
|
||||
EXIT_CODE=$?
|
||||
set -e
|
||||
if [ $EXIT_CODE -eq 7 ]; then
|
||||
echo "[PASS] phase269_p0_pattern8_frag_vm"
|
||||
exit 0
|
||||
else
|
||||
echo "[FAIL] phase269_p0_pattern8_frag_vm: expected exit 7, got $EXIT_CODE"
|
||||
cat /tmp/phase269_out.txt
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## 重要な設計判断
|
||||
|
||||
### なぜ test-only か
|
||||
|
||||
1. **非破壊的**: 既存 Pattern8 実装を壊さない
|
||||
2. **段階的**: Frag 版の動作を先に確認してから統合
|
||||
3. **デバッグ容易**: 問題切り分けが簡単(Frag 版 vs 既存実装)
|
||||
4. **拡張性**: Pattern6/7 にも同じパターンを適用可能
|
||||
|
||||
### なぜ最小 fixture か
|
||||
|
||||
1. **高速検証**: 小さいコードで問題を早期発見
|
||||
2. **デバッグ容易**: MIR dump が読みやすい
|
||||
3. **回帰テスト**: quick smoke に含めやすい
|
||||
|
||||
### P0 での制約
|
||||
|
||||
- VM のみ(LLVM は P1 以降)
|
||||
- Pattern8 のみ(Pattern6/7 は P1 以降)
|
||||
- test-only(既存実装置換は P1 以降)
|
||||
|
||||
## 次フェーズへの橋渡し
|
||||
|
||||
**Phase 269 P1+**: 既存 Pattern8 を Frag 版に置換
|
||||
- `cf_loop_pattern8_bool_predicate_impl()` から `lower_pattern8_frag()` を呼び出す
|
||||
- JoinIRConversionPipeline を廃止(Frag 版に一本化)
|
||||
- Pattern6/7 にも適用
|
||||
|
||||
**Phase 270+**: Pattern 分岐削減
|
||||
- Pattern 番号による分岐を削減
|
||||
- compose API による統一的なループ処理
|
||||
|
||||
## 関連ドキュメント
|
||||
|
||||
- **Phase 268**: `docs/development/current/main/phases/phase-268/README.md`
|
||||
- **設計図**: `docs/development/current/main/design/edgecfg-fragments.md`
|
||||
- **JoinIR アーキテクチャ**: `docs/development/current/main/joinir-architecture-overview.md`
|
||||
- **現在のタスク**: `docs/development/current/main/10-Now.md`
|
||||
|
||||
## 受け入れ基準(P0)
|
||||
|
||||
- ✅ `cargo build --release` 成功
|
||||
- ✅ `cargo test --lib --release` で全テスト PASS
|
||||
- ✅ Pattern8 Frag 版 lowerer の unit test PASS
|
||||
- ✅ `apps/tests/phase269_p0_pattern8_frag_min.hako` 作成
|
||||
- ✅ `tools/smokes/v2/profiles/integration/apps/phase269_p0_pattern8_frag_vm.sh` 作成
|
||||
- ✅ smoke test PASS(exit code 7)
|
||||
- ✅ `tools/smokes/v2/run.sh --profile quick` で 45/46 PASS 維持
|
||||
- ✅ MIR dump で Branch/Jump/Return terminator 正常生成確認
|
||||
- ✅ ドキュメント更新完了:
|
||||
- ✅ `phases/phase-269/README.md` 新規作成(このファイル)
|
||||
- ✅ `10-Now.md` 追記
|
||||
- ✅ `30-Backlog.md` 更新
|
||||
|
||||
## まとめ
|
||||
|
||||
**Phase 269 P0 の核心**:
|
||||
|
||||
- ✅ Pattern8 を Frag 化(test-only、既存と並走)
|
||||
- ✅ compose::loop_() + emit_frag() を使用
|
||||
- ✅ 最小 fixture + smoke test で動作確認
|
||||
- ✅ quick smoke 45/46 を悪化させない
|
||||
|
||||
**次のステップ**: P1 で既存 Pattern8 を Frag 版に置換 → Pattern6/7 にも適用
|
||||
Reference in New Issue
Block a user