Files
hakorune/docs/development/current/main/phase47-norm-p3-design.md

14 KiB
Raw Blame History

Phase 47: Normalized P3 (If-Sum) Design

Status: Design Complete, Minimal → Extended Dev → Canonical (P3 Core) 実装中 Date: 2025-12-21

Goal

Extend Normalized JoinIR to support Pattern3 (if-sum) loops using the same infrastructure that successfully handles P1/P2.

Key insight: P3 already shares P2's Structured JoinIR foundation (Phase 220), so Normalized extension reuses existing components.

Background: P2 Normalized Success

Phase 43/245B/46 established canonical Normalized for all P2 patterns:

  • Pattern2Mini (simple break)
  • JsonParser skip_whitespace (Trim pattern)
  • JsonParser _atoi (DigitPos + NumberAccumulation)
  • JsonParser _parse_number (multi-carrier)

Infrastructure complete:

  • Structured→Normalized→MIR(direct) pipeline
  • EnvLayout, JpInst/JpOp, StepScheduleBox
  • ConditionEnv, CarrierInfo, ExitLine
  • Mode system (Phase 45), Capability system (Phase 44)

Why P3 Uses Same Normalized

1. Shared Structured JoinIR Foundation (Phase 220)

From joinir-architecture-overview.md (lines 73-84):

Phase 220: P3 if-sum の ConditionEnv 統合完了
- P3 if-sum には ConditionPatternBox + ConditionEnv が必須
- Phase 220-D で loop 条件の変数サポート完了
- Phase 220 で if-sum の expr-result exit contract が P2 と揃った

P3 already uses P2 infrastructure:

  • ConditionEnv (condition analysis)
  • CarrierInfo (state tracking)
  • ExitLine/Boundary (exit handling)
  • LoopHeaderPHI (SSA construction)

2. Pattern Similarity

Aspect P2 (Break) P3 (If-Sum) Shared?
Loop control loop(cond) + break loop(cond) + conditional update Yes
Carriers sum, count, result sum, count (if-conditional) Yes
Exit condition Break early Continue all iterations Different
ConditionEnv Used Used (Phase 220) Yes
ExitLine Used Used Yes

Key difference: P3 has conditional carrier updates inside loop body, vs P2's unconditional updates before break.

3. Normalized Extension Points

P3 needs minimal additions to existing Normalized:

Already working:

  • ConditionEnv (loop + if conditions)
  • CarrierInfo (state tracking)
  • EnvLayout (carrier fields)
  • LoopHeaderPHI (entry/latch values)

Need to add:

  • ConditionalUpdate pattern in StepScheduleBox
    • P2: [HeaderCond, BodyInit, BreakCheck, Updates, Tail]
    • P3: [HeaderCond, IfCond, ThenUpdates, ElseUpdates, Tail]
  • If branching in Normalized JpInst
    • Already exists: If { cond, then_target, else_target, env }
    • Just need to emit for P3 body structure

Architecture: Unified Normalized

┌──────────────────────────────────────────┐
│   Structured JoinIR (Pattern1-4 共通)    │
│  - ConditionEnv (P2/P3/P4 統一 Phase 220) │
│  - CarrierInfo                           │
│  - ExitLine/Boundary                     │
└──────────────┬───────────────────────────┘
               │
               ▼
┌──────────────────────────────────────────┐
│   Normalized JoinIR (Pattern1-4 共通)    │  ← P3 もここに載せる!
│  - EnvLayout (P2 完成 → P3 拡張)         │
│  - JpInst/JpOp (If 分岐追加)            │
│  - StepScheduleBox (ConditionalUpdate)   │
└──────────────┬───────────────────────────┘
               │
               ▼
┌──────────────────────────────────────────┐
│   MIR (Pattern1-4 共通)                  │
└──────────────────────────────────────────┘

Representative P3 Loops

Phase 47-A: Minimal (sum_count)

Example: phase212_if_sum_min.hako

local sum = 0
local count = 0
local i = 0
local n = 5

loop(i < n) {
    if (i % 2 == 1) {
        sum = sum + i
        count = count + 1
    }
    i = i + 1
}

Characteristics:

  • Simple condition: i % 2 == 1
  • Two carriers: sum, count (conditionally updated)
  • One loop param: i (always updated)
  • No break, runs all iterations

Normalized shape:

  • EnvLayout: { i: int, sum: int, count: int }
  • StepSchedule: [HeaderCond(i < n), IfCond(i % 2 == 1), ThenUpdates(sum, count), Updates(i), Tail]

Phase 47-B: Extended dev targets今回の範囲

