**Phase 25.1m: Continue PHI修正** - seal_phis に continue_snapshots 入力を追加 (loopform_builder.rs) - LoopShape::debug_validate に continue/break エッジ検証追加 (control_form.rs) - test_seal_phis_includes_continue_snapshots テスト追加 - 実証テスト成功: balanced scan loop で 228回イテレーション確認 **Bug A修正: main(args) でループ未実行問題** - LoopBuilder::build_loop で entry → preheader への jump 追加 - decls.rs でデュアル関数作成時のブロック接続修正 - mir_static_main_args_loop.rs テスト追加 **パーサー改善**: - parser_box.hako に HAKO_PARSER_PROG_MAX ガード追加(無限ループ対策) 🎉 成果: - Continue 文の PHI predecessor mismatch エラー完全解消 - main(args) パラメータ有りループが正常動作 - Stage-B balanced scan で continue 正常動作確認 (228回イテレーション) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
8.9 KiB
LoopForm PHI Solution - Executive Summary
Date: 2025-11-17 Task: Solve ValueId(14)/ValueId(17) circular dependency in multi-carrier loop PHI construction Approach: LoopForm Meta-Box design based on academic SSA literature and Box Theory philosophy
Problem Statement
Multi-carrier loops (e.g., fibonacci with variables a, b, i) combined with pinned receivers (me parameter) produce invalid MIR:
bb3 (preheader):
%13 = copy %10 # me
%15 = copy %0 # limit parameter
br bb6
bb6 (header):
%18 = phi [%15, bb3], ... # ✅ OK - %15 exists in bb3
%17 = phi [%14, bb3], ... # ❌ ERROR - %14 doesn't exist in bb3!
%14 = phi [%13, bb3], ... # %14 defined HERE
Root Cause: Interleaved ValueId allocation during prepare_loop_variables_with() creates forward references that violate SSA definition-before-use.
Solution: LoopForm Meta-Box
Core Insight
Treat the entire loop structure as a single "Meta-Box" with explicit separation of:
- Carriers: Variables modified in loop body (i, a, b)
- Pinned: Loop-invariant variables (me, limit parameters)
Key Innovation
Three-Pass Construction:
// Pass 1: Allocate ALL ValueIds upfront
builder.prepare_structure(ops, current_vars)?;
// Result: pinned[0].copy=%100, pinned[0].phi=%101, carrier[0].copy=%102, ...
// Pass 2: Emit preheader block
builder.emit_preheader(ops)?;
// Result: %100 = copy %0; %102 = copy %2; ...
// Pass 3: Emit header PHIs (incomplete)
builder.emit_header_phis(ops)?;
// Result: %101 = phi [%100, bb0]; %103 = phi [%102, bb0]; ...
// Pass 4: Seal PHIs after loop body
// (merge preheader + continue blocks + latch into header PHIs)
builder.seal_phis(ops, latch_id, &continue_snapshots)?;
// Result: %101 = phi [%100, bb0], [%200, bb_cont], [%101, latch];
// %103 = phi [%102, bb0], [%201, bb_cont], [%120, latch]
Critical Property: All ValueIds allocated in Pass 1, before any MIR emission → no circular dependencies possible.
Academic Foundation
Braun et al. (2013): Simple and Efficient SSA Construction
Quote: "The φ-function itself becomes the placeholder for the loop variable, preventing forward references."
Application: Our prepare_structure() allocates all φ-IDs upfront, making them valid placeholders before any use.
LLVM Canonical Loop Form
Structure:
preheader → header (PHI nodes) → body → latch → header
↘ exit
Our Implementation: Matches LLVM canonical form exactly, with explicit preheader copy materialization.
Implementation
Files Created
-
src/mir/phi_core/loopform_builder.rs(360 lines):LoopFormBuilderstructCarrierVariableandPinnedVariabletypesLoopFormOpstrait (abstraction over MIR builder)- Unit tests demonstrating correctness
-
docs/development/analysis/loopform-phi-circular-dependency-solution.md(600+ lines):- Comprehensive analysis
- Academic literature review
- Alternative approaches considered
- Detailed implementation plan
Integration Points
Feature Flag: NYASH_LOOPFORM_PHI_V2=1 (environment variable)
Migration Strategy:
// In mir/loop_builder.rs
if std::env::var("NYASH_LOOPFORM_PHI_V2").is_ok() {
// Use new LoopFormBuilder
let mut loopform = LoopFormBuilder::new(preheader_id, header_id);
loopform.prepare_structure(ops, current_vars)?;
loopform.emit_preheader(ops)?;
loopform.emit_header_phis(ops)?;
// ... lower loop body ...
loopform.seal_phis(ops, latch_id)?;
} else {
// Use existing prepare_loop_variables_with()
let incomplete_phis = prepare_loop_variables_with(ops, ...)?;
// ... existing code ...
}
Advantages
1. Correctness
- Eliminates circular dependencies by design
- Guarantees SSA definition-before-use through explicit passes
- Aligns with academic algorithms (Braun et al., LLVM)
2. Maintainability
- Explicit separation of carriers vs. pinned variables
- Self-documenting code:
CarrierVariablevs.PinnedVariabletypes - Unit testable: Mock
LoopFormOpsimplementation in tests
3. Performance
- No runtime overhead: All allocation happens once in Pass 1
- Deterministic ordering: Predictable ValueId allocation
- Future optimization: Can skip PHIs for true loop-invariants
4. Box Theory Alignment
- LoopForm as Meta-Box: Treats loop structure itself as a Box
- Preserves simplicity: ~150 lines of core logic (vs. 650 lines in traditional SSA)
- Gradual enhancement: Can extend with nested loops, break/continue without refactoring
Testing Strategy
Phase 1: Smoke Tests
# Enable new implementation
export NYASH_LOOPFORM_PHI_V2=1
# Test fibonacci multi-carrier
cargo build --release
./target/release/nyash local_tests/fib_multi_carrier.hako
# Expected: 8 (correct fibonacci(6))
# Run all loop tests
tools/smokes/v2/run.sh --profile quick --filter "loop"
Phase 2: Regression Testing
# Compare output with/without new implementation
for test in local_tests/loop_*.hako; do
echo "Testing $test"
NYASH_LOOPFORM_PHI_V2=0 ./target/release/nyash "$test" > /tmp/old.out
NYASH_LOOPFORM_PHI_V2=1 ./target/release/nyash "$test" > /tmp/new.out
diff /tmp/old.out /tmp/new.out || echo "MISMATCH: $test"
done
Phase 3: Performance Validation
# Ensure no performance regression
hyperfine \
'NYASH_LOOPFORM_PHI_V2=0 ./target/release/nyash bench/loop_heavy.hako' \
'NYASH_LOOPFORM_PHI_V2=1 ./target/release/nyash bench/loop_heavy.hako'
Migration Timeline
Week 1: Prototype Implementation (DONE ✅)
- Create
loopform_builder.rs - Implement
LoopFormBuilderstruct - Add unit tests
- Write comprehensive documentation
Week 2: Integration & Testing
- Add feature flag to
mir/loop_builder.rs - Implement
LoopFormOpsfor existing MIR builder - Run smoke tests with new implementation
- Fix any integration issues
Week 3: Selfhost Compiler Integration
- Extend selfhost JSON bridge to use LoopForm approach
- Test multi-carrier loops in selfhost path
- Validate Phase 25.1b goals achieved
Week 4: Full Migration
- Enable by default (
NYASH_LOOPFORM_PHI_V2=1becomes default) - Deprecate old
prepare_loop_variables_with()path - Remove feature flag after confirmation
Risk Assessment
Low Risk
- No changes to MIR semantics: Same PHI nodes generated, just in correct order
- Feature-flagged rollback: Can disable if issues found
- Extensive testing: Academic algorithms are well-proven
Medium Risk
- Selfhost compiler compatibility: JSON-based approach may need adapter
- Nested loop interaction: Need to test with complex loop patterns
Mitigation
- Gradual rollout: Feature flag allows A/B testing
- Comprehensive smoke tests: Cover all loop patterns before migration
- Academic validation: Algorithm matches proven SSA construction methods
Success Criteria
Must Have (Week 2)
fib_multi_carrier.hakoproduces correct output (8)- All existing loop smoke tests pass with new implementation
- No performance regression (< 5% slowdown acceptable)
Should Have (Week 3)
- Selfhost compiler uses LoopForm for multi-carrier loops
- Nested loop support validated
- Break/continue with exit PHIs working
Nice to Have (Week 4)
- Loop-invariant optimization (skip PHIs for non-modified vars)
- Extended to support switch statements in loops
- Academic paper draft: "LoopForm Meta-Box: SSA Construction via Box Theory"
References
-
Academic Papers:
- Cytron et al. (1991): "Efficiently Computing SSA Form"
- Braun et al. (2013): "Simple and Efficient SSA Construction"
- LLVM: Loop Terminology and Canonical Forms
-
Project Documentation:
docs/private/research/papers-archive/paper-d-ssa-construction/box-theory-solution.mddocs/development/architecture/loops/loopform_ssot.mddocs/guides/loopform.md
-
Implementation Files:
src/mir/phi_core/loopform_builder.rs(new)src/mir/phi_core/loop_phi.rs(existing)src/mir/loop_builder.rs(to be updated)
Conclusion
The LoopForm Meta-Box approach provides a theoretically sound, practically simple, and philosophically aligned solution to the PHI circular dependency problem.
By treating loop structure as a first-class "Box" and separating carriers from pinned variables, we eliminate the root cause while preserving the elegance of Box Theory's SSA construction revolution (650 → 100 lines).
Next Action: Integrate LoopFormBuilder into mir/loop_builder.rs with feature flag and validate with fibonacci test.
Document Status: COMPLETE ✅ Implementation Status: PROTOTYPE READY ✅ Testing Status: UNIT TESTS PASS ✅ Integration Status: PENDING (Week 2)