3cdeb95cbc
refactor(joinir): Eliminate block allocation duplication with BlockAllocator
...
Problem:
- joinir_block_converter.rs had 4 duplicate block allocation patterns
- Lines 260-265, 487-489, 635-639, 740-748 all manually allocating BasicBlockIds
- Total duplication: 27 lines across 4 sites
Solution:
- Use existing BlockAllocator (Phase 260 P0.2) for all block allocations
- Replace manual patterns with allocate_two(), allocate_three(), allocate_n()
Changes:
- Site 1/4 (handle_conditional_method_call): 6 lines → 3 lines (-3)
- Site 2/4 (handle_jump): 4 lines → 3 lines (-1)
- Site 3/4 (handle_if_merge): 6 lines → 3 lines (-3)
- Site 4/4 (handle_nested_if_merge): 11 lines → 8 lines (-3)
Result:
- ✅ 10 lines eliminated
- ✅ Improved readability (clear intent)
- ✅ Improved maintainability (SSOT for allocation)
- ✅ No behavior change (all tests pass)
- ✅ No regression: phase269_p1_2, phase259_p0, phase269_p0 PASS
Follow-up potential:
- MergeVariableHandlerBox duplication (lines 652-660, 667-675, 785-791, 800-806)
- CallInstructionGeneratorBox duplication (lines 403-406, 511-514, 536-546)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-22 03:58:12 +09:00
4ef2261e97
fix(joinir): Phase 269 P1.2 - static call normalization for this.method()
...
Problem:
- `this.method()` calls in static box loops were using string constant "StringUtils" as receiver
- This violated Box Theory (static box this should not be runtime object)
- Pattern8 was trying to pass receiver to JoinIR, causing SSA/PHI issues
Solution (3-part fix):
1. **MeResolverBox Fail-Fast** (stmts.rs): Remove string fallback, error message cleanup
2. **ReceiverNormalizeBox** (calls/build.rs): Normalize `this/me.method()` → static call at compile-time
3. **Pattern8 Skip Static Box** (pattern8_scan_bool_predicate.rs): Reject Pattern8 for static box contexts
Key changes:
- **stmts.rs**: Update error message - remove MeBindingInitializerBox mentions
- **calls/build.rs**: Add This/Me receiver check, normalize to static call if current_static_box exists
- **calls/lowering.rs**: Remove NewBox-based "me" initialization (2 locations - fixes Stage1Cli regression)
- **pattern8_scan_bool_predicate.rs**: Skip Pattern8 for static boxes (use Pattern1 fallback instead)
Result:
- ✅ phase269_p1_2_this_method_in_loop_vm.sh PASS (exit=7)
- ✅ No regression: phase259_p0_is_integer_vm PASS
- ✅ No regression: phase269_p0_pattern8_frag_vm PASS
- ✅ Stage1Cli unit tests PASS
- ✅ MIR uses CallTarget::Global, no const "StringUtils" as receiver
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-22 03:33:30 +09:00
5f22fe8fcd
feat(pattern8): Phase 269 P1 - SSA fix and call_method type annotation
...
Phase 269 P1.0: Pattern8 SSA correctness
- Add PHI node for loop variable `i` in pattern8_scan_bool_predicate.rs
- Ensure proper SSA form: i_current = phi [(preheader, i_init), (step, i_next)]
- Create loop_predicate_scan.rs for Pattern8 Frag emission
- Pre-allocate PHI destination before block generation
- Use insert_phi_at_head_spanned() for span synchronization
Phase 269 P1.1: call_method return type SSOT propagation
- Add callee_sig_name() helper in annotation.rs for function name formatting
- Annotate call_method return types in emit_unified_call_impl()
- Use module signature as SSOT for return type resolution (no hardcoding)
- Arity-aware function name: "BoxName.method/arity"
Fixes: is_integer() now correctly returns Bool instead of String
Test: Simple call_method test returns exit=7 (loop test has pre-existing bug)
Unit tests: All 1389 tests passing
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-22 01:41:19 +09:00
df715e909e
feat(edgecfg): Phase 268-270 savepoint (if_form adoption + Pattern9 minimal loop SSOT)
2025-12-21 23:12:52 +09:00
bd84fdf78f
feat(edgecfg): Phase 267 P0 BranchStub + emit_frag (Branch→MIR)
2025-12-21 20:33:11 +09:00
f8779df5a6
feat(edgecfg): Phase 266 emit_wires PoC (wires→MIR Jump/Return)
2025-12-21 17:20:48 +09:00
21387f3816
feat(edgecfg): Phase 265 P2 - seq/if_ 実装(wires/exits 分離)
...
## 目的
「解決済み配線(wires)」と「未解決 exit(exits)」を分離し、
Frag 合成の基本パターンを完成させる。
## 実装内容
### 1. Frag 構造体の変更
- `wires: Vec<EdgeStub>` フィールド追加
- 不変条件:
- exits: target = None のみ(未配線、外へ出る exit)
- wires: target = Some(...) のみ(配線済み、内部配線)
### 2. loop_() の wires 対応
- Break/Continue を exits から wires に移動
- P1 テスト 3個を wires 検証に更新
### 3. seq(a, b) 実装
- a.Normal → b.entry を wires に追加(内部配線)
- seq の exits[Normal] は b の Normal のみ
- 新規テスト 2個追加
### 4. if_(header, cond, t, e, join_frag) 実装
- シグネチャ変更: join: BasicBlockId → join_frag: Frag
- t/e.Normal → join_frag.entry を wires に追加
- if の exits は join_frag.exits
- 新規テスト 2個追加
### 5. verify_frag_invariants() 強化
- wires/exits 分離契約の検証追加(警告のみ)
- Err 化は Phase 266 で実施
## テスト結果
- edgecfg::api: 13/13 PASS(frag 3 + compose 9 + verify 1)
- 全 lib テスト: 1388/1388 PASS(退行なし)
## 核心的な設計判断
1. **wires/exits 分離**:
- 問題: 解決済み配線と未解決 exit を混ぜると再配線バグ
- 解決: 分離して不変条件を強化
- 効果: Phase 266 で wires を MIR terminator に落とすだけ
2. **if_ は join_frag 受け取り**:
- 問題: join: BasicBlockId では「join block」か「join 以降」か曖昧
- 解決: join_frag: Frag で「join 以降」を明確化
- 効果: PHI 生成の柔軟性確保
3. **verify は警告のみ**:
- P2 の役割: wires/exits 分離の証明に集中
- Phase 266 で MIR 生成時に厳格化
## 次フェーズへの橋渡し
- Phase 266: wires を MIR terminator に落とす
- Phase 267: Pattern6/7/8 を Frag 化
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-21 16:47:47 +09:00
cda034fe8f
feat(edgecfg): Phase 265 P1 - compose 配線ロジック実装(test-only PoC)
...
## 目的
Frag/ExitKind が BasicBlockId 層で配線できることを証明
## 実装完了内容
- EdgeStub に target: Option<BasicBlockId> 追加
- compose::loop_() 配線ロジック実装(Continue → header, Break → after)
- verify_frag_invariants() 配線契約検証追加
- test-only PoC で実証完了(5個のテスト)
## 配線契約
- Continue(loop_id) の EdgeStub.target = Some(header)
- Break(loop_id) の EdgeStub.target = Some(after)
- Normal/Return/Unwind の EdgeStub.target = None(上位へ伝搬)
## テスト
- compose::tests: 5 PASS(既存2個更新 + 新規3個追加)
- verify::tests: 1 PASS(基本smoke test)
- cargo test -p nyash-rust --lib: SUCCESS
## 重要な制約
- MIR 命令生成はまだしない(Frag 層の配線能力証明のみ)
- NormalizedShadow/JoinIR層への適用は Phase 266 に繰り越し
- Pattern6/7/8 未改変(配線能力の証明に集中)
## 次のステップ
- Phase 265 P2: seq/if_ 実装(順次合成・条件分岐合成)
- Phase 266: JoinIR-VM Bridge 改修後、NormalizedShadow への適用
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-21 16:22:46 +09:00
ab1510920c
feat(edgecfg): Phase 265 P0 - compose/verify 最小実装(入口SSOT迷子防止)
...
🎯 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-21 13:07:17 +09:00
923a442326
refactor(edgecfg): add Frag/ExitKind API entrypoint (Phase 264 design-first)
...
Phase 264 P0: EdgeCFG Fragment 入口API作成(実装置換なし)
- 入口フォルダ作成: src/mir/builder/control_flow/edgecfg/api/
- コア型定義: ExitKind, EdgeStub, Frag
- 合成関数シグネチャ: seq, if_, loop_, cleanup(中身TODO、pub(crate))
- 最小テスト: 3個のユニットテスト追加(frag.rs)
- ドキュメント連動: edgecfg-fragments.md に実装入口追記
制約遵守:
- 既存 pattern6/7/8 未改変
- merge/EdgeCFG 未改変
- 既存LoopId使用(control_form.rs に PartialOrd, Ord 追加)
- MIR側EdgeArgs使用(JoinIRと混線回避)
- BTreeMap採用(決定的順序保証、Phase 69-3 教訓)
次フェーズ: Phase 265 で Pattern8 適用時に compose::loop_ を実装
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-21 12:49:53 +09:00
be4de67601
fix(joinir): improve Pattern3 classification to exclude simple conditional assignment (Phase 264 P0)
...
Problem:
- Pattern3 heuristic was too conservative: detect_if_in_body() returned
true for ANY if statement, causing simple conditional assignments to be
misclassified as Pattern3IfPhi
- Example: `if i == 0 then seg = "first" else seg = "other"` was routed
to Pattern3, but Pattern3 only handles if-sum patterns like
`sum = sum + (if x then 1 else 0)`
- This caused loops with conditional assignment to fail Pattern3 check
and exhaust all routing paths
Solution (Conservative, Phase 264 P0):
- ast_feature_extractor.rs:
- detect_if_else_phi_in_body(): Always return false
- has_if = has_if_else_phi (don't use detect_if_in_body())
- loop_pattern_detection/mod.rs:
- Add has_if_sum_signature() (returns false for P0)
- has_if_else_phi = carrier_count > 1 && has_if_sum_signature(scope)
Effect:
- Simple conditional assignment loops now fall through to Pattern1 ✅
- Pattern3 misrouting prevented ✅
Results:
- Lib tests: 1368/1368 PASS (no regression)
- Minimal repro: phase264_p0_bundle_resolver_loop_min.hako PASS ✅
- Quick smoke: 45/46 (unchanged - complex BundleResolver loop needs P1)
Phase 264 P1 TODO:
- Implement accurate if-sum signature detection (AST/CFG analysis)
- Support complex nested loops in Pattern2 or new pattern
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-21 11:49:03 +09:00
e17902a443
refactor(pattern2): move promotion decision into pattern2/api SSOT
...
Phase 263 P0.2: pattern2/api/ フォルダ化 - 入口SSOTの物理固定
目的: PromoteDecision/try_promote の参照点を1箇所に閉じ込めて、迷子防止
Changes:
1. 新規フォルダ構造:
- pattern2/api/mod.rs - 入口SSOT(try_promote と PromoteDecision を再export)
- pattern2/api/promote_decision.rs - PromoteDecision/PromoteStepResult 型定義
- pattern2/api/promote_runner.rs - try_promote(...) 実装(SSOT entry point)
- pattern2/mod.rs - api モジュールを公開
2. 移動/抽出:
- PromoteDecision enum を promote_step_box.rs → pattern2/api/promote_decision.rs へ
- promote_and_prepare_carriers を try_promote として pattern2/api/promote_runner.rs へ抽出
3. promote_step_box.rs を薄いラッパに縮退(35行, -177行):
- pattern2::api::try_promote を呼び出すだけの互換用ラッパ
- 将来的に削除予定(deprecated)
4. orchestrator を新API に書き換え:
- use super::pattern2::api::{try_promote, PromoteDecision};
- try_promote(...) を直接呼び出し
5. 参照確認:
- rg で確認: すべての参照が pattern2::api 経由に収束 ✅
検証:
- cargo test --lib: 1368/1368 PASS ✅
- quick smoke: 45/46 PASS ✅ (悪化なし)
- 参照点が pattern2/api に一本化され、迷子防止を物理的に保証
2025-12-21 11:07:36 +09:00
abdb860e7e
refactor(pattern2): introduce PromoteDecision enum to eliminate Option wrapping ambiguity
...
Phase 263 P0.1: PromoteDecision API hardening
目的: Result<Option<PromoteStepResult>, String> の揺れを型で固定し、迷子をゼロに
Changes:
- promote_step_box.rs:
- PromoteDecision enum を導入(Promoted/NotApplicable/Freeze)
- PromoteStepBox::run() の戻り値を Result<PromoteDecision, String> に統一
- promote_and_prepare_carriers() が inputs の所有権を受け取り、PromoteDecision を直接構築
- Reject 分岐を型安全に二分化(文字列マッチング維持、型で意図を明確化)
- pattern2_lowering_orchestrator.rs:
- orchestrator 側の分岐を1箇所に固定(match PromoteDecision {...})
- NotApplicable → Ok(None) で後続経路へ
- Freeze → Err で Fail-Fast
受け入れ:
- quick smoke: 45/46 PASS ✅ (悪化なし)
- NotApplicable は必ず Ok(None) で Pattern2全体を抜ける
- Freeze は必ず Err(fail-fast)
Next: ファイル構造リファクタリング(pattern2/api/ フォルダ化)を別フェーズで検討
2025-12-21 10:54:46 +09:00
93022e7e10
fix(pattern2): abort entire Pattern2 on unpromoted LoopBodyLocal instead of partial execution
...
Phase 263 P0: Pattern2 で処理できない LoopBodyLocal を検出したら Pattern2 全体を早期終了
Changes:
- promote_step_box.rs: 戻り値を Result<Option<_>, String> に変更
- Reject を二分化: 対象外(not_readonly等)→ Ok(None)、対象だが未対応 → Err
- pattern2_lowering_orchestrator.rs: Ok(None) 検出で早期 return
- apps/tests/phase263_p0_pattern2_seg_min.hako: test simplification
後続経路(legacy binding等)へ fallback させる(detection→extract→lower SSOT 維持)
Fail-Fast 原則: 対象外は Ok(None) で後続経路へ、対象だが未対応は Err で即座に失敗
Fixes: core_direct_array_oob_set_rc_vm smoke test FAIL
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-21 10:23:38 +09:00
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
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
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
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
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