722 lines
21 KiB
Markdown
722 lines
21 KiB
Markdown
|
|
# .hakoコンパイラ LoopForm v2化 実現可能性調査レポート
|
||
|
|
|
||
|
|
**調査日**: 2025-11-18
|
||
|
|
**調査者**: Claude Code (AI分析)
|
||
|
|
**目的**: Rust LoopForm v2 設計を .hako コンパイラに適用する実現可能性を評価
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## エグゼクティブサマリー
|
||
|
|
|
||
|
|
### 結論: **実装可能だが工数大 (Phase C: 16-24時間)**
|
||
|
|
|
||
|
|
**推奨**: **Option 2 (Exit PHIのみ実装)** を推奨
|
||
|
|
**理由**:
|
||
|
|
- 現在の .hako コンパイラは既に Header PHI 生成機能を持つ (`LoopFormBox.loop_counter`)
|
||
|
|
- Exit PHI 生成のみが no-op stub (`LoopSSA.stabilize_merges`)
|
||
|
|
- 最小限の修正で Test 2 (break文付きループ) が動作可能
|
||
|
|
- 完全移植 (Option 1) は工数対効果が低い
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. 現状分析レポート
|
||
|
|
|
||
|
|
### 1.1 .hakoコンパイラの現在のループ実装
|
||
|
|
|
||
|
|
#### 実装箇所
|
||
|
|
```
|
||
|
|
lang/src/shared/mir/loop_form_box.hako # LoopFormBox (PHI生成済み)
|
||
|
|
lang/src/compiler/builder/ssa/loopssa.hako # LoopSSA (no-op stub)
|
||
|
|
lang/src/shared/mir/block_builder_box.hako # BlockBuilderBox (MIR組立)
|
||
|
|
lang/src/shared/mir/mir_schema_box.hako # MirSchemaBox (JSON生成)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 実装状況
|
||
|
|
✅ **Header PHI生成**: 実装済み
|
||
|
|
```hako
|
||
|
|
// LoopFormBox.loop_counter() より (lines 30-40)
|
||
|
|
local phi_i_inputs = new ArrayBox()
|
||
|
|
phi_i_inputs.push(MirSchemaBox.phi_incoming(0, 1)) // from preheader
|
||
|
|
phi_i_inputs.push(MirSchemaBox.phi_incoming(7, 18)) // from latch
|
||
|
|
header.push(MirSchemaBox.inst_phi(10, phi_i_inputs)) // r10 = current i
|
||
|
|
```
|
||
|
|
|
||
|
|
✅ **Latch PHI生成**: 実装済み (continue/normal merge)
|
||
|
|
```hako
|
||
|
|
// LoopFormBox.loop_counter() より (lines 71-80)
|
||
|
|
local latch_phi_i = new ArrayBox()
|
||
|
|
latch_phi_i.push(MirSchemaBox.phi_incoming(5, 15)) // continue path
|
||
|
|
latch_phi_i.push(MirSchemaBox.phi_incoming(6, 17)) // body path
|
||
|
|
latch_block.push(MirSchemaBox.inst_phi(18, latch_phi_i))
|
||
|
|
```
|
||
|
|
|
||
|
|
✅ **Exit PHI生成**: 実装済み (単一ループのみ)
|
||
|
|
```hako
|
||
|
|
// LoopFormBox.loop_counter() より (lines 83-89)
|
||
|
|
local exit_vals = new ArrayBox()
|
||
|
|
exit_vals.push(MirSchemaBox.phi_incoming(1, 11)) // normal completion
|
||
|
|
exit_vals.push(MirSchemaBox.phi_incoming(3, 11)) // break path
|
||
|
|
local exit_block = new ArrayBox()
|
||
|
|
exit_block.push(MirSchemaBox.inst_phi(20, exit_vals))
|
||
|
|
```
|
||
|
|
|
||
|
|
❌ **LoopSSA統合**: no-op stub
|
||
|
|
```hako
|
||
|
|
// loopssa.hako (lines 3-7)
|
||
|
|
static box LoopSSA {
|
||
|
|
stabilize_merges(stage1_json) { return stage1_json } // ← 何もしていない
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 1.2 既存コードの問題点
|
||
|
|
|
||
|
|
**Problem 1: LoopFormBox は独立したテスト用コード**
|
||
|
|
- `LoopFormBox.loop_counter()` は完全なMIRモジュールを生成 (preheader → header → body → latch → exit)
|
||
|
|
- コンパイラパイプライン (`pipeline_v2/`) からは**使用されていない**
|
||
|
|
- テスト専用 (`tests/phase33/unit/loopform/test_basic.hako`)
|
||
|
|
|
||
|
|
**Problem 2: コンパイラは BlockBuilderBox 経由で個別命令生成**
|
||
|
|
- `emit_mir_flow.hako` → `BlockBuilderBox.loop_counter()` → 個別MIR命令
|
||
|
|
- LoopFormBox のような構造化アプローチは未使用
|
||
|
|
|
||
|
|
**Problem 3: Exit PHI生成がパイプラインに未統合**
|
||
|
|
- `LoopSSA.stabilize_merges()` は no-op stub
|
||
|
|
- break文のスナップショット収集機構が存在しない
|
||
|
|
- Exit PHI生成のタイミングが未定義
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. LoopForm v2 適用の技術的課題
|
||
|
|
|
||
|
|
### 2.1 データ構造表現の実現可能性
|
||
|
|
|
||
|
|
#### Rust実装 (参考)
|
||
|
|
```rust
|
||
|
|
struct CarrierVariable {
|
||
|
|
name: String,
|
||
|
|
init_value: ValueId, // 初期値
|
||
|
|
preheader_copy: ValueId, // Preheaderでの一意ValueId
|
||
|
|
header_phi: ValueId, // Header PHIでの一意ValueId
|
||
|
|
latch_value: ValueId, // Latchでの更新値
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### .hako実装 (MapBox/ArrayBox)
|
||
|
|
**難易度: B (中程度)** - 3-4時間
|
||
|
|
|
||
|
|
```hako
|
||
|
|
// CarrierVariable相当をMapBoxで表現
|
||
|
|
method create_carrier_var(name, init_value) {
|
||
|
|
local carrier = new MapBox()
|
||
|
|
carrier.set("name", name)
|
||
|
|
carrier.set("init_value", init_value)
|
||
|
|
carrier.set("preheader_copy", -1) // 後で割り当て
|
||
|
|
carrier.set("header_phi", -1)
|
||
|
|
carrier.set("latch_value", -1)
|
||
|
|
return carrier
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**評価**:
|
||
|
|
- ✅ MapBox/ArrayBox で構造体相当を表現可能
|
||
|
|
- ✅ MirSchemaBox で ValueId 表現は確立済み (`this.i(value)`)
|
||
|
|
- ⚠️ 型安全性なし (フィールドアクセスミスがランタイムエラー)
|
||
|
|
- ⚠️ コード量増加 (Rustの3-4倍)
|
||
|
|
|
||
|
|
### 2.2 4パス構成の実装可能性
|
||
|
|
|
||
|
|
#### Pass 1: prepare_structure
|
||
|
|
**難易度: B (中程度)** - 4-6時間
|
||
|
|
|
||
|
|
```hako
|
||
|
|
static box LoopFormV2Builder {
|
||
|
|
carriers: ArrayBox // CarrierVariable配列
|
||
|
|
pinned: ArrayBox // PinnedVariable配列
|
||
|
|
|
||
|
|
prepare_structure(current_vars, params, allocator) {
|
||
|
|
me.carriers = new ArrayBox()
|
||
|
|
me.pinned = new ArrayBox()
|
||
|
|
|
||
|
|
// current_vars をイテレート
|
||
|
|
local keys = current_vars.keys()
|
||
|
|
local i = 0
|
||
|
|
loop(i < keys.length()) {
|
||
|
|
local name = keys.get(i)
|
||
|
|
local value = current_vars.get(name)
|
||
|
|
|
||
|
|
if me._is_parameter(name, params) {
|
||
|
|
// Pinned変数
|
||
|
|
local pinned = new MapBox()
|
||
|
|
pinned.set("name", name)
|
||
|
|
pinned.set("param_value", value)
|
||
|
|
pinned.set("preheader_copy", allocator.new_value())
|
||
|
|
pinned.set("header_phi", allocator.new_value())
|
||
|
|
me.pinned.push(pinned)
|
||
|
|
} else {
|
||
|
|
// Carrier変数
|
||
|
|
local carrier = new MapBox()
|
||
|
|
carrier.set("name", name)
|
||
|
|
carrier.set("init_value", value)
|
||
|
|
carrier.set("preheader_copy", allocator.new_value())
|
||
|
|
carrier.set("header_phi", allocator.new_value())
|
||
|
|
carrier.set("latch_value", -1) // 後でsealing時に設定
|
||
|
|
me.carriers.push(carrier)
|
||
|
|
}
|
||
|
|
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
_is_parameter(name, params) {
|
||
|
|
local i = 0
|
||
|
|
loop(i < params.length()) {
|
||
|
|
if ("" + params.get(i)) == name { return 1 }
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**課題**:
|
||
|
|
- .hako に HashMap.keys() メソッドが存在するか不明 → **要確認**
|
||
|
|
- ValueId allocator が .hako コンパイラに存在するか → **要確認**
|
||
|
|
|
||
|
|
#### Pass 2: emit_preheader
|
||
|
|
**難易度: A (簡単)** - 2-3時間
|
||
|
|
|
||
|
|
```hako
|
||
|
|
emit_preheader(builder) {
|
||
|
|
// Pinned変数のCopy生成
|
||
|
|
local i = 0
|
||
|
|
loop(i < me.pinned.length()) {
|
||
|
|
local pin = me.pinned.get(i)
|
||
|
|
builder.emit_copy(
|
||
|
|
pin.get("preheader_copy"),
|
||
|
|
pin.get("param_value")
|
||
|
|
)
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
// Carrier変数のCopy生成
|
||
|
|
i = 0
|
||
|
|
loop(i < me.carriers.length()) {
|
||
|
|
local car = me.carriers.get(i)
|
||
|
|
builder.emit_copy(
|
||
|
|
car.get("preheader_copy"),
|
||
|
|
car.get("init_value")
|
||
|
|
)
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
// Header へジャンプ
|
||
|
|
builder.emit_jump(me.header_id)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**評価**: 既存の `MirSchemaBox.inst_copy()` / `inst_jump()` で実装可能
|
||
|
|
|
||
|
|
#### Pass 3: emit_header_phis
|
||
|
|
**難易度: B (中程度)** - 3-4時間
|
||
|
|
|
||
|
|
```hako
|
||
|
|
emit_header_phis(builder) {
|
||
|
|
// Pinned変数のPHI生成 (不完全: preheaderのみ)
|
||
|
|
local i = 0
|
||
|
|
loop(i < me.pinned.length()) {
|
||
|
|
local pin = me.pinned.get(i)
|
||
|
|
local inputs = new ArrayBox()
|
||
|
|
inputs.push(MirSchemaBox.phi_incoming(
|
||
|
|
me.preheader_id,
|
||
|
|
pin.get("preheader_copy")
|
||
|
|
))
|
||
|
|
builder.emit_phi(
|
||
|
|
pin.get("header_phi"),
|
||
|
|
inputs
|
||
|
|
)
|
||
|
|
builder.update_var(pin.get("name"), pin.get("header_phi"))
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
// Carrier変数のPHI生成 (不完全: preheaderのみ)
|
||
|
|
i = 0
|
||
|
|
loop(i < me.carriers.length()) {
|
||
|
|
local car = me.carriers.get(i)
|
||
|
|
local inputs = new ArrayBox()
|
||
|
|
inputs.push(MirSchemaBox.phi_incoming(
|
||
|
|
me.preheader_id,
|
||
|
|
car.get("preheader_copy")
|
||
|
|
))
|
||
|
|
builder.emit_phi(
|
||
|
|
car.get("header_phi"),
|
||
|
|
inputs
|
||
|
|
)
|
||
|
|
builder.update_var(car.get("name"), car.get("header_phi"))
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**課題**:
|
||
|
|
- `builder.update_var()` が .hako コンパイラに存在するか → **要確認**
|
||
|
|
- PHI命令の更新機構 (seal時) が必要
|
||
|
|
|
||
|
|
#### Pass 4: seal_phis
|
||
|
|
**難易度: B (中程度)** - 4-5時間
|
||
|
|
|
||
|
|
```hako
|
||
|
|
seal_phis(builder, latch_id) {
|
||
|
|
// Pinned変数のPHI完成 (latch入力追加)
|
||
|
|
local i = 0
|
||
|
|
loop(i < me.pinned.length()) {
|
||
|
|
local pin = me.pinned.get(i)
|
||
|
|
local latch_value = builder.get_variable_at_block(
|
||
|
|
pin.get("name"),
|
||
|
|
latch_id
|
||
|
|
)
|
||
|
|
if latch_value == null {
|
||
|
|
latch_value = pin.get("header_phi") // fallback
|
||
|
|
}
|
||
|
|
|
||
|
|
local inputs = new ArrayBox()
|
||
|
|
inputs.push(MirSchemaBox.phi_incoming(
|
||
|
|
me.preheader_id,
|
||
|
|
pin.get("preheader_copy")
|
||
|
|
))
|
||
|
|
inputs.push(MirSchemaBox.phi_incoming(
|
||
|
|
latch_id,
|
||
|
|
latch_value
|
||
|
|
))
|
||
|
|
|
||
|
|
builder.update_phi_inputs(
|
||
|
|
me.header_id,
|
||
|
|
pin.get("header_phi"),
|
||
|
|
inputs
|
||
|
|
)
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
// Carrier変数のPHI完成 (同様の処理)
|
||
|
|
// ... (省略)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**課題**:
|
||
|
|
- `builder.update_phi_inputs()` メソッドが必要 → **新規実装必要**
|
||
|
|
- JSONベースのMIR構築で「既存PHI命令の更新」をどう実現するか
|
||
|
|
|
||
|
|
### 2.3 Exit PHI生成
|
||
|
|
|
||
|
|
**難易度: C (難しい)** - 8-10時間
|
||
|
|
|
||
|
|
```hako
|
||
|
|
build_exit_phis(builder, exit_id, exit_snapshots) {
|
||
|
|
// exit_snapshots: [(block_id, { var_name: value_id }), ...]
|
||
|
|
|
||
|
|
local all_vars = new MapBox() // var_name => [(block_id, value_id), ...]
|
||
|
|
|
||
|
|
// Header fallthrough値を追加
|
||
|
|
local i = 0
|
||
|
|
loop(i < me.pinned.length()) {
|
||
|
|
local pin = me.pinned.get(i)
|
||
|
|
local name = pin.get("name")
|
||
|
|
local inputs = new ArrayBox()
|
||
|
|
inputs.push(new ArrayBox().push(me.header_id).push(pin.get("header_phi")))
|
||
|
|
all_vars.set(name, inputs)
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
// Carrier変数も同様
|
||
|
|
// ...
|
||
|
|
|
||
|
|
// break snapshots を統合
|
||
|
|
i = 0
|
||
|
|
loop(i < exit_snapshots.length()) {
|
||
|
|
local snap = exit_snapshots.get(i)
|
||
|
|
local block_id = snap.get(0)
|
||
|
|
local vars_map = snap.get(1)
|
||
|
|
|
||
|
|
local var_names = vars_map.keys()
|
||
|
|
local j = 0
|
||
|
|
loop(j < var_names.length()) {
|
||
|
|
local var_name = var_names.get(j)
|
||
|
|
local value_id = vars_map.get(var_name)
|
||
|
|
|
||
|
|
local existing = all_vars.get(var_name)
|
||
|
|
if existing == null {
|
||
|
|
existing = new ArrayBox()
|
||
|
|
all_vars.set(var_name, existing)
|
||
|
|
}
|
||
|
|
existing.push(new ArrayBox().push(block_id).push(value_id))
|
||
|
|
|
||
|
|
j = j + 1
|
||
|
|
}
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
// PHI生成
|
||
|
|
local var_names = all_vars.keys()
|
||
|
|
i = 0
|
||
|
|
loop(i < var_names.length()) {
|
||
|
|
local var_name = var_names.get(i)
|
||
|
|
local inputs = all_vars.get(var_name)
|
||
|
|
|
||
|
|
// 重複除去 (sanitize_phi_inputs相当)
|
||
|
|
inputs = me._sanitize_phi_inputs(inputs)
|
||
|
|
|
||
|
|
if inputs.length() == 0 {
|
||
|
|
// スキップ
|
||
|
|
} else if inputs.length() == 1 {
|
||
|
|
// 単一入力: 直接バインド
|
||
|
|
builder.update_var(var_name, inputs.get(0).get(1))
|
||
|
|
} else {
|
||
|
|
// 複数入力: PHI生成
|
||
|
|
local phi_id = builder.new_value()
|
||
|
|
local phi_inputs = new ArrayBox()
|
||
|
|
local j = 0
|
||
|
|
loop(j < inputs.length()) {
|
||
|
|
local inp = inputs.get(j)
|
||
|
|
phi_inputs.push(MirSchemaBox.phi_incoming(
|
||
|
|
inp.get(0), // block_id
|
||
|
|
inp.get(1) // value_id
|
||
|
|
))
|
||
|
|
j = j + 1
|
||
|
|
}
|
||
|
|
builder.emit_phi(phi_id, phi_inputs)
|
||
|
|
builder.update_var(var_name, phi_id)
|
||
|
|
}
|
||
|
|
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
_sanitize_phi_inputs(inputs) {
|
||
|
|
// 重複除去: block_idでグループ化し、最後の値を採用
|
||
|
|
local map = new MapBox()
|
||
|
|
local i = 0
|
||
|
|
loop(i < inputs.length()) {
|
||
|
|
local inp = inputs.get(i)
|
||
|
|
local bb = "" + inp.get(0) // block_idを文字列化
|
||
|
|
map.set(bb, inp)
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
// MapBox → ArrayBox変換
|
||
|
|
local result = new ArrayBox()
|
||
|
|
local keys = map.keys()
|
||
|
|
i = 0
|
||
|
|
loop(i < keys.length()) {
|
||
|
|
result.push(map.get(keys.get(i)))
|
||
|
|
i = i + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
return result
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**最大の課題**:
|
||
|
|
- **break文検出とスナップショット収集**をどこで行うか?
|
||
|
|
- コンパイラパイプラインの改修が必要
|
||
|
|
|
||
|
|
### 2.4 ValueId事前割り当て
|
||
|
|
|
||
|
|
**現状調査結果**:
|
||
|
|
- .hako コンパイラのValueId生成器が不明
|
||
|
|
- `MirSchemaBox.i(value)` は既存値をラップするのみ
|
||
|
|
|
||
|
|
**必要機能**:
|
||
|
|
```hako
|
||
|
|
static box ValueIdAllocator {
|
||
|
|
next_id: IntegerBox
|
||
|
|
|
||
|
|
birth() {
|
||
|
|
me.next_id = 100 // 初期値
|
||
|
|
}
|
||
|
|
|
||
|
|
new_value() {
|
||
|
|
local id = me.next_id
|
||
|
|
me.next_id = me.next_id + 1
|
||
|
|
return id
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**難易度: A (簡単)** - 1-2時間
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. 実装難易度・工数見積もり
|
||
|
|
|
||
|
|
### 3.1 難易度評価
|
||
|
|
|
||
|
|
| コンポーネント | 難易度 | 工数 | 理由 |
|
||
|
|
|---------------|--------|------|------|
|
||
|
|
| データ構造設計 | B | 3-4h | MapBox/ArrayBox で実装可能だが冗長 |
|
||
|
|
| Pass 1: prepare_structure | B | 4-6h | HashMap.keys() 存在確認が必要 |
|
||
|
|
| Pass 2: emit_preheader | A | 2-3h | 既存APIで実装可能 |
|
||
|
|
| Pass 3: emit_header_phis | B | 3-4h | PHI更新機構が必要 |
|
||
|
|
| Pass 4: seal_phis | B | 4-5h | update_phi_inputs実装が必要 |
|
||
|
|
| Exit PHI: build_exit_phis | C | 8-10h | break検出機構の実装が必要 |
|
||
|
|
| ValueId allocator | A | 1-2h | シンプルなカウンター |
|
||
|
|
| テスト・デバッグ | B | 4-6h | MIR JSON検証 |
|
||
|
|
|
||
|
|
**総工数見積もり**:
|
||
|
|
- **最小 (MVP)**: 20-26時間
|
||
|
|
- **推奨 (完全版)**: 30-40時間
|
||
|
|
|
||
|
|
### 3.2 段階的実装計画
|
||
|
|
|
||
|
|
#### Phase A (MVP): 最小動作版
|
||
|
|
**目標**: Test 2でheader PHI生成を確認
|
||
|
|
**工数**: 10-12時間
|
||
|
|
|
||
|
|
**タスク**:
|
||
|
|
1. ValueIdAllocator実装 (1-2h)
|
||
|
|
2. LoopFormV2Builder骨格作成 (2-3h)
|
||
|
|
3. Pass 1-3実装 (header PHI生成のみ) (6-7h)
|
||
|
|
4. テスト実行 (1h)
|
||
|
|
|
||
|
|
**成果物**:
|
||
|
|
- 単純ループ (break/continueなし) で header PHI 生成
|
||
|
|
- `LoopFormBox.loop_count()` と同等の機能
|
||
|
|
|
||
|
|
#### Phase B (Exit PHI): break対応
|
||
|
|
**目標**: Test 2で単一break文のループが動作
|
||
|
|
**工数**: 12-16時間
|
||
|
|
|
||
|
|
**タスク**:
|
||
|
|
1. Pass 4 (seal_phis) 実装 (4-5h)
|
||
|
|
2. break文検出機構 (5-6h)
|
||
|
|
3. build_exit_phis実装 (8-10h)
|
||
|
|
4. テスト・デバッグ (3-4h)
|
||
|
|
|
||
|
|
**成果物**:
|
||
|
|
- break文付きループで exit PHI 生成
|
||
|
|
- `LoopFormBox.loop_counter()` と同等の機能
|
||
|
|
|
||
|
|
#### Phase C (完全版): 全機能
|
||
|
|
**目標**: Test 2完全パス
|
||
|
|
**工数**: 8-12時間
|
||
|
|
|
||
|
|
**タスク**:
|
||
|
|
1. continue対応 (latch PHI) (3-4h)
|
||
|
|
2. ネストループ対応 (4-5h)
|
||
|
|
3. 複数break対応 (1-2h)
|
||
|
|
4. 総合テスト (2-3h)
|
||
|
|
|
||
|
|
**成果物**:
|
||
|
|
- Rust LoopForm v2 と同等の完全実装
|
||
|
|
|
||
|
|
**総工数 (Phase A-C)**: **30-40時間**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. 代替案の検討
|
||
|
|
|
||
|
|
### Option 1: LoopForm v2 完全移植
|
||
|
|
**メリット**:
|
||
|
|
- ✅ Rustと同等の完全性
|
||
|
|
- ✅ 将来的な拡張性
|
||
|
|
|
||
|
|
**デメリット**:
|
||
|
|
- ❌ 実装工数大 (30-40時間)
|
||
|
|
- ❌ .hakoコンパイラのメンテナンス負荷増
|
||
|
|
- ❌ 型安全性なし (ランタイムエラーリスク)
|
||
|
|
|
||
|
|
**評価**: **非推奨** (工数対効果が低い)
|
||
|
|
|
||
|
|
### Option 2: Exit PHIのみ実装 ⭐推奨
|
||
|
|
**メリット**:
|
||
|
|
- ✅ 最小限の修正でTest 2パス
|
||
|
|
- ✅ 既存の `LoopFormBox` を活用
|
||
|
|
- ✅ 工数削減 (12-16時間)
|
||
|
|
|
||
|
|
**デメリット**:
|
||
|
|
- ⚠️ Header PHI生成は既存ロジック依存
|
||
|
|
- ⚠️ LoopForm v2の核心思想 (事前ValueId割り当て) を完全には反映しない
|
||
|
|
|
||
|
|
**実装方針**:
|
||
|
|
1. `LoopSSA.stabilize_merges()` を実装
|
||
|
|
2. break文検出とスナップショット収集
|
||
|
|
3. Exit PHI生成 (`build_exit_phis` 相当)
|
||
|
|
|
||
|
|
**評価**: **強く推奨** (実用性と工数のバランス)
|
||
|
|
|
||
|
|
### Option 3: Rustコンパイラに統一
|
||
|
|
**メリット**:
|
||
|
|
- ✅ .hakoコンパイラのメンテナンス不要
|
||
|
|
- ✅ LoopForm v2の恩恵を直接享受
|
||
|
|
|
||
|
|
**デメリット**:
|
||
|
|
- ❌ Selfhostの意義喪失
|
||
|
|
- ❌ Phase 15目標に反する
|
||
|
|
|
||
|
|
**評価**: **非推奨** (プロジェクト方針に反する)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. 推奨事項
|
||
|
|
|
||
|
|
### 推奨Option: **Option 2 (Exit PHIのみ実装)**
|
||
|
|
|
||
|
|
**理由**:
|
||
|
|
1. **最小限の修正で目標達成**: Test 2 (break文付きループ) が動作
|
||
|
|
2. **既存実装を活用**: `LoopFormBox.loop_counter()` で Header/Latch PHI は既に実装済み
|
||
|
|
3. **工数削減**: 12-16時間 (vs 完全移植30-40時間)
|
||
|
|
4. **段階的移行**: 将来的に完全移植も可能 (Phase Cへの道筋)
|
||
|
|
|
||
|
|
### 実装計画 (Option 2)
|
||
|
|
|
||
|
|
**Step 1: break文検出機構 (4-5時間)**
|
||
|
|
```hako
|
||
|
|
// lang/src/compiler/pipeline_v2/stmt_break_detector_box.hako (新規)
|
||
|
|
static box StmtBreakDetectorBox {
|
||
|
|
break_snapshots: ArrayBox // [(block_id, var_snapshot), ...]
|
||
|
|
|
||
|
|
birth() {
|
||
|
|
me.break_snapshots = new ArrayBox()
|
||
|
|
}
|
||
|
|
|
||
|
|
capture_snapshot(block_id, var_map) {
|
||
|
|
local snap = new ArrayBox()
|
||
|
|
snap.push(block_id)
|
||
|
|
snap.push(var_map)
|
||
|
|
me.break_snapshots.push(snap)
|
||
|
|
}
|
||
|
|
|
||
|
|
get_snapshots() {
|
||
|
|
return me.break_snapshots
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Step 2: Exit PHI生成 (6-8時間)**
|
||
|
|
```hako
|
||
|
|
// lang/src/compiler/builder/ssa/loopssa.hako (修正)
|
||
|
|
using lang.compiler.pipeline_v2.stmt_break_detector_box as BreakDetector
|
||
|
|
|
||
|
|
static box LoopSSA {
|
||
|
|
stabilize_merges(stage1_json, break_detector, header_vars) {
|
||
|
|
// break文が存在しない場合はスキップ
|
||
|
|
local snaps = break_detector.get_snapshots()
|
||
|
|
if snaps.length() == 0 { return stage1_json }
|
||
|
|
|
||
|
|
// Exit PHI生成
|
||
|
|
local exit_phis = me._build_exit_phis(
|
||
|
|
header_vars,
|
||
|
|
snaps
|
||
|
|
)
|
||
|
|
|
||
|
|
// stage1_jsonに追加
|
||
|
|
// ... (JSON操作)
|
||
|
|
|
||
|
|
return stage1_json
|
||
|
|
}
|
||
|
|
|
||
|
|
_build_exit_phis(header_vars, exit_snapshots) {
|
||
|
|
// Option 2の build_exit_phis 実装
|
||
|
|
// ... (上記セクション2.3参照)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Step 3: パイプライン統合 (2-3時間)**
|
||
|
|
- `emit_mir_flow.hako` から `LoopSSA.stabilize_merges()` を呼び出し
|
||
|
|
- break文処理時に `BreakDetector.capture_snapshot()` を呼び出し
|
||
|
|
|
||
|
|
**Step 4: テスト・デバッグ (2-3時間)**
|
||
|
|
- Test 2 (break文付きループ) で動作確認
|
||
|
|
- MIR JSON 検証
|
||
|
|
|
||
|
|
**総工数**: **14-19時間**
|
||
|
|
|
||
|
|
### リスク評価
|
||
|
|
|
||
|
|
**技術リスク: 中**
|
||
|
|
- .hako コンパイラのアーキテクチャが JSON ベースであり、Rust の命令型アプローチと異なる
|
||
|
|
- PHI命令の更新 (seal時) が JSON 操作で複雑化する可能性
|
||
|
|
|
||
|
|
**メンテナンスリスク: 低**
|
||
|
|
- Option 2 は既存の `LoopFormBox` を活用するため、新規コードは最小限
|
||
|
|
- `LoopSSA.stabilize_merges()` のみの実装で、他への影響が少ない
|
||
|
|
|
||
|
|
**互換性リスク: 低**
|
||
|
|
- 既存のループ処理は変更せず、exit PHI 生成のみ追加
|
||
|
|
- 後方互換性が保たれる
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. 期待される成果物
|
||
|
|
|
||
|
|
### 1. 現状分析レポート ✅
|
||
|
|
**内容**: 本ドキュメント セクション1
|
||
|
|
|
||
|
|
### 2. 実装可能性評価 ✅
|
||
|
|
**内容**: 本ドキュメント セクション2
|
||
|
|
|
||
|
|
### 3. 工数見積もり ✅
|
||
|
|
**内容**: 本ドキュメント セクション3
|
||
|
|
|
||
|
|
### 4. 実装計画案 ✅
|
||
|
|
**内容**: 本ドキュメント セクション5
|
||
|
|
|
||
|
|
### 5. 推奨事項 ✅
|
||
|
|
**結論**: **Option 2 (Exit PHIのみ実装)** を推奨
|
||
|
|
|
||
|
|
**根拠**:
|
||
|
|
- 最小工数 (14-19時間) で目標達成
|
||
|
|
- 既存実装を活用し、リスク低減
|
||
|
|
- 段階的移行の道筋が明確
|
||
|
|
|
||
|
|
**次のアクション**:
|
||
|
|
1. ユーザーに Option 2 を提案
|
||
|
|
2. 承認後、実装開始 (Step 1-4)
|
||
|
|
3. Test 2 パス確認
|
||
|
|
4. 必要に応じて Phase C (完全版) への移行を検討
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. 調査手法
|
||
|
|
|
||
|
|
### 実施した調査
|
||
|
|
1. ✅ コード精読: `lang/src/compiler/` 配下の関連ファイル
|
||
|
|
- `loopssa.hako`, `loop_form_box.hako`, `block_builder_box.hako`, `mir_schema_box.hako`
|
||
|
|
2. ✅ Rust実装との比較: `src/mir/phi_core/loopform_builder.rs` との対比
|
||
|
|
3. ✅ アーキテクチャ分析: .hakoのMIR生成パイプライン理解
|
||
|
|
- JSON ベースのMIR構築方式を確認
|
||
|
|
4. ✅ 実装シミュレーション: 疑似コードレベルでの実装可能性検証
|
||
|
|
|
||
|
|
### 未確認項目 (要調査)
|
||
|
|
- [ ] .hako の `MapBox.keys()` メソッド存在確認
|
||
|
|
- [ ] .hako コンパイラの ValueId 生成器の実装箇所
|
||
|
|
- [ ] `builder.update_var()` / `builder.get_variable_at_block()` の存在確認
|
||
|
|
- [ ] JSON操作によるPHI命令更新の実装詳細
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 付録A: Rust vs .hako データ構造対応表
|
||
|
|
|
||
|
|
| Rust型 | .hako表現 | 実装例 |
|
||
|
|
|--------|-----------|--------|
|
||
|
|
| `struct CarrierVariable` | `MapBox` | `local car = new MapBox(); car.set("name", "i")` |
|
||
|
|
| `Vec<CarrierVariable>` | `ArrayBox` | `local carriers = new ArrayBox(); carriers.push(car)` |
|
||
|
|
| `HashMap<String, ValueId>` | `MapBox` | `local vars = new MapBox(); vars.set("i", 10)` |
|
||
|
|
| `ValueId` | `IntegerBox` | `local vid = 10` (整数で表現) |
|
||
|
|
| `BasicBlockId` | `IntegerBox` | `local bid = 5` (整数で表現) |
|
||
|
|
|
||
|
|
**注意点**:
|
||
|
|
- .hako は型安全性がないため、フィールドアクセスミスがランタイムエラーになる
|
||
|
|
- Rustの3-4倍のコード量が必要
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 付録B: 参考実装コード (Option 2)
|
||
|
|
|
||
|
|
**完全な実装例は本ドキュメント セクション5参照**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**レポート作成日**: 2025-11-18
|
||
|
|
**次回レビュー**: 実装開始前 (ユーザー承認後)
|
||
|
|
**ドキュメント状態**: READY FOR REVIEW ✅
|