Files
hakorune/docs/development/current/main/phases/phase-255
tomoaki 64f679354a fix(joinir): Phase 256 P1 - Carrier PHI wiring and parameter mapping (in progress)
**Status**: Core carrier PHI issue partially resolved, debugging loop body

**Progress**:
 Task 1: split_scan_minimal.rs Carriers-First ordering (6 locations)
 Task 2: pattern7_split_scan.rs boundary configuration (host/join inputs, exit_bindings, expr_result)
 Result now flows from k_exit to post-loop code (RC issue resolved)
⚠️  Loop body instruction execution needs review

**Key Fixes**:
1. Fixed host_inputs/join_inputs to match main() params Carriers-First order
2. Added result to exit_bindings (CarrierRole::LoopState)
3. Added result back to loop_invariants for variable initialization
4. Added expr_result=join_exit_value_result for loop expression return
5. Fixed jump args to k_exit to include all 4 params [i, start, result, s]

**Current Issue**:
- Loop body type errors resolved (String vs Integer fixed)
- New issue: Loop body computations (sep_len) undefined in certain blocks
- Likely cause: JoinIR→MIR conversion of local variables needs review

**Next Steps**:
- Review JoinValueSpace allocation and ValueId mapping in conversion
- Verify loop_step instruction ordering and block structure
- May need to refactor bound computation or revisit split algorithm

🤖 Generated with Claude Code
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-20 01:24:04 +09:00
..

Status: Completed Scope: Phase 255 (Pattern 6 multi-param loop wiring/PHI 対応) Related:

  • docs/development/current/main/10-Now.md
  • docs/development/current/main/phases/phase-254/README.md

Phase 255: Multi-param loop の boundary/PHI/wiring を SSOT 化する

前フェーズPhase 254からの引き継ぎ

Phase 254 で Pattern 6 (ScanWithInit) の実装が完了したが、integration テストで失敗:

[ERROR] ❌ [rust-vm] VM error: Invalid value:
[rust-vm] use of undefined value ValueId(10)
(fn=StringUtils.index_of/2, last_block=Some(BasicBlockId(4)),
 last_inst=Some(Compare { dst: ValueId(14), op: Ge, lhs: ValueId(10), rhs: ValueId(13) }))

根本原因

JoinIR→MIR merge/boundary システムが複数ループ変数を想定していない

現状の仕様Pattern 1-5

  • 単一ループ変数前提(例: i のみ)
  • with_loop_var_name() が1つの変数名を受け取る
  • exit_bindings が単一 carrier を想定

Pattern 6 の要求3変数ループ

index_of(s, ch) {
    local i = 0
    loop(i < s.length()) {
        if s.substring(i, i + 1) == ch { return i }
        i = i + 1
    }
    return -1
}

必要な変数:

  • s: haystackループ不変
  • ch: needleループ不変
  • i: loop indexループ状態

問題の詳細

  1. PHI ノード作成の不足:

    // 期待: 3つの PHI ノード
    %4 = phi [%0, entry], [%4, loop]  // s
    %5 = phi [%1, entry], [%5, loop]  // ch
    %6 = phi [%2, entry], [%6, loop]  // i
    
    // 実際: 1つだけ作られる
    %4 = phi [%0, entry], [%4, loop]  // s だけ
    // %5 と %6 が undefined → 実行時エラー!
    
  2. 影響箇所:

    • JoinInlineBoundaryBuilder::with_loop_var_name() - 単一変数想定
    • LoopExitBinding の使い方 - exit_bindings に複数指定しても PHI が作られない
    • JoinIRConversionPipeline の merge 処理 - 複数 PHI 作成に未対応

解決方針SSOT 化)

方針: LoopState と Invariants を分けて wiring

LoopState変化する変数:

  • i: ループカウンタ
  • 毎イテレーションで更新される
  • PHI ノードが必要
  • exit_binding で final value を取得

Invariants不変な変数:

  • s, ch: ループ内で参照するが変化しない
  • PHI ノードは必要だが、すべてのイテレーションで同じ値
  • phi [init, init, init, ...] の形になる

