Commit Graph

2328 Commits

Author SHA1 Message Date
a15821cb17 Revert "fix(pattern2): return Ok(None) for unpromoted LoopBodyLocal instead of Err"
This reverts commit e0278405c0.
2025-12-21 10:21:05 +09:00
e0278405c0 fix(pattern2): return Ok(None) for unpromoted LoopBodyLocal instead of Err
- Pattern2 で処理できない LoopBodyLocal は Err ではなく処理続行
- Pattern1 等に fallback させる(detection→extract→lower SSOT 維持)
- out-of-scope 変数(reassigned body-local)はreject不要

Fixes: core_direct_array_oob_set_rc_vm smoke test FAIL
Fixes: phase263_p0_pattern2_seg_min (新規テスト)
2025-12-21 09:56:56 +09:00
9d71a3b1a4 test(phase263): add minimal repro for Pattern2 LoopBodyLocal seg issue
- apps/tests/phase263_p0_pattern2_seg_min.hako: loop body で seg 代入
- tools/.../phase263_p0_pattern2_seg_vm.sh: VM smoke test
- 現状: Pattern2 rejection で FAIL(固定)
- 期待: 修正後に Pattern1 fallback で PASS
2025-12-21 09:54:39 +09:00
fc6eed1b04 docs: Phase 260 P2 完了記録 + EdgeCFG SSOT 確立
Update phase-260/README.md:
- Status: P2 完了 (EdgeCFG SSOT確立)
- Add P2 completion record with test results
- Add EdgeCFG SSOT definition (Jump/Branch: terminator SSOT, Return: metadata exception)
- Document unified API (read/write separation)
- Note Option B' trade-off (Return metadata exception)

Update 10-Now.md:
- Add Phase 260 P2 completion entry (2025-12-21)
- Test results: 1368 lib tests, 45/46 smoke, phase258 tail call
- Verification: 0 jump_args references (comments excluded)
- 9 files modified

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 09:39:39 +09:00
901ce767ce refactor(verify): Phase 260 P2 - Remove dual-source edge-args validation
- Delete legacy jump_args consistency checks (62 lines from cfg.rs)
- Metadata no longer exists, so dual-source validation is obsolete
- Rely on existing SSA validation for PHI correctness

Simplifies verification now that jump_args metadata is deleted
and terminator operands are the sole source of truth.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 09:39:26 +09:00
45a7e24f7d feat(mir): Phase 260 P2 - Delete BasicBlock.jump_args, unify to terminator SSOT
- Delete legacy jump_args/jump_args_layout fields from BasicBlock
- Add return_env/return_env_layout for Return-specific metadata
- Rename set_return_edge_args() → set_return_env() (clearer semantics)
- Remove 8 legacy helper methods (has/get/set/clear legacy_jump_args)
- Simplify set_jump/branch_with_edge_args (remove legacy sync, keep API)
- Update edge_args_from_terminator() to terminator-only (no fallback)
- Update 10+ JoinIR handler/test sites to use new API

This completes Phase 260 P0 → P2 migration: edge-args are now
exclusively in terminator operands (Jump/Branch) or Return-specific
metadata (renamed from legacy terminology).

BREAKING: BasicBlock.jump_args field removed. Use terminator edge-args
or block.return_env() for Return blocks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 09:39: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
2f2596db37 refactor(mir): phase261 p0.1 unify return edge-args writes 2025-12-21 08:40:34 +09:00
7c9f453fc6 refactor(mir): phase261 p0 enforce edge-args writer ssot (verify + sync) 2025-12-21 08:32:04 +09:00
89c5fc2654 docs: Phase 260 P0.3 完了記録 + 既知FAIL SSOT更新
**10-Now.md 更新**:
- Phase 260 P0.2/P0.3 完了記録追加(15モジュール、約3941行、53単体テスト)
- Current First FAIL を "P0.3完了後" に更新
- 既知FAILに "Phase 260 scope外" を明記
- 期待/実際の詳細追加
- 次アクション: 機能側Phase(Pattern2 LoopBodyLocal promotion)へ

**phase-260/README.md 更新**:
- Status: P0.3 完了 
- P0.2/P0.3 進捗セクション追加(commit履歴、成果)
- モジュール分割の責務一覧(Utilities 7 + Handlers 8)
- SSOT維持確認項目(jump_args直参照ゼロ、out_edges()/edge_args_to() SSOT維持、PHI preservation、Phase metadata保持)