Fixture Carriers / Params 条件式 EnvLayout 期待
pattern3_if_sum_multi_min i, sum, count i > 0 i, sum, count, len
jsonparser_if_sum_min i, sum i > 0JsonParser 由来の簡約形) i, sum, len

特徴:

  • どちらも if/else を持ち、Else は no-opSelect/If PHI を確実に通すため)
  • MethodCall は含めず、まずは条件+複数キャリア更新に絞った dev 拡張
  • P3 if-sum capability (= P3IfSum) に乗せ、Structured→Normalized→MIR(direct) で A/B 比較する

Complexity: Higher than sum_count (method calls, body-local)

Phase 47-C: Selfhost loops (future)

Complex P3 patterns from selfhost compiler (deferred to later phase).

Implementation Status

Phase 47-A-PREP ( Complete, commit 42ecd7a7):

  • Fixture added: pattern3_if_sum_minimal in normalized/fixtures.rs
  • Test stub added: test_normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured
  • Basic infrastructure for P3 development mode testing

Phase 47-A-IMPL ( Complete, 2025-12-12):

  • StepSchedule renamed and extended: pattern2_step_schedule.rsstep_schedule.rs
  • P3 StepKind added: IfCond, ThenUpdates, ElseUpdates
  • Pattern2 lowering separation: P3 steps panic in P2 lowering責務境界を明確化
  • ShapeGuard: Pattern3IfSumMinimal detection added構造ベース検出
  • Normalized bridge: normalize_pattern3_if_sum_minimal を通じて P3 最小ケースを Normalized→MIR(direct) パイプラインに統合
  • Runner / VM tests: P3 minimal について Structured 経路と Normalized→MIR(direct) 経路が一致することを dev-only スイートで確認
  • 938/938 tests PASS退行なし

Phase 47-B ( Extended dev):

  • Fixture 拡張: pattern3_if_sum_multi_min.program.jsonsum+count / jsonparser_if_sum_min.program.json を normalized_dev フィクスチャに追加
  • ShapeGuard: Pattern3IfSumMulti / Pattern3IfSumJson 追加、capability=P3IfSum
  • Normalizer/Bridge: P3 if-sum multi/json を Structured→Normalized→MIR(direct) で dev 実行、Structured と一致
  • Tests: normalized_pattern3_if_sum_multi_vm_bridge_direct_matches_structured / normalized_pattern3_json_if_sum_min_vm_bridge_direct_matches_structured

Phase 47-C ( Canonical 化):

  • P3 if-sum minimal/multi/json を canonical Normalized セットに昇格mode/env に関わらず direct ルート)
  • Bridge/runner は P2 と同様に P3 を常時 Normalized→MIR(direct) へルーティング
  • Docs/overview を canonical セット拡張に合わせて更新

Implementation Strategy

Phase 47-A: Minimal sum_count (dev-only, 実装済みの範囲)

Goal: Prove P3 can use Normalized infrastructure with minimal additions.

実装済みステップ:

  1. ShapeGuard: Pattern3IfSumMinimal shape 追加
    • Compare + Select + tail call を持つ 3 関数構成の P3 if-sum 最小パターンを検出。
  2. StepScheduleBox: P3 用 StepKind 追加
    • IfCond / ThenUpdates / ElseUpdatesstep_schedule.rs に導入し、P2/P3 共通の箱として再利用。
  3. Normalized loweringminimal:
    • normalize_pattern3_if_sum_minimal により、P3 最小ケースを P2 と同じ器の NormalizedModule に変換し、direct ブリッジで扱える形に整備。
  4. Tests:
    • Runner 経路: normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured
    • Normalization 経路: test_phase47a_pattern3_if_sum_minimal_normalizationshape + normalize 成功)
    • (詳細な VM Bridge 比較は Phase 47-B 以降で拡張していく)

Dev fixture: apps/tests/phase212_if_sum_min.hako(最小 if-sum パターン)

Phase 47-B: array_filter (dev-only)

Goal: Extend to body-local + method calls.

Additions:

  • Body-local handling in EnvLayout (already exists for P2 DigitPos)
  • Method call in if condition (ExprLowerer already supports)

Phase 47-C: Canonical promotion

Goal: Move P3 minimal from dev-only to canonical (like P2).

Criteria:

  • All invariants verified (Phase 47-A/B tests passing)
  • No regressions in 937+ tests
  • Performance acceptable (Normalized vs Structured comparison)

Normalized Components for P3

EnvLayout Extension

P2 example:

struct Pattern2Env {
    i: int,      // loop param
    sum: int,    // carrier
}

P3 extension (same structure):

