2025-12-18 07:18:00 +09:00
|
|
|
# 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 x` after 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)
|
|
|
|
|
|
|
|
|
|
1. **join_k is a JoinFunction**: Not a concept, but actual function in JoinModule
|
|
|
|
|
2. **then/else end with TailCall(join_k)**: Not Ret, not direct post-if
|
|
|
|
|
3. **env merging is explicit**: env_phi parameter receives merged environment
|
|
|
|
|
4. **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
|
|
|
|
|
|
2025-12-18 08:18:20 +09:00
|
|
|
### P0: LLVM EXE parity baseline (Phase 128) ✅
|
2025-12-18 07:18:00 +09:00
|
|
|
|
|
|
|
|
- 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)
|
|
|
|
|
|
2025-12-18 08:18:20 +09:00
|
|
|
### P1-B: Materialize join_k (if-as-last) ✅
|
2025-12-18 07:18:00 +09:00
|
|
|
|
2025-12-18 08:18:20 +09:00
|
|
|
**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`
|
2025-12-18 07:18:00 +09:00
|
|
|
|
2025-12-18 08:18:20 +09:00
|
|
|
**What is supported**:
|
|
|
|
|
- if-only, and the `if` is the last statement (Phase 129-B)
|
|
|
|
|
- then/else: TailCall(join_k) with env argument (PHI禁止)
|
2025-12-18 07:18:00 +09:00
|
|
|
|
2025-12-18 08:18:20 +09:00
|
|
|
**Status**: DONE (Phase 129-B: fixture + VM smoke PASS)
|
2025-12-18 07:18:00 +09:00
|
|
|
|
2025-12-18 08:18:20 +09:00
|
|
|
### P2: Post-if support (return-var) 🔜
|
2025-12-18 07:18:00 +09:00
|
|
|
|
|
|
|
|
**New fixture**: `apps/tests/phase129_if_only_post_if_return_var_min.hako`
|
|
|
|
|
```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 continuation works
|
|
|
|
|
|
2025-12-18 08:18:20 +09:00
|
|
|
**Status**:
|
|
|
|
|
- Fixture + VM smoke exist.
|
|
|
|
|
- Not yet guaranteed to run through Normalized join_k path (can still fall back).
|
2025-12-18 07:18:00 +09:00
|
|
|
|
|
|
|
|
### 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
|
2025-12-18 07:54:16 +09:00
|
|
|
- ✅ 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禁止
|
2025-12-18 08:18:20 +09:00
|
|
|
- ✅ P2 (setup): fixture + VM smoke exist
|
|
|
|
|
- [ ] P2 (behavior): post-if path runs via Normalized (no fallback)
|
2025-12-18 07:18:00 +09:00
|
|
|
- [ ] P3: Documentation updated
|
|
|
|
|
- [ ] Regression: phase103, phase118, phase128 all PASS
|
|
|
|
|
- [ ] `cargo test --lib` PASS
|
|
|
|
|
|
|
|
|
|
## Verification Commands
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Unit tests
|
|
|
|
|
cargo test --lib
|
|
|
|
|
|
2025-12-18 08:18:20 +09:00
|
|
|
# Smoke tests (baseline)
|
2025-12-18 07:18:00 +09:00
|
|
|
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
|
2025-12-18 08:18:20 +09:00
|
|
|
bash tools/smokes/v2/profiles/integration/apps/phase129_join_k_as_last_vm.sh
|
2025-12-18 07:18:00 +09:00
|
|
|
|
|
|
|
|
# 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=1` required
|
|
|
|
|
- **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
|