Phase 260 完全達成: CFG基盤整備完了、今後は機能側Phaseへ

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 08:18:29 +09:00
2c01a7335a refactor(joinir): Phase 260 P0.3 Phase 2 - extract 5 complex handlers
Extracts all remaining complex handlers from joinir_block_converter.rs:

**handlers/call.rs** (308 lines):
- handle_call() - Call + tail call processing
- Phase 131 P2: Stable function name ValueId (module-global SSOT)
- Phase 131 P2: Legacy jump-args metadata for tail calls
- Phase 256 P1.8: Function name resolution
- 5 comprehensive unit tests

**handlers/jump.rs** (566 lines):
- handle_jump() - Jump to continuation (conditional/unconditional)
- get_continuation_name() helper (Phase 256 P1.9)
- Stable ValueId allocation (JUMP_FUNC_NAME_ID_BASE = 91000)
- Phase 246-EX: Legacy jump-args metadata
- 5 comprehensive unit tests

**handlers/conditional_method_call.rs** (413 lines):
- handle_conditional_method_call() - If/Phi expansion (single variable)
- 3-block pattern: cond → then (BoxCall) / else (Copy) → merge (PHI)
- Uses block_allocator + terminator_builder
- 4 comprehensive unit tests

**handlers/if_merge.rs** (454 lines):
- handle_if_merge() - If/Phi with multiple variables
- Handles parallel merges (e.g., sum + count in fold operations)
- Uses merge_variable_handler for copy emission
- 4 comprehensive unit tests

**handlers/nested_if_merge.rs** (557 lines):
- handle_nested_if_merge() - Multi-level nested branches (MOST COMPLEX)
- Dynamic N+3 block allocation (N levels + then + final_else + merge)
- Cascading AND logic for N conditions
- 4 comprehensive unit tests

All handlers:
- Use extracted utilities (block_allocator, call_generator, merge_variable_handler, terminator_builder, block_finalizer)
- Accept finalize_fn as parameter (enables testing)
- Fully tested (22 unit tests total, all passing)
- Ready for integration into converter

Pattern reduction: ~581 lines of complex control flow → 5 focused modules

Phase 2 complete - all handlers extracted and tested.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 08:08:25 +09:00
e7f9adcfed refactor(joinir): Phase 260 P0.3 Phase 1 - extract terminator_builder + block_finalizer
Extracts shared utilities from joinir_block_converter.rs to prepare for
handler extraction (Phase 2):

**terminator_builder.rs** (207 lines):
- create_branch_terminator() - Branch with empty edge_args
- emit_branch_and_finalize() - Branch + block finalization
- create_jump_terminator() - Jump with empty edge_args
- create_return_terminator() - Return terminator
- Eliminates 4x Branch terminator duplication

**block_finalizer.rs** (246 lines):
- finalize_block() - Add instructions + terminator (PHI-preserving)
- finalize_remaining_instructions() - Flush pending instructions
- Phase 189 FIX: Critical PHI preservation logic
- PHI instructions remain at block start for SSA correctness

Pattern reduction: ~90 lines duplicated 4x → 2 utility modules

All utilities fully tested with comprehensive unit tests.
Phase 1 complete - utilities ready for Phase 2 handler extraction.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 07:40:05 +09:00
666de9d3ec refactor(joinir): Phase 260 P0.2 - extract select handler
Adds select handler to the handlers/ module:

**handlers/select.rs** (118 lines):
- handle_select() - Select instruction (Phase 256 P1.5)
- Direct instruction emission (no branch/PHI expansion)
- Debug logging support
- Comprehensive unit tests

Pattern: Simple instruction wrapper, no control flow complexity

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 07:27:18 +09:00
875bfee1ba refactor(joinir): Phase 260 P0.2 - extract call_generator + 4 simple handlers
Extracts repeated patterns from joinir_block_converter.rs:

**call_generator.rs** (195 lines):
- emit_call_pair() - Const + Call instruction pair generation
- emit_call_pair_with_spans() - With span tracking
- Eliminates 3x duplication of call generation pattern

