Implementation: - Add make_pattern2_scope_manager() helper for DRY - Header conditions use ExprLowerer for supported patterns - Legacy fallback for unsupported patterns - Fail-Fast on supported patterns that fail Tests: - 4 new tests (all pass) - test_expr_lowerer_supports_simple_header_condition_i_less_literal - test_expr_lowerer_supports_header_condition_var_less_var - test_expr_lowerer_header_condition_generates_expected_instructions - test_pattern2_header_condition_via_exprlowerer Also: Archive old phase documentation (34k lines removed) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
12 KiB
Phase 189: Select Instruction MIR Bridge - ChatGPT Architectural Inquiry
Date: 2025-12-05 Status: Blocking Issue Identified Assigned to: ChatGPT (Architecture & Design Guidance) Related Phase: Phase 188-Impl-3 (Pattern 3 implementation complete except for MIR bridge)
Executive Summary
Phase 188-Impl-3 (Loop with If-Else PHI) has successfully implemented:
- ✅ Pattern 3 JoinIR lowering infrastructure (loop_with_if_phi_minimal.rs)
- ✅ Pattern 3 routing in MIR builder (control_flow.rs)
- ✅ Select instruction definition in JoinIR
- ✅ JoinIR runtime execution for Select
- ✅ JSON serialization for Select
Remaining Blocker: Pattern 3 tests cannot execute because Select instruction conversion from JoinIR to MIR is not implemented.
The Select instruction (JoinIR's ternary operator: cond ? then_val : else_val) cannot be directly represented in MIR's current instruction set. We need a clean architectural approach to convert it to MIR-compatible control flow.
Current Situation
What Works (Pattern 1 & 2)
- Pattern 1 (Simple While Loop): ✅ Fully working (loop_min_while.hako)
- Pattern 2 (Loop with Conditional Break): ✅ Fully working (joinir_min_loop.hako)
- Both use only instructions already implemented in MIR bridge
What Doesn't Work (Pattern 3)
- Pattern 3 (Loop with If-Else PHI): 🔄 Infrastructure complete, execution blocked
- Test case: apps/tests/loop_if_phi.hako
- Expected: Prints "sum=9" (sum of odd numbers 1-5)
- Actual: Fails at MIR bridge conversion with Select instruction
Root Cause: Missing Select → MIR Conversion
// JoinIR lowering generates this (works fine):
let sum_new = alloc_value();
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Select {
dst: sum_new,
cond: if_cond,
then_val: sum_then,
else_val: sum_else,
}));
// MIR bridge conversion fails here:
// src/mir/join_ir_vm_bridge/convert.rs line ~XXX
MirLikeInst::Select { .. } => {
return Err("Select instruction not yet implemented".into());
// ❌ This is where we get stuck
}
Why Select Can't Be Direct in MIR
MIR instruction set (14 instructions) doesn't have a direct ternary/select instruction:
- Arithmetic: Const, UnaryOp, BinOp, Compare, TypeOp
- Memory: Load, Store
- Control: Branch (goto two targets), Jump (goto one target), Return
- Other: Phi, NewBox, BoxCall
Problem: Select needs to produce a value and involve control flow, which MIR separates:
- Control flow → Branch/Jump instructions that create multiple basic blocks
- Value production → Phi nodes at merge points
Technical Challenge: Select → MIR Conversion
Pattern of the Conversion
A JoinIR Select must be converted to:
- Branch block with the condition → splits into then_block and else_block
- Then block → computes
then_val - Else block → computes
else_val - Merge block → Phi instruction that merges the two values
Example: JoinIR vs MIR Representation
JoinIR (what we have):
let if_cond = ... // compute condition
let sum_then = sum + i // then branch
let sum_else = sum + 0 // else branch
let sum_new = Select { // ternary select
cond: if_cond,
then_val: sum_then,
else_val: sum_else,
}
// sum_new is ready to use
MIR (what we need to generate):
block_before:
if_cond = Compare(...)
Branch if_cond → block_then, block_else
block_then:
sum_then = BinOp(Add, sum, i)
Jump → block_merge [sum_then]
block_else:
sum_else = BinOp(Add, sum, 0)
Jump → block_merge [sum_else]
block_merge:
sum_new = Phi([sum_then, sum_else]) // merges two values
// sum_new ready to use
Questions for ChatGPT
1. Clean Conversion Strategy
How should we cleanly structure the Select → MIR conversion in the codebase?
Considerations:
- Should this be a separate transformation function or inline in the converter?
- What's the best way to handle the block generation and control flow linking?
- Should we use existing utilities (e.g., block management functions) or create new ones?
Reference: Look at how existing Select-like constructs are handled:
- If/Then/Else lowering in
src/mir/builder/if_builder.rs(lines ~200-350) - Phi generation in
src/mir/join_ir/lowering/if_select.rs - How Branch/Phi are currently being connected
2. Block Creation and Management
The conversion needs to create new MIR blocks. How should this interact with existing block management?
Questions:
- Should new blocks be pre-allocated (like LoopForm does)?
- Should the conversion happen immediately or deferred?
- How do we ensure proper linking between blocks (edges, dominance)?
- Do we need metadata tracking for Select block origins?
3. Value ID Continuity
JoinIR uses local ValueIds (0, 1, 2, ...), which get remapped to host ValueIds. How do we handle the intermediate values?
Context:
- JoinModule is converted to MirModule via
convert_join_module_to_mir_with_meta() - ValueIds are already remapped at this stage
- Then blocks are merged via
merge_joinir_mir_blocks()
Question: Should the Select expansion happen:
- (A) In
convert_join_module_to_mir_with_meta()(early in the JoinModule→MirModule stage)? - (B) In the MIR bridge converter (current location)?
- (C) In
merge_joinir_mir_blocks()(late, after remapping)?
4. Code Organization
Where should the Select conversion logic live?
Options:
- Option A: New file
src/mir/join_ir_vm_bridge/select_expansion.rs- Pros: Single responsibility, easy to test, clear naming
- Cons: Small file, might split related code
- Option B: Expand
src/mir/join_ir_vm_bridge/convert.rs- Pros: Centralized conversion logic
- Cons: File gets larger, mixed concerns
- Option C: Create in JoinIR lowering layer (
src/mir/join_ir/lowering/select_expansion.rs)- Pros: Closer to where Select is created
- Cons: Mixing JoinIR and MIR concerns
What's the architectural pattern used elsewhere in the codebase?
5. Performance and Optimization Implications
Select expansion creates extra blocks and Phi nodes. Any concerns?
Questions:
- Will the VM interpreter handle this correctly?
- Does the LLVM backend optimize this back to conditional moves?
- Should we add a Select-fast-path for simple cases (where Select result isn't used in loops)?
- How do we measure the quality of generated MIR?
6. Testing Strategy
How should we validate the Select expansion?
Suggested Approach:
- Existing test: apps/tests/loop_if_phi.hako (integration test)
- New unit test: Test Select expansion in isolation
- MIR output inspection: Compare before/after
- Round-trip test: JoinIR → MIR → VM execution
Your input: What's the minimal test to validate correctness?
7. Future Extensibility
Pattern 3 uses Select for single variable mutation. What about more complex patterns?
Consider:
- Pattern 4+: Multiple variables mutating in if/else?
- IfMerge instruction (which we have but don't use)?
- Should IfMerge replace Select as the canonical form?
- How does this relate to Phase 33's IfMerge lowering work?
Existing References in Codebase
Similar Transformations
-
If-Select lowering (
src/mir/join_ir/lowering/if_select.rs)- Converts if/else with PHI to JoinIR Select instruction
- ~180 lines, well-structured
- Insight: This is the opposite direction (MIR→JoinIR Select)
-
If builder (
src/mir/builder/if_builder.rs)- Creates MIR blocks for if/then/else
- Lines 200-350 show block creation and Phi handling
- Insight: Shows how to properly structure MIR control flow
-
Loop builder (
src/mir/builder/loop_builder.rs)- Generates loop control flow with Phi nodes
- Handles block linking and edge management
- Insight: Established patterns for block management
-
LoopForm (
src/mir/loop_pattern_detection.rs+src/mir/mir_loopform.rs)- Entire subsystem for loop pattern detection
- Pre-allocates and links blocks
- Insight: Large-scale block transformation pattern
Related Files
src/mir/join_ir_vm_bridge/convert.rs(current location of Select error)src/mir/join_ir/lowering/inline_boundary.rs(ValueId mapping)src/mir/join_ir/lowering/loop_patterns.rs(routing logic)
Proposed Implementation Phases
Phase 189-A: Design & Validation (ChatGPT Input)
- Architectural decision on conversion location (early vs late in pipeline)
- Code organization approach
- Test strategy definition
Phase 189-B: Core Implementation
- Implement Select → Branch + Then + Else + Phi conversion
- Unit tests for conversion correctness
- Integration test with loop_if_phi.hako
Phase 189-C: Optimization & Polish
- Performance validation
- MIR output quality analysis
- Documentation and comments
Success Criteria
✅ Minimal: Pattern 3 test (loop_if_phi.hako) produces sum=9
✅ Better: All MIR patterns (1-3) work correctly
✅ Best: Design is extensible for future patterns (4+)
Timeline Context
- Phase 188-Impl-1: Pattern 1 ✅ Complete (loop_min_while.hako)
- Phase 188-Impl-2: Pattern 2 ✅ Complete (joinir_min_loop.hako)
- Phase 188-Impl-3: Pattern 3 🔄 Lowering complete, MIR bridge pending
- Phase 189: Select expansion (THIS INQUIRY)
- Phase 190+: Additional patterns, optimizations, cleanup
Key Files for Reference
docs/development/current/main/phase188-select-implementation-spec.md ← Spec
docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/
├── design.md ← Full 1648-line design document
└── pattern3-implementation-spec.md ← Pattern 3 detailed spec
src/mir/join_ir/lowering/
├── loop_with_if_phi_minimal.rs ← Pattern 3 lowering (381 lines)
├── if_select.rs ← Similar conversion (opposite dir)
└── inline_boundary.rs ← ValueId mapping
src/mir/join_ir_vm_bridge/convert.rs ← Current error location (line ~XXX)
src/mir/builder/
├── if_builder.rs ← Example: if/else block creation
└── loop_builder.rs ← Example: loop block management
apps/tests/loop_if_phi.hako ← Pattern 3 test (blocked)
Appendix: Test Case Details
Pattern 3 Test: loop_if_phi.hako
static box Main {
main(args) {
local console = new ConsoleBox()
local i = 1
local sum = 0
loop(i <= 5) {
if (i % 2 == 1) { sum = sum + i } else { sum = sum + 0 }
i = i + 1
}
console.println("sum=" + sum)
return 0
}
}
Execution trace:
- i=1: 1%2==1 → sum=0+1=1
- i=2: 2%2==0 → sum=1+0=1
- i=3: 3%2==1 → sum=1+3=4
- i=4: 4%2==0 → sum=4+0=4
- i=5: 5%2==1 → sum=4+5=9
- i=6: 6<=5 is false → exit, print "sum=9"
Expected output: sum=9\n
ChatGPT Requested Deliverables
-
Architectural Recommendation (Section 1-4)
- Clean conversion strategy
- Code organization approach
- Block management pattern
- ValueId handling strategy
-
Design Document (reference material provided)
- Template for Phase 189-A design writeup
- Implementation checklist
-
Code Pattern Examples (if helpful)
- Reference snippets from similar transformations
- Pseudocode for Select expansion algorithm
-
Phase 189 Kickoff Plan
- Implementation order
- Testing approach
- Success metrics
Status: Awaiting ChatGPT input on architectural approach before proceeding to Phase 189-B implementation.
🤖 Created by: Claude Code 📅 Date: 2025-12-05 🎯 Target: Phase 189 - Select Instruction MIR Bridge Implementation Status: Historical