struct Pattern3Env {
    i: int,      // loop param
    sum: int,    // carrier (conditionally updated)
    count: int,  // carrier (conditionally updated)
}

No new fields needed - P3 carriers work same as P2.

StepScheduleBox Extension

P2 steps:

enum StepKind {
    HeaderCond,   // loop(cond)
    BodyInit,     // local ch = ...
    BreakCheck,   // if (cond) break
    Updates,      // sum = sum + 1
    Tail,         // i = i + 1
}

P3 addition:

enum StepKind {
    // ... existing P2 steps
    IfCond,           // if (cond) in body
    ThenUpdates,      // carrier updates in then branch
    ElseUpdates,      // carrier updates in else branch (if any)
}

P3 schedule:

// sum_count pattern
[HeaderCond, IfCond, ThenUpdates, Updates, Tail]

// vs P2 pattern
[HeaderCond, BodyInit, BreakCheck, Updates, Tail]

JpInst Reuse

Already exists in Normalized (from P2):

pub enum JpInst {
    Let { dst, op, args },
    If { cond, then_target, else_target, env },  // ← P3 uses this!
    TailCallFn { target, args },
    TailCallKont { target, args },
}

P3 usage:

  • If instruction for body if-statement
  • then_target → block with carrier updates
  • else_target → block without updates (or with different updates)

No new JpInst needed!

Testing Strategy

Phase 47-A: Minimal

Test (runner-based, implemented): normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured

#[cfg(feature = "normalized_dev")]
#[test]
fn test_normalized_pattern3_if_sum_minimal() {
    let source = r#"
        local sum = 0
        local count = 0
        local i = 0
        local n = 5
        loop(i < n) {
            if (i % 2 == 1) {
                sum = sum + i
                count = count + 1
            }
            i = i + 1
        }
        print("sum = " + sum.to_string())
        print("count = " + count.to_string())
    "#;

    // 現在は Runner ベースで Structured→Normalized→Structured roundtrip のみ実装済み。
    // VM Bridge での Normalized→MIR(direct) 比較は後続ステップ。
}

Expected outputphase212_if_sum_min.hako 相当): sum = 23 回中 2 回加算)

Phase 47-B: array_filter

Test: test_normalized_pattern3_array_filter

Similar structure, verify method calls + body-local work in Normalized.

Success Criteria

Phase 47-A complete when:

  1. test_normalized_pattern3_if_sum_minimal passes (dev-only)
  2. Structured→Normalized→MIR(direct) output matches Structured→MIR
  3. All 937+ tests still pass (no regressions)
  4. ShapeGuard can detect Pattern3IfSumMinimal
  5. Documentation updated (architecture overview, CURRENT_TASK)

Phase 47-B complete when:

  1. array_filter test passes (dev-only)
  2. Body-local + method calls work in P3 Normalized

Phase 47-C complete when:

  1. P3 minimal promoted to canonical (always Normalized)
  2. Performance validated

Scope Management

In Scope (Phase 47-A):

  • Minimal P3 (sum_count pattern)
  • Dev-only Normalized support
  • Reuse P2 infrastructure (ConditionEnv, CarrierInfo, ExitLine)

Out of Scope (deferred):

  • Complex P3 patterns (nested if, multiple conditions)
  • Canonical promotion (Phase 47-C)
  • Pattern4 (continue) support (separate NORM-P4 phase)
  • Selfhost loops (later phase)

File Impact Estimate

Expected modifications (Phase 47-A):

  1. shape_guard.rs: +20 lines (Pattern3IfSumMinimal shape)
  2. step_schedule.rs: +40 lines (P3 step kinds, rename from pattern2_*)
  3. normalized_bridge/direct.rs: +60 lines (If instruction handling)
  4. tests/normalized_joinir_min.rs: +30 lines (P3 test)
  5. phase47-norm-p3-design.md: +200 lines (this doc)
  6. joinir-architecture-overview.md: +10 lines (Phase 47 section)
  7. CURRENT_TASK.md: +5 lines (Phase 47 entry)

Total: ~365 lines (+), pure additive (no P2 code changes)

Benefits

  1. Infrastructure reuse: 90% of P2 Normalized code works for P3
  2. Unified pipeline: All patterns (P1/P2/P3) use same Normalized
  3. Incremental rollout: Dev-only → canonical, same as P2
  4. Clear path to P4: Pattern4 (continue) follows same approach

Next Steps After Phase 47

  1. NORM-P4: Pattern4 (continue) Normalized support
  2. Canonical promotion: Move P3/P4 from dev-only to canonical
  3. Selfhost loops: Complex patterns from selfhost compiler
  4. Performance optimization: Profile Normalized vs Structured

References