6.2 KiB
6.2 KiB
Phase 129: Materialize join_k Continuation + LLVM Parity
Goal
- Materialize join_k as a real JoinFunction (not just a concept)
- Achieve VM+LLVM EXE parity for Phase 128 if-only partial assign pattern
- Verify structural properties: join_k exists, PHI禁止 (no PHI in Normalized)
Background
Phase 128 added basic Assign(int literal) support to Normalized builder, but:
- join_k was mentioned in comments but not actually materialized
- The If lowering doesn't generate a join continuation
- post-if statements (e.g.,
return xafter if) aren't supported in Normalized path
Phase 129 fixes this by actually generating join_k as a JoinFunction.
Design
join_k Continuation Pattern
if cond {
x = 2 // then: env_then = env with x=2
} else {
// else: env_else = env (unchanged)
}
print(x) // post-if: needs env from both branches
Normalized Lowering:
then:
x = Const(2)
env_then[x] = new_vid
TailCall(join_k, env_then)
else:
// no assignment
env_else = env (original)
TailCall(join_k, env_else)
join_k(env_phi):
// env_phi is the merged environment
// post-if statements use env_phi
print(env_phi[x])
Ret
Key Properties (SSOT)
- join_k is a JoinFunction: Not a concept, but actual function in JoinModule
- then/else end with TailCall(join_k): Not Ret, not direct post-if
- env merging is explicit: env_phi parameter receives merged environment
- PHI禁止: No PHI instructions in Normalized (env update + continuation only)
Structural Verification
verify_normalized_structure() enforces:
- If node exists → join_k exists (as JoinFunction)
- then/else don't end with Ret (they tail-call join_k)
- join_k has env parameter (for merged environment)
- No PHI instructions (structural check)
Scope
In-Scope (Phase 129)
- If-only patterns (no loops)
- Assign(int literal) RHS only (Phase 128 baseline)
- post-if statements: print/return (minimal set)
- VM + LLVM EXE parity (both must work)
Out-of-Scope
- Loop patterns (Phase 130+)
- Assign(complex expr) RHS (Phase 130+)
- Nested if (Phase 130+)
Implementation Plan
P0: LLVM EXE parity baseline (Phase 128) ✅
- Add
phase128_if_only_partial_assign_normalized_llvm_exe.sh - Verify VM+LLVM parity for Phase 128 baseline
- Regression: phase103, phase118
Status: DONE (commit e7ad3d31b)
P1-B: Materialize join_k (if-as-last) ✅
Target:
src/mir/control_tree/normalized_shadow/if_as_last_join_k.rs- orchestrator:
src/mir/control_tree/normalized_shadow/builder.rs - structure verification:
src/mir/control_tree/normalized_shadow/normalized_verifier.rs - contract parity:
src/mir/control_tree/normalized_shadow/parity_contract.rs
What is supported:
- if-only, and the
ifis the last statement (Phase 129-B) - then/else: TailCall(join_k) with env argument (PHI禁止)
Status: DONE (Phase 129-B: fixture + VM smoke PASS)
P2 (Phase 129-C): Post-if support (return-var) ✅
New fixture: apps/tests/phase129_if_only_post_if_return_var_min.hako
x=1; flag=1; if flag==1 { x=2 }; print(x); return "OK"
Expected: 2 (x updated in then branch)
VM smoke: phase129_if_only_post_if_return_var_vm.sh
NYASH_JOINIR_DEV=1 HAKO_JOINIR_STRICT=1- Verify join_k → post_k continuation works
Implementation:
src/mir/control_tree/normalized_shadow/post_if_post_k.rs(new, 392 lines)- Post-if lowering with post_k continuation
- join_k merges env from then/else → TailCall(post_k, merged_env)
- post_k executes post-if statements → Ret
Status: DONE (Phase 129-C complete)
- Fixture + VM smoke PASS
- Runs through Normalized post_k path for
return xpattern - Structure verification enforces join_k → post_k → Ret
- Note: Current fixture
phase129_if_only_post_if_return_var_min.hakohasprint(x); return "OK"which falls back to legacy (print not in Phase 129-C scope). Simplified test withreturn xconfirmed to use post_k path
P3: Documentation
- This README (DONE)
- Update
10-Now.md/01-JoinIR-Selfhost-INDEX.md/30-Backlog.md
Acceptance Criteria
- ✅ P0: Phase 128 LLVM EXE smoke passes
- ✅ P1-B: join_k materialized for if-as-last (then/else tail-call join_k)
- ✅ P1-B: verify_normalized_structure enforces join_k tailcall + PHI禁止
- ✅ P2 (setup): fixture + VM smoke exist
- ✅ P2 (behavior): post-if path runs via Normalized (no fallback)
- ✅ P2 (Phase 129-C): post_k continuation implemented and verified
- ✅ P3: Documentation updated
- ✅ Regression: phase128, phase129-B all PASS
- ✅
cargo test --libPASS (1155 tests)
Verification Commands
# Unit tests
cargo test --lib
# Smoke tests (baseline)
bash tools/smokes/v2/profiles/integration/apps/phase128_if_only_partial_assign_normalized_vm.sh
bash tools/smokes/v2/profiles/integration/apps/phase128_if_only_partial_assign_normalized_llvm_exe.sh
bash tools/smokes/v2/profiles/integration/apps/phase129_join_k_as_last_vm.sh
# Regression
bash tools/smokes/v2/profiles/integration/apps/phase103_if_only_llvm_exe.sh
bash tools/smokes/v2/profiles/integration/apps/phase118_loop_nested_if_merge_vm.sh
Feedback Points
Box-First Modularization
lower_if_node: Currently ~70 lines, could be split into:generate_join_k_function(create JoinFunction)lower_if_branches(then/else tail calls)- Single responsibility principle
Fail-Fast Opportunities
- verify_normalized_structure should fail early if:
- If exists but no join_k found
- then/else don't tail-call join_k
- join_k has no env parameter
Legacy Findings
- Current
verify_branch_is_return_literal: Too restrictive for Phase 129- Should allow Assign statements in branches (Phase 128 already supports)
- Should verify tail-call to join_k (not just Return)
Related Phases
- Phase 128: If-only partial assign (baseline)
- Phase 113: If-only partial assign parity (StepTree path)
- Phase 121-127: StepTree→Normalized foundation
- Phase 130+: Loop patterns, complex RHS
Notes
- Dev-only:
joinir_dev_enabled()+HAKO_JOINIR_STRICT=1required - PHI禁止: Normalized path doesn't use PHI (env update + continuation instead)
- join_k naming: Could use
join_k,k_join, or auto-generate unique ID