5ee3b62042
refactor(joinir): Phase 287 P0.4 - Extract header_phi_prebuild
...
Extract header PHI pre-build orchestration to header_phi_prebuild.rs
(~220 lines). This is orchestration logic that coordinates entry
selection, block remapping, carrier extraction, and PHI building.
Changes:
- NEW: merge/header_phi_prebuild.rs (220 lines)
- MOD: merge/mod.rs: 1,233 → ~1,027 lines (-206 lines)
- Function: prebuild_header_phis() - orchestrates PHI pre-build
- Helper: get_default_entry_block() - fallback for no boundary
Orchestration Responsibilities:
- Entry function selection (via entry_selector SSOT)
- Block remapping (loop_header vs merge_entry)
- Carrier extraction from boundary (with exit_bindings filtering)
- LoopHeaderPhiBuilder invocation
- Reserved ValueId collection (PHI dsts + function params)
Verification:
- Build: 0 errors
- Pattern6: RC:9 ✅
- Smoke: 154/154 PASS (verified via quick profile)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-27 10:21:28 +09:00
fb2ac627da
refactor(joinir): Phase 287 P0.3 - Extract entry_selector (SSOT)
...
Extract entry function selection logic to entry_selector.rs (93 lines).
This enforces SSOT principles for loop header and merge entry selection.
SSOT Strategy:
1. Prefer boundary.loop_header_func_name (explicit specification)
2. Fallback: Exclude MAIN and continuation_func_ids (SSOT, not string matching)
3. Never use "k_exit" prefix heuristics
Changes:
- NEW: merge/entry_selector.rs (43 lines net after extraction)
- MOD: merge/mod.rs: 1,269 → ~1,233 lines (-36 lines)
- Functions:
- select_loop_step_func_name() (loop header SSOT)
- select_merge_entry_func() (Pattern 3 if-sum support)
- get_function() (helper with error handling)
Verification:
- Build: 0 errors
- Pattern6: RC:9 ✅
- Smoke: 154/154 PASS (verified via quick profile)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-27 10:17:49 +09:00
95fef8696d
refactor(joinir): Phase 287 P0.2 - Extract value_remapper
...
Extract remap_values() to value_remapper.rs (46 lines). This is a pure
helper function that allocates new ValueIds while avoiding conflicts
with reserved PHI dst ValueIds.
Changes:
- NEW: merge/value_remapper.rs (Phase 3 helper)
- MOD: merge/mod.rs: 1,315 → ~1,269 lines (-46 lines)
- Delegation: value_remapper::remap_values() called from orchestrator
Verification:
- Build: 0 errors
- Pattern6: RC:9 ✅
- Smoke: 154/154 PASS (verified via quick profile)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-27 10:14:27 +09:00
433e1d45c0
refactor(joinir): Phase 287 P0.1 - Move verification to debug_assertions
...
- Move verify_no_phi_dst_overwrite() to debug_assertions.rs
- Move verify_phi_inputs_defined() to debug_assertions.rs
- Move verify_joinir_contracts() to debug_assertions.rs
- Remove duplicate get_instruction_dst() from mod.rs
- mod.rs: 1,555 → ~1,380 lines (-176 lines)
- Semantic invariance: 154/154 smoke tests PASS, Pattern6 RC:9
Phase 287 P0: Big Files Refactoring (意味論不変)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-27 10:10:59 +09:00
a04b48416e
fix(joinir): Phase 287 P2 - Pattern6 nested loop latch overwrite fix
...
Fix infinite loop in Pattern6 (nested loop minimal) caused by main→loop_step
overwriting k_inner_exit→loop_step latch values.
Root cause: JoinIR main entry block was incorrectly treated as BackEdge,
causing it to overwrite the correct latch incoming values set by the true
back edge (k_inner_exit → loop_step).
Solution:
- Restrict latch recording to TailCallKind::BackEdge only
- Treat only MAIN's entry block as entry-like (not loop_step's entry block)
- Add debug_assert! to detect double latch set in future
Refactoring:
- Extract latch recording to latch_incoming_recorder module (SSOT)
- Add boundary.loop_header_func_name for explicit header identification
- Strengthen tail_call_classifier with is_source_entry_like parameter
Tests: apps/tests/phase1883_nested_minimal.hako → RC:9 (was infinite loop)
Smoke: 154/154 PASS, no regressions
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-27 09:39:29 +09:00
bbfc3c1d94
refactor(joinir): Phase 287 P2 - Strengthen BackEdge/latch conditions (WIP)
...
**Problem**: Phase 188.3 Pattern6 (nested loop) encounters infinite loop
- inner_step → inner_step (self-recursion) incorrectly classified as BackEdge
- → redirects to outer header (loop_step) instead of inner_step entry
- is_recursive_call causes inner recursion to overwrite outer latch values
- → PHI receives wrong values → i doesn't increment → infinite loop
**Fix 1: BackEdge classification strictness** (tail_call_classifier.rs)
- Add `is_target_loop_entry` parameter to classify_tail_call()
- BackEdge ONLY when target==loop_step (entry_func), not inner_step
- Prevents inner_step → inner_step from redirecting to outer header
**Fix 2: latch_incoming guard** (instruction_rewriter.rs)
- Change condition from `is_recursive_call || is_target_loop_entry`
to `is_target_loop_entry` only
- Prevents inner_step self-recursion from overwriting outer loop's latch
- set_latch_incoming() now called with correct values (verified by debug)
**Status**: 🚧 WIP - Infinite loop still occurs
- set_latch_incoming('i', BasicBlockId(8), ValueId(21)) ✅ Called correctly
- But final PHI: `phi [%4, bb8]` instead of `phi [%21, bb8]` ❌
- Root cause likely in PHI generation (merge/mod.rs), not latch_incoming
- Next: Investigate why latch_incoming values aren't used in PHI
**Files**:
- src/mir/builder/control_flow/joinir/merge/tail_call_classifier.rs
- src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-27 08:32:14 +09:00
d0527bcc2a
feat(joinir): Phase 188.3-P3.3 - Pattern6 continuation generation + Call callee fix
...
Phase 3-3 完了: 4関数モデル JoinIR 生成
- nested_loop_minimal.rs (337行, 新規): 4関数モデル実装
- main(): エントリーポイント
- loop_step(i, sum): outer loop header
- inner_step(j, i_outer, sum): inner loop (tail recursion)
- k_inner_exit(i, sum): outer continuation after inner loop
- k_exit(sum): 最終 exit
- pattern6_nested_minimal.rs: lowering pipeline 実装
- boundary 構築 (continuation_func_ids 設定)
- JoinIRConversionPipeline 呼び出し
- instruction_rewriter.rs: latch incoming 拡張
- continuation→header 呼び出し対応
Call callee 修正:
- call_generator.rs: callee フィールドを Callee::Global に設定
- joinir_block_converter.rs: emit_call_pair 使用に統一
smoke test 追加:
- phase1883_nested_minimal_vm.sh (integration)
既知の問題 (次タスク):
- ValueId(104) undefined: PHI/merge 問題
- JoinIR 関数パラメータの MIR マッピングが不完全
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-27 06:51:43 +09:00
fa00ed3018
refactor(joinir): Split contract_checks.rs into 2 files (Phase 286C-4.3)
...
Split 1,239-line contract_checks.rs into responsibility-based modules
for better maintainability and clarity.
## Changes
1. **New file: debug_assertions.rs** (440 lines)
- 6 debug-only verification functions (panic! on violation)
- All functions guarded with #[cfg(debug_assertions)]
- Excluded from release builds
- Functions:
* verify_loop_header_phis()
* verify_exit_line()
* verify_exit_phi_no_collision()
* verify_valueid_regions()
* verify_condition_bindings_consistent()
* verify_header_phi_dsts_not_redefined()
2. **Updated: contract_checks.rs** (1,239 → 848 lines, -391 lines)
- Kept 6 Fail-Fast functions (Result<(), String>)
- Kept all 13 unit tests
- Removed debug-only functions and imports
3. **Updated: mod.rs**
- Added `mod debug_assertions;` declaration
## Responsibility Split
- **contract_checks.rs**: Fail-Fast contracts (production)
- Return errors with diagnostic messages
- Run in both debug and release builds
- **debug_assertions.rs**: Debug-only assertions (development)
- Panic on contract violations
- Excluded from release builds (#[cfg(debug_assertions)])
## Benefits
- Single Responsibility Principle (each file <850 lines)
- Clear separation: Fail-Fast vs Debug-only
- Improved maintainability (localized changes)
- Better build performance (debug code stripped in release)
## Test Results
- ✅ Build: 0 errors
- ✅ Smoke tests: 45/46 PASS (no regression)
- ❌ core_direct_array_oob_set_rc_vm: FAIL (existing known issue)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 06:08:46 +09:00
ad1a8bd8ec
feat(joinir): Add carrier_inputs completeness contract (Phase 286C-4.2)
...
Adds Fail-Fast contract to verify carrier_inputs completeness at plan stage,
preventing silent bugs where carrier collection is skipped.
## Changes
1. **contract_checks.rs**:
- Added `verify_carrier_inputs_complete()` function
- Checks all non-ConditionOnly carriers are present in carrier_inputs
- Error tag: `[joinir/contract:C4]` for grep-friendly diagnostics
- Added test helper `make_boundary()` for JoinInlineBoundary construction
- Added 3 unit tests (missing carrier, ConditionOnly skip, valid case)
2. **instruction_rewriter.rs**:
- Call `verify_carrier_inputs_complete()` after plan_rewrites()
- Runs before apply_rewrites() for clean error state
## Contract
For each non-ConditionOnly exit_binding:
- `carrier_inputs[carrier_name]` must exist
Catches bugs where:
- CarrierInputsCollector fails to add a carrier
- plan_rewrites skips a carrier mistakenly
- exit_phi_builder receives incomplete carrier_inputs
## Test Results
- ✅ json_lint_vm: PASS (was FAIL in 286C-4.1 before fix)
- ✅ Full suite: 45/46 PASS (no regression)
- ❌ core_direct_array_oob_set_rc_vm: FAIL (existing known issue)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 05:43:34 +09:00
86dfa30abe
chore(joinir): Phase 286C-5 Step 3 - Remove unused imports
...
Ran `cargo fix --allow-dirty --lib` to automatically remove unused imports
across the codebase. This cleanup is standard maintenance and improves code
hygiene.
**Files Modified**:
- instruction_rewriter.rs: Removed 6 unused imports
- block_remapper::remap_block_id
- LoweringDecision
- ParameterBindingBox
- propagate_value_type_for_inst (2 occurrences)
- apply_remapped_terminator
- PhiAdjustment, ParameterBinding from scan_box
- Other files: Minor unused import cleanup (12 files total)
**No Functional Changes**: Pure cleanup, all tests expected to pass.
Phase 286C-5 progress: 3/4 steps complete
Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 05:18:06 +09:00
14ff126934
refactor(joinir): Phase 286C-5 Step 1 - CarrierInputsCollector Box extraction
...
Extract duplicated carrier_inputs collection logic into a dedicated Box:
**DRY Achievement**:
- Remove duplication between Return fallback (lines 740-763) and ExitJump
handling (lines 876-909)
- Single source of truth for carrier PHI fallback logic
- Reduced code size by ~30 lines (60 duplicated → 30 unified)
**Box Structure**:
- CarrierInputsCollector: Encapsulates carrier PHI collection from header
- Input: boundary + loop_header_phi_info
- Output: Vec<(carrier_name, block_id, value_id)>
- Filters ConditionOnly carriers automatically
- Handles DirectValue fallback to host_slot
**Files Modified**:
- instruction_rewriter.rs: Replace 2 inline blocks with Box calls
- carrier_inputs_collector.rs: New Box implementation (95 lines)
- rewriter/mod.rs: Export new module
**Contract Preserved**:
- Identical logic: ConditionOnly filter → header PHI → DirectValue fallback
- Same logging output format
- No behavior change, pure refactoring
Phase 286C-5 progress: 1/4 steps complete
Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 05:16:22 +09:00
bfc63b0e3c
fix(joinir): collect carrier_inputs for skippable ExitJump (Phase 286C-4.1)
...
After the Phase 286C-4 refactoring, carrier_inputs was not being
collected when a tail call's TailCallKind is ExitJump and the target
is a skippable continuation. This caused json_lint_vm to fail with:
[joinir/phase118/exit_phi/missing_carrier_phi]
exit_bindings carrier 'i' is missing from exit_carrier_phis
Root cause: The 3-stage pipeline refactoring separated Return→Jump
conversion (which collected carrier_inputs) from tail call handling.
When found_tail_call=true, the Return processing was skipped entirely,
but tail call handling didn't collect carrier_inputs.
Fix: Add carrier_inputs collection in the ExitJump (skippable) path
at lines 901-934. This mirrors the fallback logic from the Return
processing path.
Test results: 45/46 PASS (same as before refactoring)
- json_lint_vm: PASS (was FAIL)
- core_direct_array_oob_set_rc_vm: FAIL (unchanged, known issue)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 05:05:49 +09:00
e55665aa22
fix(joinir): verbose flag should not use env var (test pollution)
...
joinir_dev_enabled() was being used in verbose flags, causing debug
output to appear during smoke tests and polluting expected output.
Changed 3 locations from:
let verbose = debug || crate::config::env::joinir_dev_enabled()
To:
let verbose = debug
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 04:42:32 +09:00
5b74b3134a
refactor(orchestrator): Phase 286C-4 Step 4 - Complete 3-stage pipeline (~1150 lines removed)
...
Transformed merge_and_rewrite() from monolithic function to orchestrator:
**File Reduction**:
- Before: 2437 lines
- After: 1289 lines
- Removed: 1148 lines (47% reduction)
**New Architecture**:
- Stage 1: scan_blocks() - Read-only analysis (~200 lines)
- Stage 2: plan_rewrites() - Generate rewritten blocks (~550 lines)
- Stage 3: apply_rewrites() - Mutate builder (~160 lines)
**merge_and_rewrite() Now**:
- Metadata setup (~80 lines)
- Call 3-stage pipeline (~50 lines)
- DirectValue processing (~50 lines)
- Result building (~20 lines)
- Total: ~200 lines (down from ~1350)
**Benefits**:
- Clear separation of concerns (scan/plan/apply)
- No builder mutation until apply stage
- Easier to test and maintain
- Preserves all functionality
Build passes successfully. Phase 286C-4 complete.
2025-12-25 04:09:11 +09:00
8619ed07b9
feat(apply): Phase 286C-4 Step 3 - Implement apply_rewrites() (~160 lines)
...
Implemented apply_rewrites() stage to mutate MirBuilder:
**Block Addition**:
- Add all new blocks to current function
- Debug logging for blocks with 4+ instructions
**Boundary Injection** (~100 lines):
- Call BoundaryInjector::inject_boundary_copies()
- Build value_map for join_inputs and condition_bindings
- Collect PHI dst IDs from loop_header_phi_info
**Context Updates**:
- Add phi_inputs to ctx.exit_phi_inputs
- Add carrier_inputs to ctx.carrier_inputs
**Fix**:
- Use `ref args` in tail_call_target destructuring to avoid move error
Build passes successfully.
2025-12-25 04:04:50 +09:00
21e855d62a
feat(plan): Phase 286C-4 Step 2 - Complete plan_rewrites() (~370 lines)
...
Added parameter binding insertion and terminator conversion to plan_rewrites():
**Parameter Binding (~100 lines)**:
- Generate Copy instructions for tail call arguments
- Handle recursive/continuation/normal tail calls
- Skip bindings for loop header PHIs
- Record latch incoming for loop header PHI
**Terminator Conversion (~270 lines)**:
- Return → Jump conversion using ReturnConverterBox
- Exit value collection using ExitArgsCollectorBox
- Update result.phi_inputs and result.carrier_inputs
- Handle tail call Jump terminators with classification
Plan stage now generates complete RewrittenBlocks ready for apply stage.
Build passes with warnings only.
2025-12-25 04:01:44 +09:00
a78742b6d7
refactor(plan): Phase 286C-4 Step 2 - plan_rewrites() initial implementation
...
Extract block generation logic from merge_and_rewrite() into plan_rewrites():
- Function/block initialization (~70 lines)
- First pass: instruction filtering (~180 lines)
- Span synchronization (~20 lines)
Implemented:
- Instruction filtering using InstructionFilterBox
- Block ID remapping with local_block_map
- PHI dst protection for loop headers
- Deterministic function/block iteration
TODO (Step 2 continuation):
- Parameter binding insertion for tail calls (~100 lines)
- Terminator conversion logic (~270 lines)
- Exit PHI/carrier input collection
Current: ~290 lines extracted, target ~550 lines
Progress: Step 2/4 (plan_rewrites) partial
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 03:57:43 +09:00
a40ee8dda5
refactor(plan): Phase 286C-4 Step 1 - plan_helpers module
...
Create helper functions to support plan_rewrites() extraction:
- build_local_block_map(): Build block ID mapping for a function
- sync_spans(): Synchronize instruction spans after rewriting
These pure functions will be used by both the current monolithic
merge_and_rewrite() and the new plan_rewrites() function.
Progress: Step 1/4 (helpers) complete
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 03:53:42 +09:00
875c5e02fd
refactor(joinir): Phase 286C-2.1 Steps 3-5 - Extract scan logic, fix debug output
...
Step 3 Complete:
- Extract 94 lines of scan logic into scan_blocks()
- Populate RewritePlan with TailCallRewrite, ReturnConversion
- Read-only analysis phase (no mutations)
Steps 4-5 Partial:
- Document 3-stage pipeline architecture
- Infrastructure ready for future extraction
- Remaining extraction deferred to Phase 286C-2.2
Bug Fix:
- Remove joinir_dev_enabled() from verbose flag in scan_blocks()
- Prevents unintended debug output during tests
- Smoke tests now pass (45/46, 1 known fail unrelated)
Current State:
- scan_blocks(): 94 lines ✅ functional
- plan_rewrites(): stub (future extraction ~400 lines)
- apply_rewrites(): stub (future extraction ~200 lines)
- merge_and_rewrite(): ~1300 lines (target ~150 lines)
Build: cargo build --release ✅
Tests: 45/46 pass (1 known JoinIR pattern fail)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 03:45:16 +09:00
bfee1fd451
refactor(joinir): Phase 286C-2.1 Step 4-5 (Partial) - Document 3-stage pipeline structure
...
Steps 3-5 Summary:
- ✅ Step 3: scan_blocks() extraction complete (94 lines, functional)
- ⏳ Step 4-5: Documented plan/apply separation (requires future work)
What was achieved:
1. scan_blocks() now identifies tail calls and returns (read-only)
2. Clear orchestrator structure documented in merge_and_rewrite()
3. Strategic markers show what belongs to each stage
4. Foundation laid for future extraction of plan/apply logic
Current state:
- scan_blocks(): 94 lines (EXTRACTED ✅ )
- plan_rewrites(): Stub (main loop lines 380-1469 contains logic)
- apply_rewrites(): Stub (builder mutations intertwined with plan)
- merge_and_rewrite(): ~1300 lines (needs further refactoring)
Target state (future work):
- scan_blocks(): ~100 lines (identification only)
- plan_rewrites(): ~400 lines (block generation, no builder mutation)
- apply_rewrites(): ~200 lines (builder mutation only)
- merge_and_rewrite(): ~100-200 lines (orchestrator)
Why partial completion:
- Main loop (1400 lines) has highly intertwined plan + apply logic
- Safe extraction requires careful separation (multi-session work)
- Current commit achieves scan extraction + clear architecture docs
- Follows 80/20 rule: Working scan stage + clear path forward
Next steps (future):
- Extract parameter binding logic → plan_rewrites()
- Extract block generation logic → plan_rewrites()
- Extract builder.add_block() calls → apply_rewrites()
- Move PHI/carrier input collection → plan_rewrites()
Build: cargo build --release ✅
Tests: Existing tests pass (no behavior changes)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 03:31:43 +09:00
7e259ad334
refactor(joinir): Phase 286C-2.1 Step 3 - Extract scan logic into scan_blocks()
...
- Move instruction identification logic from main loop to scan_blocks()
- Populate RewritePlan with tail_calls, return_conversions
- Read-only analysis phase complete (no mutations, just detection)
- merge_and_rewrite() now calls scan_blocks() to identify rewrites
Scan logic extracted:
- Tail call detection: Check Call instructions for intra-module calls
- Return detection: Identify Return terminators for exit jump conversion
- Populate TailCallRewrite with target_func_name, target_block, args
- Populate ReturnConversion with return_value, has_exit_edge_args
Build: cargo build --release ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 03:28:53 +09:00
f2458280c1
refactor(joinir): Phase 286C-2.1 Step 1 - Create 3-stage function stubs
...
- Create scan_blocks() stub (Stage 1: Read-only analysis)
- Create plan_rewrites() stub (Stage 2: Pure transformation)
- Create apply_rewrites() stub (Stage 3: Builder mutation)
- Add strategic markers for future extraction (STAGE 1/2/3)
- Document future orchestrator structure
Function Signatures:
- scan_blocks(&MirFunction, &JoinInlineBoundary, &RewriteContext) -> Result<RewritePlan, String>
- plan_rewrites(RewritePlan, &mut RewriteContext) -> Result<RewrittenBlocks, String>
- apply_rewrites(&mut MirBuilder, RewrittenBlocks) -> Result<(), String>
Benefits:
- Borrow checker safety: Sequential calling pattern (no overlapping borrows)
- Clear extraction targets: TODO markers identify logic to move
- Build stability: Stubs compile successfully, no functionality changes yet
- Foundation for incremental refactoring: Steps 2-5 can now proceed safely
Strategic Markers:
- Line 205: STAGE 1 marker (scan logic)
- Line 282: STAGE 2 marker (plan logic)
- Line 1355: STAGE 3 marker (apply logic)
- Line 1514: Future orchestrator structure
Status:
- Scaffolding: ✅ Complete (stubs in place)
- Extraction: ⏳ Next step (move logic from merge_and_rewrite to stubs)
Build: cargo build --release ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 03:19:06 +09:00
1a8a70cc99
refactor(joinir): Phase 286C-2.1 - 3-stage pipeline scaffolding (Scan/Plan/Apply)
...
- Create 3-stage pipeline architecture to solve borrow checker conflicts
- Stage 1 (ScanBox): Read-only scanning, identify rewrites (170 lines)
- Stage 2 (PlanBox): Pure transformation, generate new blocks (85 lines)
- Stage 3 (ApplyBox): Builder mutation only (75 lines)
New Files:
- scan_box.rs: Stage 1 - Read-only scan for RewritePlan
- plan_box.rs: Stage 2 - Transform RewritePlan → RewrittenBlocks
- apply_box.rs: Stage 3 - Apply RewrittenBlocks to MirBuilder
- C-2.1-pipeline-refactoring.md: Implementation guide
Data Structures:
- RewritePlan: Describes WHAT to rewrite (tail calls, returns, PHI, params)
- RewrittenBlocks: Contains HOW to rewrite (new blocks, replacements, inputs)
Benefits:
- Borrow checker safety: No overlapping mutable/immutable borrows
- Single responsibility: Each stage has one clear purpose
- Testability: Each stage can be unit tested independently
- Maintainability: Clear data flow, isolated changes
Status:
- Scaffolding: ✅ Complete (structure defined, stub implementations)
- Integration: ⏳ Next step (refactor merge_and_rewrite to use 3 stages)
Build: cargo build --release ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 03:05:44 +09:00
d81937e744
refactor(joinir): Phase 286C-2 - RewriteContext state consolidation
...
- Create RewriteContext struct to consolidate 11 scattered state variables
- Add 4 helper Boxes: InstructionFilterBox, ParameterBindingBox, ReturnConverterBox, TailCallDetectorBox
- Reduce instruction_rewriter.rs cognitive overhead via centralized state API
- All state mutations now go through consistent RewriteContext methods
Changes:
- New: rewrite_context.rs (94 lines) - State consolidation SSOT
- New: 4 helper Box modules (instruction_filter, parameter_binding, return_converter, tail_call_detector)
- Modified: instruction_rewriter.rs (1454 → 1421 lines)
- Modified: rewriter/mod.rs (export RewriteContext)
Benefits:
- State tracking simplified (11 variables → 1 context object)
- Clearer intent via API methods (add_exit_phi_input vs push)
- Foundation for future refactoring (Phase 286C-2.1: 3-stage pipeline)
- Zero functionality changes (pure refactoring)
Build: cargo build --release ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 02:58:36 +09:00
843d094598
refactor(joinir): Phase 286 P1-P3 - Boundary contract context enrichment
...
- P1: Add alloc_join_param()/alloc_join_local() API to JoinValueSpace
- Prevents future API misuse (thin wrappers with explicit "JoinIR" context)
- Updated docs with footnote-style number references
- P2: Enrich error context with host_fn for better diagnostics
- Added context: &str parameter to verify_boundary_contract_at_creation()
- Error format now shows: [merge_joinir_mir_blocks host=<fn> ...]
- P3: Add join-side info to error context (continuation count + boundary summary)
- Uses boundary.continuation_func_ids.len() for join=
- Adds [conts=X exits=Y conds=Z] suffix with fixed key names
- Enables faster debugging with log-searchable format
Error format: [merge_joinir_mir_blocks host=X join=Y [conts=A exits=B conds=C]]
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude <noreply@anthropic.com >
2025-12-25 02:15:40 +09:00
b0eeb14c54
refactor(phase284): P1 SSOT Consolidation - Block Remapper & Return Emitter
...
## Summary
Refactored Phase 284 P1 codebase to consolidate scattered logic into SSOT
(Single Source of Truth) modules, improving maintainability and enabling
Pattern4/5 code reuse.
## New Modules
### 1. Block Remapper SSOT
**File**: `src/mir/builder/control_flow/joinir/merge/block_remapper.rs` (152 lines)
- **Purpose**: Consolidate block ID remapping logic (Phase 284 P1 fix)
- **Function**: `remap_block_id(block_id, local_block_map, skipped_entry_redirects)`
- **Rule**: local_block_map priority > skipped_entry_redirects (prevents ID collision)
- **Tests**: 4 unit tests (priority cascade, collision handling, etc.)
### 2. Return Jump Emitter
**File**: `src/mir/join_ir/lowering/return_jump_emitter.rs` (354 lines)
- **Purpose**: Reusable return handling helper for Pattern4/5
- **Function**: `emit_return_conditional_jump(loop_step_func, return_info, k_return_id, ...)`
- **Scope**: P1 - unconditional return + conditional (loop_var == N) only
- **Tests**: 3 unit tests (unconditional, no return, conditional)
## Modified Files
**merge/instruction_rewriter.rs** (-15 lines):
- Replaced inline block remapping with `remap_block_id()` call
- Cleaner Branch remap logic
**merge/rewriter/terminator.rs** (-43 lines):
- Delegates remap_jump/remap_branch to block_remapper SSOT
- Simplified duplicate logic
**lowering/loop_with_continue_minimal.rs** (-108 lines):
- Replaced ~100 line return handling with `emit_return_conditional_jump()` call
- Extracted helper functions to return_jump_emitter.rs
- Line reduction: 57% decrease in function complexity
**merge/mod.rs, lowering/mod.rs**:
- Added new module exports (block_remapper, return_jump_emitter)
**phase-284/README.md**:
- Updated completion status (P1 Complete + Refactored)
- Added SSOT consolidation notes
- Documented module architecture
## Code Quality Improvements
| Metric | Before | After | Change |
|--------|--------|-------|--------|
| Duplicate block remap logic | 2 places | SSOT | -15 lines |
| Return handling code | inline (100L) | helper call | -99 lines |
| Testability | Limited | Unit tests (7) | +7 tests |
| Module cohesion | Low (scattered) | High (consolidated) | Better |
## Testing
✅ Build: Success (cargo build --release)
✅ Smoke tests: All pass (46 PASS, 1 pre-existing FAIL)
✅ Regression: Zero
✅ Unit tests: 7 new tests added
## Future Benefits
1. **Pattern5 Reuse**: Direct use of `emit_return_conditional_jump()` helper
2. **Phase 285 (P2)**: Nested if/loop returns via same infrastructure
3. **Maintainability**: SSOT reduces debugging surface area
4. **Clarity**: Each module has single responsibility
## Architectural Notes
**Block Remapper SSOT Rule**:
```
remap_block_id(id, local_block_map, skipped_entry_redirects):
1. Check local_block_map (function-local priority)
2. Fall back to skipped_entry_redirects (global redirects)
3. Return original if not found
```
Prevents function-local block ID collisions with global remap entries.
**Return Emitter Pattern**:
```
emit_return_conditional_jump(func, return_info, k_return_id, alloc_value):
- Pattern1-5: All use same infrastructure
- P1 scope: top-level return only (nested if/loop → P2)
- Returns: JoinInst::Jump(cont=k_return, cond=Some(return_cond))
```
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2025-12-23 14:37:01 +09:00
661bbe1ab7
feat(phase284): P1 Complete - Return in Loop with Block Remap Fix
...
## Summary
Completed Phase 284 P1: Enable return statements in Pattern4/5 loops via
JoinInst::Ret infrastructure (100% pre-existing, no new infrastructure needed).
**Critical Bug Fix**: Block ID remap priority
- Fixed: local_block_map must take precedence over skipped_entry_redirects
- Root cause: Function-local block IDs can collide with global remap entries
(example: loop_step:bb4 vs k_exit:bb4 after merge allocation)
- Impact: Conditional Jump else branches were incorrectly redirected to exit
- Solution: Check local_block_map FIRST, then skipped_entry_redirects
## Implementation
### New Files
- `src/mir/join_ir/lowering/return_collector.rs` - Return detection SSOT (top-level only, P1 scope)
- `apps/tests/phase284_p1_return_in_loop_min.hako` - Test fixture (exit code 7)
- Smoke test scripts (VM/LLVM)
### Modified Files
- `loop_with_continue_minimal.rs`: Return condition check + Jump generation
- `pattern4_with_continue.rs`: K_RETURN registration in continuation_funcs
- `canonical_names.rs`: K_RETURN constant
- `instruction_rewriter.rs`: Fixed Branch remap priority (P1 fix)
- `terminator.rs`: Fixed Jump/Branch remap priority (P1 fix)
- `conversion_pipeline.rs`: Return normalization support
## Testing
✅ VM: exit=7 PASS
✅ LLVM: exit=7 PASS
✅ Baseline: 46 PASS, 1 FAIL (pre-existing emit issue)
✅ Zero regression
## Design Notes
- JoinInst::Ret infrastructure was 100% complete before P1
- Bridge automatically converts JoinInst::Ret → MIR Return terminator
- Pattern4/5 now properly merge k_return as non-skippable continuation
- Correct semantics: true condition → return, false → continue loop
## Next Phase (P2+)
- Refactor: Block remap SSOT (block_remapper.rs)
- Refactor: Return jump emitter extraction
- Scope: Nested if/loop returns, multiple returns
- Design: Standardize early exit pattern (return/break/continue as Jump with cond)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2025-12-23 14:21:27 +09:00
bfbc9b26bf
fix(joinir): Phase 283 P0 - Pattern3 Undefined ValueId Bug Fix
...
- Fix: extract_if_condition() moved after local_cond_env construction
(loop_with_if_phi_if_sum.rs:175)
- Root cause: condition extraction before i_param/sum_param creation
- Result: i % 2 referenced caller's ConditionEnv with unmapped ValueId
- Fail-Fast: Add condition_bindings validation in merge (mod.rs)
- Fixture: Update loop_if_phi.hako for C2 compatibility (sum.toString())
- Verified: VM execution outputs sum=9 ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-23 08:14:27 +09:00
1b7fd7a0ff
refactor(plan): Phase 273 P3+ - Legacy code removal
...
Phase 273 P3+ 完成: レガシーコード削除 + 未使用 import 整理
Removed Legacy Items:
1. emit_scan_with_init_edgecfg() - Pattern6 固有の emission 関数
- File deleted: src/mir/builder/emission/loop_scan_with_init.rs (~144 lines)
- Replaced by: generalized Frag API (Phase 273 P2)
2. CoreCarrierInfo struct - Legacy carrier representation
- Removed from: src/mir/builder/control_flow/plan/mod.rs (~15 lines)
- Replaced by: CorePhiInfo (generalized PHI representation)
3. verify_carrier() function - CoreCarrierInfo validator
- Removed from: src/mir/builder/control_flow/plan/verifier.rs (~15 lines)
- Replaced by: generalized PHI verification (V7-V9)
Code Cleanup:
- cargo fix applied: unused imports removed (~30 files)
- Verifier invariants updated: V1→V2-V9 (carrier→PHI model)
- Module declaration cleanup in emission/mod.rs
Impact:
- Total lines removed: ~174 lines (net reduction)
- Pattern-agnostic architecture strengthened
- All legacy Pattern6 references eliminated
Tests:
- ✅ VM tests PASS (phase254/256/258)
- ✅ LLVM tests PASS (phase256/258)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-23 00:11:20 +09:00
c0334f8b7e
refactor(mir): phase260 p0.2 hide legacy edge-args reads behind BasicBlock API
...
- Add block.return_env() getter for Return env metadata
- Update instruction_rewriter.rs to use block.return_env()
- Update exit_collection.rs to use block.return_env()
- Prepare for Phase 260 P2 (jump_args deletion)
This consolidates all legacy edge-args reads through BasicBlock API,
enabling clean deletion of jump_args field in P2.
2025-12-21 09:01:35 +09:00
aa3fdf3c18
refactor(joinir): Phase 260 P0.1 Step 6b - fix tests and add TODO
...
- Fix helpers.rs tests to use new MirFunction::new(FunctionSignature, BasicBlockId) API
- Update continuation_contract.rs import path to use rewriter::helpers
- Add TODO comment for future exit_collection integration
- All 6 rewriter tests pass
The exit_collection module is complete and tested but full integration
with instruction_rewriter.rs deferred (80/20 rule - logging context
and flow control require careful refactoring).
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-21 06:33:11 +09:00
cbed040a74
refactor(joinir): Phase 260 P0.1 Step 6 - extract exit_collection.rs
...
Extract exit value collection logic from instruction_rewriter.rs into
dedicated rewriter/exit_collection.rs module (~305 lines).
New functions:
- collect_exit_values_from_legacy_edge_args(): Phase 246-EX collection
- add_carrier_values_to_inputs(): carrier values → carrier_inputs map
- handle_fallback_exit_collection(): Phase 246-EX/131 P1.5 fallback
- collect_k_exit_values(): k_exit tail call lowering (Phase 131)
Key changes:
- ExitCollectionResult struct for structured return values
- Uses Vec<(String, (BasicBlockId, ValueId))> for carrier_values
(matching ExitArgsCollectorBox output format)
- Logging removed from helpers (caller handles via local log! macro)
- 3 unit tests for add_carrier_values_to_inputs
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-21 06:28:09 +09:00
15b3352e21
refactor(joinir): Phase 260 P0.1 Step 5 - Extract terminator.rs (Jump/Branch remapping)
...
Extract Jump/Branch terminator remapping to dedicated module.
3 clean functions: remap_jump, remap_branch, apply_remapped_terminator.
Changes:
- NEW: rewriter/terminator.rs - 3 functions (145 lines)
- remap_jump(): Jump block ID + edge_args remapping
- remap_branch(): Branch block ID + condition + edge_args remapping
- apply_remapped_terminator(): Apply remapped terminator with edge_args handling
- CHANGED: instruction_rewriter.rs - use terminator module (deleted local logic)
- Deleted remap_edge_args closure (lines 902-911)
- Replaced Jump remapping (lines 1056-1067) → remap_jump()
- Replaced Branch remapping (lines 1069-1094) → remap_branch()
- Replaced terminator setting (lines 1098-1127) → apply_remapped_terminator()
- CHANGED: rewriter/mod.rs - declare terminator module
Benefits:
- Phase 259 P0 FIX: skipped_entry_redirects handling centralized
- Testable in isolation (pure block ID/ValueId mapping)
- Reduces instruction_rewriter.rs by ~40 lines
Reduction:
- instruction_rewriter.rs: 1396 → ~1356 lines (-40)
Next: Extract exit_collection.rs (Return→Jump + exit value collection)
2025-12-21 06:17:14 +09:00
d9ff3f60ff
refactor(joinir): Phase 260 P0.1 Step 4 - Extract type_propagation.rs (70 lines)
...
Extract propagate_value_type_for_inst to dedicated type_propagation module.
Handles type info flow from JoinIR→MIR merge (SSOT + fallback inference).
Changes:
- NEW: rewriter/type_propagation.rs - propagate_value_type_for_inst
- CHANGED: instruction_rewriter.rs - import from type_propagation (deleted local fn)
- CHANGED: rewriter/mod.rs - declare type_propagation module
Design:
- SSOT: Prefer type info from JoinIR source function metadata
- Fallback: Infer from instruction structure (Const/Copy/BinOp/Compare)
- LLVM: Ensures '+' stays numeric (not concat_hh_mixed)
Reduction:
- instruction_rewriter.rs: 1466 → 1396 lines (-70)
Next: Start terminator.rs extraction (Branch/Jump/Return remapping)
2025-12-21 06:11:53 +09:00
e555b4ad31
refactor(joinir): Phase 260 P0.1 Step 3 - Extract helpers.rs (is_skippable_continuation)
...
Extract is_skippable_continuation to dedicated helpers module.
Small pure function (12 lines) with comprehensive tests (3 test cases).
Changes:
- NEW: rewriter/helpers.rs - is_skippable_continuation + 3 tests
- CHANGED: instruction_rewriter.rs - import from helpers (deleted local definition)
- CHANGED: rewriter/mod.rs - re-export from helpers
Benefits:
- Testable in isolation (pure function)
- Clear module boundary (structural checks)
- instruction_rewriter.rs: 1477 → 1466 lines (-11)
Tests:
- test_is_skippable_continuation_pure_stub ✅
- test_is_skippable_continuation_has_instructions ✅
- test_is_skippable_continuation_multiple_blocks ✅
Next: Extract type_propagation.rs (propagate_value_type_for_inst - 70 lines)
2025-12-21 06:09:45 +09:00
b87760e247
refactor(joinir): Phase 260 P0.1 Step 2 - Extract logging.rs (DEBUG-177 style)
...
Extract logging utilities into dedicated module (safest first split).
Provides log_if() function + rewriter_log!() macro as alternatives to local log! macro.
Changes:
- NEW: rewriter/logging.rs - log_if() + rewriter_log!() macro
- CHANGED: rewriter/mod.rs - declare logging module
Design:
- log_if(trace, enabled, msg): Function form for explicit control
- rewriter_log!(): Macro form for format!() convenience
- Both wrap JoinLoopTrace::stderr_if() (existing infrastructure)
Status:
- instruction_rewriter.rs still uses local log! macro (unchanged)
- Future: Gradually migrate to logging::log_if() or rewriter_log!()
- cargo check PASS ✅
Next: Extract is_skippable_continuation to helpers.rs (smallest function)
2025-12-21 06:06:29 +09:00
4bc469239d
refactor(joinir): Phase 260 P0.1 Step 1 - Create rewriter/ skeleton (box-first modularization)
...
Create rewriter/ directory with re-export skeleton for instruction_rewriter.rs.
This enables gradual refactoring without breaking existing code.
Changes:
- NEW: src/.../joinir/merge/rewriter/mod.rs (re-exports instruction_rewriter)
- CHANGED: merge/mod.rs - route calls through rewriter module
- STRATEGY: Keep instruction_rewriter.rs intact, split later into:
- terminator.rs (Branch/Jump/Return remapping)
- exit_line.rs (ExitLine/exit-phi wiring)
- carriers.rs (loop_invariants, exit_bindings)
- logging.rs (DEBUG-177 style verbose logs)
Acceptance:
- cargo check PASS ✅
- No behavior change (挙動変更なし)
- Backward compatible (instruction_rewriter.rs still exists)
Next: Extract terminator.rs (smallest, safest first split)
2025-12-21 06:03:43 +09:00
4dfe3349bf
refactor(mir): phase260 p0 edge-args plumbing (strangler) + ssot api + docs
2025-12-21 04:34:22 +09:00
4496b6243d
feat(joinir): Phase 259 P0 complete - Pattern8 final fixes + docs (pre-block-params migration)
...
Phase 259 P0: Pattern8 (BoolPredicateScan) 完全完了
is_integer/1 を Pattern8 で受理し、VM/LLVM EXE 両方で動作確認完了。
次の大工事(block-parameterized CFG への移行)前のマイルストーンとして記録。
## Key Fixes Applied
1. **skipped_entry_redirects** (instruction_rewriter.rs)
- k_exit のスキップ時、entry block 参照を exit_block_id へリダイレクト
- BasicBlockId not found エラーを根治
2. **loop_var_name** (pattern8_scan_bool_predicate.rs)
- merge_entry_block 選択に使用(`Some(parts.loop_var.clone())`)
- 未設定時の誤った entry block 選択を修正
3. **loop_invariants** (pattern8_scan_bool_predicate.rs)
- PHI-free 不変量パラメータ(`[(me, me_host), (s, s_host)]`)
- loop_var_name 設定時、BoundaryInjector が join_inputs Copy を全スキップするため必要
- Pattern6 と同じ設計(header PHI で不変量を保持)
4. **expr_result** (pattern8_scan_bool_predicate.rs)
- k_exit からの返り値を明示設定(`Some(join_exit_value)`)
- Pattern7 style(推測ではなく明示)
5. **Smoke test scripts**
- set +e パターンで exit code 7 をキャプチャ
- LLVM EXE スクリプトにコメント追加(tools/build_llvm.sh 経由の明記)
## Contract Documentation
- join-explicit-cfg-construction.md に Pattern8 契約の具体例を追加
- "pattern増でも推測増にしない" の実例として記録
- loop_var_name / loop_invariants / expr_result / jump_args_layout の契約を明示
- 20-Decisions.md に正規化(Semantic/Plumbing)の分離方針を追記
- DOCS_LAYOUT.md に重要ドキュメントへの参照を追加
## Test Results
- ✅ VM smoke test: `[PASS] phase259_p0_is_integer_vm` (exit 7)
- ✅ LLVM EXE: tools/build_llvm.sh 経由で exit 7 確認
- ✅ --verify: PASS
## Next FAIL (Phase 260+)
- Function: `Main.main/0` in `apps/examples/json_lint/main.hako`
- Error: `[cf_loop/pattern2] Failed to extract break condition from loop body`
- Pattern: Nested loop(外側 loop + 内側 loop with break)
🚀 次の大工事: block-parameterized CFG への移行を開始します。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-21 03:21:22 +09:00
a767f0f3a9
feat(joinir): Phase 259 P0 - Pattern8 BoolPredicateScan + Copy binding fix
...
Pattern8 (Boolean Predicate Scan) implementation for is_integer/1:
- New pattern detection for `loop + if not predicate() { return false }`
- JoinIR lowerer with main/loop_step/k_exit structure
- Me receiver passed as param (by-name 禁止)
Key fixes:
1. expr_result = Some(join_exit_value) (Pattern7 style)
2. Tail-call: dst: None (no extra Ret instruction)
3. instruction_rewriter: Add `&& is_loop_header_with_phi` check
- Pattern8 has no carriers → no PHIs → MUST generate Copy bindings
- Without this, ValueId(103/104/105) were undefined
Status: Copy instructions now generated correctly, but exit block
creation issue remains (next step: Step A-C in指示書).
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-21 02:40:07 +09:00
73ddc5f58d
feat(joinir): Phase 257 P1.1/P1.2/P1.3 - Pattern6 SSOT + LoopHeaderPhi CFG fix
...
P1.1: Pattern6 false positive fix (SSOT approach)
- can_lower() now calls extract_scan_with_init_parts() for SSOT
- index_of_string/2 no longer triggers false positive
- Graceful fall-through with Ok(None)
P1.2: LoopHeaderPhi CFG-based correction
- Step 0: Manual successor update from terminators
- CFG-based entry predecessor computation (header_preds - latch)
- Multi-entry-pred support (bb0 host + bb10 JoinIR main)
- Explicit host_entry_block addition (emit_jump runs after finalize)
P1.3: Smoke script validation
- phase254_p0_index_of_vm.sh: --verify + VM error detection
- phase257 smokes updated
Acceptance criteria (all PASS):
✅ phase254_p0_index_of_min.hako verify
✅ phase257_p0_last_index_of_min.hako verify
✅ ./tools/smokes/v2/run.sh --profile quick (no Pattern6 false positive)
Technical discovery:
- Host entry block (bb0) Jump set in Phase 6 (after finalize)
- instruction_rewriter bypasses set_terminator(), skips successor update
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-20 23:30:27 +09:00
edc7355937
refactor(joinir): unify boundary join_inputs SSOT (pattern4/6/7)
...
Apply Phase 256.8 SSOT fix to Pattern4/6/7:
- Use join_module.entry.params.clone() instead of hardcoded ValueIds
- Add fail-fast validation for params count mismatch
- Remove ValueId(0), ValueId(PARAM_MIN + k) patterns
- Clean up unused PARAM_MIN imports
This prevents entry_param_mismatch errors structurally and maintains
consistency with Pattern2/3.
Changes:
- pattern4_with_continue.rs: Lines 442-476 (SSOT extraction + validation)
- pattern6_scan_with_init.rs: Lines 447-471 (SSOT extraction + validation)
- pattern7_split_scan.rs: Lines 495-526 (SSOT extraction + validation)
All patterns now use the same SSOT principle:
1. Extract entry function (priority: join_module.entry → fallback "main")
2. Use params as SSOT: join_inputs = entry_func.params.clone()
3. Build host_inputs in expected order (pattern-specific)
4. Fail-fast validation: join_inputs.len() == host_inputs.len()
Verification:
- cargo build --release: ✅ PASS (no PARAM_MIN warnings)
- Quick profile: ✅ First FAIL still json_lint_vm (baseline maintained)
- Pattern6 smoke: ✅ PASS (index_of test)
- Pattern7 smoke: Pre-existing phi pred mismatch (not introduced by SSOT)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-20 20:05:11 +09:00
4439d64da3
refactor(joinir): make jump_args layout explicit (Phase 256)
2025-12-20 13:04:24 +09:00
1028bd419c
fix(joinir): stabilize Phase 256 merge (jump_args, DCE, func names)
2025-12-20 11:01:48 +09:00
2c4268b691
wip(joinir): Phase 256 P1.10 - classify_tail_call continuation support
...
## 修正内容
- classify_tail_call に is_target_continuation パラメータ追加
- k_exit 呼び出しを ExitJump として分類(BackEdge に誤分類されるのを防止)
- entry_func_name の決定ロジックを修正(loop_step を正しく識別)
- Continuation param bindings の Copy 生成ロジック追加
## 残存問題
bb8/bb9 の instructions が 0 になる問題
- add_block 時は 4 instructions ある
- printer 時は instructions=0, spans=4
- 原因調査中
🔍 WIP - ChatGPT レビュー用
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-20 10:25:13 +09:00
077657b7a1
feat(joinir): Phase 256 P1.5-P1.7 contracts and naming SSOT
2025-12-20 06:38:21 +09:00
575a5d750f
refactor(joinir): Phase 255 P2 - loop_invariants + var() unification + Phase 256 prep
...
## Task A: Loop Invariants Architecture (Option A - Boundary Extension)
Introduced explicit loop_invariants concept for variables that are:
- Used in loop body but never modified (e.g., substring needle in index_of)
- Need header PHI (all iterations use same value)
- Do NOT need exit PHI (not a LoopState)
Implementation:
- Added `loop_invariants: Vec<(String, ValueId)>` field to JoinInlineBoundary
- Added `with_loop_invariants()` method to JoinInlineBoundaryBuilder
- Modified Pattern 6 to use loop_invariants instead of ConditionOnly misuse
* s (haystack) and ch (needle) now properly classified
* exit_bindings simplified to only LoopState carriers
- Extended LoopHeaderPhiBuilder to generate invariant PHIs
* Entry PHI: from host
* Latch PHI: self-reference (same value every iteration)
- Updated instruction_rewriter to handle invariant latch incoming
Files Modified:
- src/mir/join_ir/lowering/inline_boundary.rs (structure + builder)
- src/mir/join_ir/lowering/inline_boundary_builder.rs (builder method)
- src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs
- src/mir/builder/control_flow/joinir/merge/loop_header_phi_builder.rs
- src/mir/builder/control_flow/joinir/merge/mod.rs
- src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs
## Task B: Code Quality - var() Helper Unification
Created common module to eliminate var() duplication:
- New module: src/mir/builder/control_flow/joinir/patterns/common/
- Centralized var() helper in ast_helpers.rs
- Updated Pattern 6 and Pattern 2 to use common var()
- Test code (5 occurrences) deferred to Phase 256+ per 80/20 rule
Result: Eliminated 2 duplicate var() functions, 5 test occurrences remain
Files Created:
- src/mir/builder/control_flow/joinir/patterns/common/ast_helpers.rs
- src/mir/builder/control_flow/joinir/patterns/common/mod.rs
Files Modified:
- src/mir/builder/control_flow/joinir/patterns/mod.rs
- src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs
- src/mir/builder/control_flow/joinir/patterns/policies/balanced_depth_scan_policy.rs
## Task C: Documentation - PostLoopEarlyReturnPlan Usage Examples
Enhanced post_loop_early_return_plan.rs with:
- Architecture explanation (exit PHI usage prevents DCE)
- Pattern 2 example (Less: balanced_depth_scan)
- Pattern 6 example (NotEqual: index_of)
- Builder defer decision: when 4+ patterns emerge, add builder
Files Modified:
- src/mir/builder/control_flow/joinir/patterns/policies/post_loop_early_return_plan.rs
## Task D: Phase 256 Preparation
Analyzed next failure from smoke tests:
- `StringUtils.split/2` with variable-step loop
- Not constant step (i += len or similar)
- Three implementation options identified
Created Phase 256 README with:
- Minimal reproduction code
- Root cause analysis
- Implementation options with trade-offs
- Clear next steps
Files Created:
- docs/development/current/main/phases/phase-256/README.md
## Verification Results
✅ All tests passing:
- pattern254_p0_index_of_vm.sh: PASS
- No regression in Pattern 1-5
- Smoke test progresses past json_lint_vm to next failure
✅ Architecture achievements:
- Semantic clarity: loop_invariants vs exit_bindings properly separated
- ConditionOnly misuse eliminated
- PHI generation correct for all carrier types
- Code quality: var() duplication reduced
- Next phase clearly defined
## Summary
Phase 255 P2 achieves root-cause fix for multi-param loop support:
- Boundary concept expanded (loop_invariants field)
- Pattern 6 architecture corrected (no ConditionOnly misuse)
- Code quality improved (var() centralized)
- Next pattern (variable-step) is now the challenge
✨ Box-first principles maintained: clean separation, explicit roles, minimal coupling
🧠 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2025-12-19 23:48:49 +09:00
6a3b6deb20
feat(anf): Phase 145 P0/P1/P2 - ANF (A-Normal Form) transformation
...
Implement ANF transformation for impure expressions to fix evaluation order:
Phase 145 P0 (Skeleton):
- Add anf/ module with contract/plan/execute 3-layer separation
- AnfDiagnosticTag, AnfOutOfScopeReason, AnfPlan enums
- Stub execute_box (always returns Ok(None))
- 11 unit tests pass
Phase 145 P1 (Minimal success):
- String.length() whitelist implementation
- BinaryOp + MethodCall pattern: x + s.length() → t = s.length(); result = x + t
- Exit code 12 verification (VM + LLVM EXE)
- 17 unit tests pass
Phase 145 P2 (Generalization):
- Recursive ANF for compound expressions
- Left-to-right, depth-first evaluation order
- Patterns: x + s.length() + z, s1.length() + s2.length()
- ANF strict mode (HAKO_ANF_STRICT=1)
- Diagnostic tags (joinir/anf/*)
- 21 unit tests pass, 0 regression
Also includes Phase 143 P2 (else symmetry) completion.
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-19 16:19:49 +09:00
845ae70cb7
chore: Remove unused imports in normalized_shadow modules
...
Cleaned up unused imports after Phase 143 execution fix (5e662eaaf ).
**Priority files (Phase 143)**:
- if_as_last_join_k.rs: removed ValueId, BTreeMap
- loop_true_break_once.rs: added #[cfg(test)] for test-only imports
- post_if_post_k.rs: removed ValueId, BTreeMap
- normalized_helpers.rs: added #[cfg(test)] for Span
**Additional cleanup**:
- contract_checks.rs: removed BasicBlockId
- joinir/mod.rs: removed Info struct re-exports (functions kept)
- patterns/mod.rs: removed Info struct re-exports (functions kept)
- ast_feature_extractor.rs: removed EscapeSkipPatternInfo
- plan_box.rs: added #[cfg(test)] for PlanKind
**Verification**:
- 0 unused import warnings (was 20+)
- All 69 normalized_shadow tests pass
- Clean build with --release
Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-19 08:36:45 +09:00
5e662eaaf6
fix(normalization): Phase 143 execution fix - Param region SSOT
...
Problem: normalized_helpers allocated env params as ValueId(1,2...)
in PHI Reserved region (0-99) instead of Param region (100-999)
per JoinValueSpace contract.
Root cause: All 4 normalized shadow modules started from
next_value_id=1, violating the Param region contract.
Solution:
- Add NormalizedHelperBox::alloc_env_params_param_region()
that allocates params starting from PARAM_MIN (100)
- Update 4 normalized shadow files to use new API:
- loop_true_if_break_continue.rs
- loop_true_break_once.rs
- if_as_last_join_k.rs
- post_if_post_k.rs
- Fix instruction_rewriter.rs type mismatch
(func.signature.params → func.params)
Verification:
- Unit tests: 69/69 PASS
- VM smoke: exit code 7 ✅
- LLVM EXE smoke: exit code 7 ✅ (timeout resolved!)
ValueId Space Contract (Phase 201):
| Region | Range | Purpose |
|--------------|----------|------------------------------|
| PHI Reserved | 0-99 | Loop header PHI dst |
| Param | 100-999 | env params (flag, counter) |
| Local | 1000+ | Const, BinOp, condition |
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-19 08:23:20 +09:00