**handlers/** module (4 simple handlers, 389 lines total):
- ret.rs - Return instruction handling
- method_call.rs - MethodCall → BoxCall conversion
- field_access.rs - FieldAccess → BoxCall (getter pattern)
- new_box.rs - NewBox instruction handling

All handlers fully tested with comprehensive unit tests.

Pattern reduction: ~60 lines duplicated 3x → single utility modules

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 07:22:14 +09:00
84cd653aef refactor(joinir): Phase 260 P0.2 - extract merge_variable_handler.rs
Extracts merge copy emission pattern from joinir_block_converter.rs to
eliminate 4x code duplication:

- MergeBranch enum (Then/Else) for branch selection
- emit_merge_copies() for MergePair-based copy emission
- emit_copy_instructions() for direct ValueId pair emission
- Comprehensive unit tests for all patterns

Pattern reduction: ~20 lines duplicated 4x → single 60-line module

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 07:07:21 +09:00
c2e8099ff6 refactor(joinir): Phase 260 P0.2 - extract block_allocator.rs
Extract block ID allocation pattern from joinir_block_converter.rs into
dedicated block_allocator.rs module (~130 lines).

New BlockAllocator struct provides:
- allocate_one(): Single block ID
- allocate_two(): Pair (exit + continue pattern)
- allocate_three(): Triple (then + else + merge pattern)
- allocate_n(): N block IDs for nested structures
- 5 unit tests

This eliminates 4x repeated allocation pattern across:
- handle_conditional_method_call() lines 259-265
- handle_jump() lines 484-487
- handle_if_merge() lines 630-635
- handle_nested_if_merge() lines 731-744

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 06:57:16 +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
8fa7e64f24 docs(phase260): checkpoint P0/P0.1 + update quick first fail 2025-12-21 05:54:00 +09:00
1fe5be347d refactor(mir): phase260 p0.1 strangler hardening + smoke fixtures 2025-12-21 05:47:37 +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
e4f57ea83d docs: update Phase 257-259 SSOT (first FAIL is is_integer) 2025-12-21 00:29:55 +09:00
23531bf643 feat(joinir): Phase 258 P0 dynamic needle window scan 2025-12-21 00:29:50 +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
9ba89bada2 feat(pattern6): support reverse scan for last_index_of
Extend Pattern6 (ScanWithInit) to handle both forward and reverse scans:
- Forward: i=0, loop(i < len), i=i+1 (existing)
- Reverse: i=len-1, loop(i >= 0), i=i-1 (NEW)

Implementation:
- Added ScanDirection enum (Forward/Reverse)
- Updated extract_scan_with_init_parts() to detect both patterns
- Created lower_scan_with_init_reverse() lowerer
- Pattern6 now selects appropriate lowerer based on scan direction

Files modified:
- src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs
- src/mir/join_ir/lowering/scan_with_init_reverse.rs (new)
- src/mir/join_ir/lowering/mod.rs

Known issue (pre-existing):
- PHI predecessor mismatch bug exists in Pattern6 (both forward and reverse)
- This bug existed BEFORE Phase 257 P0 implementation
- Out of scope for Phase 257 P0 - will be addressed separately

Phase 257 P0
2025-12-20 20:28:41 +09:00
8394b2d6fd docs(phase256): document P1.13.5 boundary SSOT unification
Phase 256.8.5 Cleanup: Document the completion of boundary SSOT
unification across Pattern4/6/7.

Updates:
- Phase 256 README: Add P1.13.5 section with implementation details
- 10-Now.md: Add P1.13.5 to recent fixes list

Documentation highlights:
- Background: Pattern2 fix needed horizontal expansion
- Implementation: SSOT unified across all patterns (2,3,4,6,7)
- Benefits: Structural prevention of entry param mismatch
- Results: ~40 lines of duplication eliminated, magic numbers removed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 20:12:26 +09:00
636b1406bc refactor(joinir): extract get_entry_function helper
Phase 256.8.5: Eliminate duplication of entry function extraction logic
across Pattern2/4/6/7.

Changes:
- Add patterns/common/joinir_helpers.rs with get_entry_function() helper
- Refactor 4 files to use shared helper (eliminate ~40 lines of duplication)
- Consistent error messages across all patterns

Benefits:
- DRY principle: Single source of truth for entry function extraction
- Maintainability: Future changes only need to happen once
- Consistency: All patterns use identical logic and error messages
- Testability: Can be tested independently

Files refactored:
- pattern2_steps/emit_joinir_step_box.rs
- pattern4_with_continue.rs
- pattern6_scan_with_init.rs
- pattern7_split_scan.rs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 20:10:48 +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
cb8a6984d4 refactor: modularize shape_guard.rs and separate canonicalizer tests
shape_guard.rs (1401 lines → 6 files):
- pattern2.rs: Break-loop patterns (132 lines)
- pattern3.rs: If-sum patterns (67 lines)
- pattern4.rs: Continue patterns (152 lines)
- selfhost.rs: Selfhost-specific detectors (245 lines)
- utils.rs: Shared helpers (33 lines)
- mod.rs: API coordination & tests (776 lines)

canonicalizer.rs (1863 lines → 433 lines):
- Separated 1430 lines of tests to canonicalizer_tests.rs

Benefits:
- Improved maintainability (smaller, focused files)
- Clear separation of concerns (pattern families)
- Preserved API compatibility (re-exports)
- No new warnings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 07:29:26 +09:00
077657b7a1 feat(joinir): Phase 256 P1.5-P1.7 contracts and naming SSOT 2025-12-20 06:38:21 +09:00
3d09302832 fix(joinir): guard bridge meta debug logs 2025-12-20 06:36:16 +09:00
41d28330e9 feat(select): Task 2-E complete - VM/LLVM backend support for Select instruction
Phase 256 P1.5: Implement Select instruction (ternary conditional) across entire MIR pipeline

Task 2-E Implementation:
- Added Select ValueId entry to effects() in instruction/methods.rs (pure operation)
- Added Select case to dst_value() for definition tracking
- Added Select case to used_values() for use-def chains (cond, then_val, else_val)
- Fixed non-exhaustive pattern matches in 5 locations:
  * src/mir/instruction/methods.rs: 3 match arms (effects, dst_value, used_values)
  * src/mir/printer_helpers.rs: format_instruction display
  * src/mir/query.rs: reads_of and writes_of MirQuery trait

- Created VM backend: src/llvm_py/instructions/select.py
  * lower_select() implements ternary: dst = cond ? then_val : else_val
  * Converts cond to i1 for boolean test
  * Uses llvmlite builder.select() for LLVM IR generation

- Integrated Select dispatch in instruction_lower.py
  * Imported lower_select module
  * Added select case to instruction dispatch (after barrier, before while)
  * Passes resolver, ValueIds, and CFG context

Compilation Status:  0 errors (cargo build --release succeeded)
MIR Output:  Select instructions present in generated MIR
Next: Investigate SSA undefined value issue in Pattern7 loop_step

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-20 03:20:55 +09:00
bfd324d7b9 feat(joinir): Phase 256 P1.5 - JoinInst::Select 命令サポート(根治)
## 変更内容

Task 1(既完了): boundary パラメータを bridge 経路全体に伝播
- conversion_pipeline.rs, bridge.rs(複数箇所), meta.rs, routing_legacy_binding.rs, execute_box.rs

Task 2-A~2-D: Select 命令の実装
- 2-A: MirInstruction::Select バリアント追加
- 2-B: JoinIR Select → MIR Select 直接変換(branch+phi展開廃止)
- 2-C:  joinir_id_remapper に Select remap case(ValueId変換の根治)
- 2-D: value_collector に Select case

## 根本原因解決

Pattern7 の JoinInst::Select が JoinIR→MIR で未対応
→ ValueId(1002) → ValueId(57) のリマップが行われず
→ "use of undefined value ValueId(57)" エラー

## 現在地

 cargo check: 0 errors
 Pattern7/6 VM test(Task 2-E LLVM実装後)

🧠 Generated with Claude Code
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-20 03:11:58 +09:00
64f679354a fix(joinir): Phase 256 P1 - Carrier PHI wiring and parameter mapping (in progress)
**Status**: Core carrier PHI issue partially resolved, debugging loop body

**Progress**:
 Task 1: split_scan_minimal.rs Carriers-First ordering (6 locations)
 Task 2: pattern7_split_scan.rs boundary configuration (host/join inputs, exit_bindings, expr_result)
 Result now flows from k_exit to post-loop code (RC issue resolved)
⚠️  Loop body instruction execution needs review

**Key Fixes**:
1. Fixed host_inputs/join_inputs to match main() params Carriers-First order
2. Added result to exit_bindings (CarrierRole::LoopState)
3. Added result back to loop_invariants for variable initialization
4. Added expr_result=join_exit_value_result for loop expression return
5. Fixed jump args to k_exit to include all 4 params [i, start, result, s]

**Current Issue**:
- Loop body type errors resolved (String vs Integer fixed)
- New issue: Loop body computations (sep_len) undefined in certain blocks
- Likely cause: JoinIR→MIR conversion of local variables needs review

**Next Steps**:
- Review JoinValueSpace allocation and ValueId mapping in conversion
- Verify loop_step instruction ordering and block structure
- May need to refactor bound computation or revisit split algorithm

🤖 Generated with Claude Code
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-20 01:24:04 +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
2d9c6ea3c6 feat(joinir): Phase 254-255 - Pattern 6 (ScanWithInit) + exit PHI DCE fix
## Phase 254: Pattern 6 (ScanWithInit) Detection & JoinIR Lowering

Pattern 6 detects index_of/find/contains-style loops:
- Loop condition: i < x.length()
- Loop body: if with method call condition + early return
- Step: i = i + 1
- Post-loop: return not-found value (-1)

Key features:
- Minimal lowering: main/loop_step/k_exit functions
- substring hoisted to init-time BoxCall
- Two k_exit jumps (found: i, not found: -1)
- Tests: phase254_p0_index_of_min.hako

## Phase 255 P0: Multi-param Loop CarrierInfo

Implemented CarrierInfo architecture for Pattern 6's 3-variable loop (s, ch, i):
- i: LoopState (header PHI + exit PHI)
- s, ch: ConditionOnly (header PHI only)
- Alphabetical ordering for determinism
- All 3 PHI nodes created correctly
- Eliminates "undefined ValueId" errors

## Phase 255 P1: Exit PHI DCE Fix

Prevents exit PHI from being deleted by DCE:
- PostLoopEarlyReturnStepBox emits post-loop guard
- if (i != -1) { return i } forces exit PHI usage
- Proven pattern from Pattern 2 (balanced_depth_scan)
- VM/LLVM backends working

## Test Results

 pattern254_p0_index_of_vm.sh: PASS (exit code 1)
 pattern254_p0_index_of_llvm_exe.sh: PASS (mock)
 Quick profile: json_lint_vm PASS (progresses past index_of)
 Pattern 1-5: No regressions

## Files Added

- src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs
- src/mir/join_ir/lowering/scan_with_init_minimal.rs
- apps/tests/phase254_p0_index_of_min.hako
- docs/development/current/main/phases/phase-254/README.md
- docs/development/current/main/phases/phase-255/README.md

🧠 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-19 23:32:25 +09:00
09b968256f feat(normalization): Phase 253 - mutable_accumulator_analyzer detector pattern
**Core Change**: Refactor from "validator" to "detector" pattern

**Before** (Fail-Fast):
- Err for non-accumulator assignments (i = i - 1, i = s.length(), etc.)
- JoinIR pipeline aborted on detection

**After** (Detector):
- Ok(None) for non-accumulator patterns (other lowering paths can handle)
- Only Add operator supported (i = i + 1)
- Other operators/patterns return None gracefully

**Modified Behavior** (6 locations):
1. L112-116: operator != Add → Ok(None)
2. L149-152: RHS MethodCall/Call → Ok(None)
3. L153-156: RHS complex expression → Ok(None)
4. L158-161: Left operand reversed → Ok(None)
5. L162-165: Left operand not Variable → Ok(None)
6. L166-170: Value not BinaryOp → Ok(None)

**Tests** (11/11 PASS):
- 2 existing tests updated (Err → Ok(None))
- 3 new tests added:
  - test_decrement_not_accumulator (i = i - 1)
  - test_complex_rhs_not_accumulator (x = x + (i + 1))
  - test_non_binop_assignment_not_accumulator (i = s.length())

**Documentation**:
- Updated docstring to reflect detector strategy
- Detection Strategy section added with all Ok(None) cases

**Status**:
-  mutable-acc-spec errors eliminated
- ⚠️ quick profile still FAIL: StringUtils.index_of/2 not JoinIR-supported (Phase 254 scope)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-19 20:38:57 +09:00
0dd9ec9704 feat(normalization): Phase 252 P1 - DebugOutputBox unification + this.methodcall tests
**P1-1: Local Refactor**:
- loop_with_if_phi_if_sum.rs: Replace 8 eprintln! with DebugOutputBox
- Default output: 0 lines (clean)
- With NYASH_JOINIR_DEBUG=1: Rich trace output

**P1-2: Unit Tests** (3/3 PASS):
- test_this_methodcall_in_condition: BoxCall generation
- test_this_methodcall_requires_context: Static box requirement
- test_this_methodcall_disallowed_method: Method whitelist enforcement

**P1-3: v2 Smoke Fixture**:
- phase252_p0_this_methodcall_break_cond_min.hako
- StringUtils.count_leading_digits with this.is_digit break condition
- VM + LLVM integration test scripts

**P1-4: Test Fixes**:
- condition_lowering_box.rs: current_static_box_name: None
- loop_with_break_minimal/tests.rs: current_static_box_name: None

🧪 Tests:
- cargo test condition_lowerer: 3 new tests PASS
- cargo check --lib: PASS (0 errors)

📊 Quick Profile Status:
- json_pp_vm:  PASS
- json_lint_vm:  FAIL (deferred to Phase 253)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-19 20:30:58 +09:00
9336785680 feat(anf): Phase 146/147 - Loop/If Condition ANF with Compare support
## Phase 146 P0: ANF Routing SSOT Unified

**Goal**: Unify ANF routing in `lower_expr_with_scope()` L54-84, remove legacy lowering

**Changes**:
- expr_lowerer_box.rs: Added scope check (PureOnly → skip ANF, WithImpure → try ANF)
- post_if_post_k.rs: Removed legacy inline lowering (L271-285), added `lower_condition_legacy()` helper
- contract.rs: Already had `CondLoweringFailed` out-of-scope reason

**Test Results**:  Phase 146 P0 smoke (exit 7), 0 regressions

## Phase 146 P1: Compare Operator Support

**Goal**: Enable ANF for condition expressions with Compare operators

**Changes**:
- joinir_dev.rs: Added `anf_allow_pure_enabled()` (HAKO_ANF_ALLOW_PURE=1)
- expr_lowerer_box.rs: PureOnly scope ANF support (L56-66)
- execute_box.rs: Compare operator support (+122 lines)
  - `execute_compare_hoist()`, `execute_compare_recursive()`, `ast_compare_to_joinir()`
  - Extended `normalize_and_lower()` for Compare

**Test Results**:  Phase 146 P1 smoke (exit 7 with flags), 0 regressions

## Phase 147 P0: Recursive Comparison ANF

**Goal**: Extend recursive ANF to Compare operators

**Changes**:
- contract.rs: Added `AnfParentKind::Compare` variant
- plan_box.rs: Compare case in BinaryOp routing (L68-79, L134-139)
  - Distinguishes Compare vs arithmetic BinaryOp

**Benefits**: Enables recursive ANF for comparisons
- `s.length() == 3` → `t = s.length(); if (t == 3)` 
- `s1.length() < s2.length()` → `t1 = s1.length(); t2 = s2.length(); if (t1 < t2)` 

## Implementation Summary

**Files Modified** (9 files, +253 lines, -25 lines = +228 net):
1. src/config/env/joinir_dev.rs (+28 lines)
2. src/mir/control_tree/normalized_shadow/anf/contract.rs (+2 lines)
3. src/mir/control_tree/normalized_shadow/anf/execute_box.rs (+122 lines)
4. src/mir/control_tree/normalized_shadow/anf/plan_box.rs (+18 lines)
5. src/mir/control_tree/normalized_shadow/common/expr_lowerer_box.rs (+18 lines, -0 lines)
6. src/mir/control_tree/normalized_shadow/post_if_post_k.rs (+44 lines, -25 lines)
7. CURRENT_TASK.md
8. docs/development/current/main/10-Now.md
9. docs/development/current/main/30-Backlog.md

**Files Created** (7 files):
- apps/tests/phase146_p0_if_cond_unified_min.hako
- apps/tests/phase146_p1_if_cond_intrinsic_min.hako
- tools/smokes/.../phase146_p0_if_cond_unified_vm.sh
- tools/smokes/.../phase146_p0_if_cond_unified_llvm_exe.sh
- tools/smokes/.../phase146_p1_if_cond_intrinsic_vm.sh
- tools/smokes/.../phase146_p1_if_cond_intrinsic_llvm_exe.sh
- docs/development/current/main/phases/phase-146/README.md

**Acceptance Criteria**:  All met
- cargo build --release: PASS (0 errors, 0 warnings)
- Phase 145 regressions: PASS (exit 12, 18, 5)
- Phase 146 P0: PASS (exit 7)
- Phase 146 P1: PASS (exit 7 with HAKO_ANF_ALLOW_PURE=1)

**Architecture**:
- SSOT: ANF routing only in `lower_expr_with_scope()` L54-84
- Box-First: Phase 145 `anf/` module extended
- Legacy removed: post_if_post_k.rs unified with SSOT

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-19 17:03:56 +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