実装戦略

Option A推奨: Boundary に invariants フィールド追加

pub struct JoinInlineBoundary {
    pub join_inputs: Vec<ValueId>,  // 既存main の params
    pub host_inputs: Vec<ValueId>,  // 既存host 側の ValueId

    // 新規追加
    pub loop_invariants: Vec<(String, ValueId)>,  // (変数名, host ValueId)

    pub exit_bindings: Vec<LoopExitBinding>,  // 既存LoopState 用)
    pub loop_var_name: Option<String>,        // 既存(単一変数用、廃止予定)
}

利点:

  • 既存の Pattern 1-5 に影響なし
  • invariants の扱いを明示的に分離
  • PHI 生成ロジックを追加しやすい

Option B: exit_bindings を拡張

pub enum CarrierRole {
    LoopState,       // 既存: 変化する変数
    ConditionOnly,   // 既存: 条件のみ
    LoopInvariant,   // 新規: ループ不変
}

問題点:

  • CarrierRole::LoopInvariant を追加しても、現状の merge ロジックが対応していない
  • exit_bindings は "exit value" を想定しているが、invariants は "同じ値を保持" という意味合いが異なる

推奨: Option A

  • invariants を明示的に分離
  • merge ロジックに invariants 専用の PHI 生成を追加

実装タスクP0

Task 1: Boundary 構造拡張

ファイル: src/mir/join_ir/lowering/inline_boundary.rs

  1. JoinInlineBoundaryloop_invariants フィールド追加
  2. JoinInlineBoundaryBuilder::with_loop_invariants() メソッド追加

Task 2: PHI 生成ロジック拡張

ファイル: src/mir/join_ir/lowering/inline_boundary.rs または merge 関連

  1. loop_invariants から PHI ノードを生成
  2. すべてのブロックで同じ値を持つ PHI として作成
  3. variable_map に登録

Task 3: Pattern 6 の boundary 構築を修正

ファイル: src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs

  1. with_loop_invariants() を使って s, ch を登録
  2. exit_bindings は i のみLoopState
let boundary = JoinInlineBoundaryBuilder::new()
    .with_inputs(
        vec![s_param, ch_param, i_param],
        vec![s_host, ch_host, i_host],
    )
    .with_loop_invariants(vec![
        (parts.haystack.clone(), s_host),
        (parts.needle.clone(), ch_host),
    ])
    .with_exit_bindings(vec![i_exit_binding])
    .with_loop_var_name(Some(parts.loop_var.clone()))
    .build();

Task 4: Unit Tests

ファイル: src/mir/join_ir/lowering/inline_boundary.rs (tests module)

  1. invariants を含む boundary 作成テスト
  2. PHI ノードが正しく生成されることを確認

Task 5: Integration Tests

実行:

HAKORUNE_BIN=./target/release/hakorune bash tools/smokes/v2/profiles/integration/apps/phase254_p0_index_of_vm.sh
HAKORUNE_BIN=./target/release/hakorune bash tools/smokes/v2/profiles/integration/apps/phase254_p0_index_of_llvm_exe.sh

期待: 両方 PASSexit code 1

禁止事項

  • workaround / by-name 分岐 / ハック禁止
  • Pattern 1-5 の動作を変更しないregression 禁止)
  • フォールバック処理の追加禁止Fail-Fast 原則維持)

受け入れ基準

  • phase254_p0_index_of_vm.sh が PASS
  • phase254_p0_index_of_llvm_exe.sh が PASS
  • 最終的に --profile quick の最初の FAIL が次へ進むindex_of で freeze しない)
  • Pattern 1-5 の既存テストがすべて PASSregression なし)

進捗P0

  • Task 1: Boundary 構造拡張: 未着手
  • Task 2: PHI 生成ロジック拡張: 未着手
  • Task 3: Pattern 6 boundary 修正: 未着手
  • Task 4: Unit Tests: 未着手
  • Task 5: Integration Tests: 未着手