From c3a26e705ef984f976e1b1d8c0e2db34df50d1c1 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Fri, 12 Dec 2025 05:23:18 +0900 Subject: [PATCH] feat(joinir): Phase 47-A-IMPL - P3 Normalized infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement Pattern3 (if-sum) Normalized infrastructure, extending existing P2 StepSchedule and ShapeGuard systems. Key changes: 1. StepSchedule generalization (P2 → P2/P3): - Renamed: pattern2_step_schedule.rs → step_schedule.rs - Extended StepKind enum with P3 variants: - IfCond (if condition in body) - ThenUpdates (carrier updates in then branch) - ElseUpdates (carrier updates in else branch) - Added pattern3_if_sum_schedule() function - Added unit test: test_pattern3_if_sum_schedule() - Updated module references (mod.rs, loop_with_break_minimal.rs) 2. ShapeGuard extension: - Added Pattern3IfSumMinimal variant to NormalizedDevShape - Added is_pattern3_if_sum_minimal() detector (placeholder) - Updated shape detector table - Extended capability_for_shape() mapping 3. Bridge integration: - bridge.rs: Added P3 shape handling in normalize_for_shape() - normalized.rs: Added P3 roundtrip match (uses P2 temporarily) 4. P2/P3 separation: - loop_with_break_minimal.rs: Added panic for P3 steps in P2 lowering - Clear boundary enforcement (P2 lowerer rejects P3 steps) 5. Documentation: - CURRENT_TASK.md: Phase 47-A-IMPL status - phase47-norm-p3-design.md: Implementation status section Benefits: - Reuses 90% of P2 infrastructure (ConditionEnv, CarrierInfo, ExitLine) - Clean P2/P3 separation via StepKind - Pure additive changes (no P2 behavioral changes) - Ready for Phase 47-A-LOWERING (full P3 Normalized implementation) Tests: 938/938 PASS (+1 from step_schedule unit test) - All existing P1/P2 tests pass (no regressions) - P3 test uses Structured path temporarily (proper lowering in next phase) Next phase: Implement full P3 Normalized→MIR(direct) lowering --- CURRENT_TASK.md | 7 +++ .../current/main/phase47-norm-p3-design.md | 21 ++++++++ .../lowering/loop_with_break_minimal.rs | 6 ++- src/mir/join_ir/lowering/mod.rs | 2 +- ...ern2_step_schedule.rs => step_schedule.rs} | 53 +++++++++++++++---- src/mir/join_ir/normalized.rs | 5 ++ src/mir/join_ir/normalized/shape_guard.rs | 21 ++++++++ src/mir/join_ir_vm_bridge/bridge.rs | 4 ++ 8 files changed, 107 insertions(+), 12 deletions(-) rename src/mir/join_ir/lowering/{pattern2_step_schedule.rs => step_schedule.rs} (77%) diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index a4c67f7c..e9707790 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -87,6 +87,13 @@ - JsonParser P2 ライン(_skip_whitespace/_atoi/_parse_number)全て canonical Normalized 化完了。 - P3/P4 Normalized 対応は NORM-P3/NORM-P4 フェーズで実施(今回スコープ外)。 - 937/937 tests PASS。 +- **Phase 47-A-IMPL(実装中 2025-12-12)**: + - StepScheduleBox 汎用化: pattern2_step_schedule.rs → step_schedule.rs リネーム + - P3 StepKind 追加: IfCond, ThenUpdates, ElseUpdates(P2 lowering との分離完了) + - ShapeGuard: Pattern3IfSumMinimal 検出追加(placeholder stub実装) + - Normalized bridge: P3 shape handling 追加(P2 normalization 使用) + - 938/938 tests PASS(regression なし) + - 次ステップ: Phase 47-A-LOWERING で full P3 Normalized lowering 実装 - **Phase 45-NORM-MODE(実装済み✅ 2025-12-12)**: - JoinIR モード一本化: バラバラだったフラグ/feature を `JoinIrMode` enum に集約(StructuredOnly / NormalizedDev / NormalizedCanonical)。 - `current_joinir_mode()` でモード取得、bridge/runner で `normalized_dev_enabled()` → mode pattern matching に移行。 diff --git a/docs/development/current/main/phase47-norm-p3-design.md b/docs/development/current/main/phase47-norm-p3-design.md index 10490c2c..6bff217c 100644 --- a/docs/development/current/main/phase47-norm-p3-design.md +++ b/docs/development/current/main/phase47-norm-p3-design.md @@ -155,6 +155,27 @@ loop(i < arr.length()) { Complex P3 patterns from selfhost compiler (deferred to later phase). +## Implementation Status + +**Phase 47-A-PREP** (✅ Complete, commit 42ecd7a7): +- Fixture added: `pattern3_if_sum_minimal` in `normalized/fixtures.rs` +- Test stub added: `test_normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured` +- Basic infrastructure for P3 development mode testing + +**Phase 47-A-IMPL** (✅ Complete, 2025-12-12): +- ✅ StepSchedule renamed and extended: `pattern2_step_schedule.rs` → `step_schedule.rs` +- ✅ P3 StepKind added: `IfCond`, `ThenUpdates`, `ElseUpdates` +- ✅ Pattern2 lowering separation: P3 steps panic in P2 lowering (clean boundary) +- ✅ ShapeGuard: `Pattern3IfSumMinimal` detection added (placeholder stub) +- ✅ Normalized bridge: P3 shape handling in `normalize_for_shape()` and roundtrip +- ✅ 938/938 tests PASS (no regressions) +- ⏳ TODO: Full P3 Normalized lowering (Phase 47-A-LOWERING) + +**Next Phase** (Phase 47-A-LOWERING): +- Implement `lower_pattern3_if_sum_minimal()` fully +- Generate Normalized JpInst for P3 structure (If branching, conditional updates) +- Test VM output comparison (Normalized vs Structured) + ## Implementation Strategy ### Phase 47-A: Minimal sum_count (dev-only) diff --git a/src/mir/join_ir/lowering/loop_with_break_minimal.rs b/src/mir/join_ir/lowering/loop_with_break_minimal.rs index 3b47bb4f..19128e57 100644 --- a/src/mir/join_ir/lowering/loop_with_break_minimal.rs +++ b/src/mir/join_ir/lowering/loop_with_break_minimal.rs @@ -70,7 +70,7 @@ use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace; use crate::mir::join_ir::lowering::loop_body_local_env::LoopBodyLocalEnv; use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; use crate::mir::join_ir::lowering::loop_update_analyzer::UpdateExpr; -use crate::mir::join_ir::lowering::pattern2_step_schedule::{ +use crate::mir::join_ir::lowering::step_schedule::{ build_pattern2_schedule, Pattern2ScheduleContext, Pattern2StepKind, }; use crate::mir::join_ir::lowering::update_env::UpdateEnv; @@ -667,6 +667,10 @@ pub(crate) fn lower_loop_with_break_minimal( Pattern2StepKind::BreakCheck => loop_step_func.body.append(&mut break_block), Pattern2StepKind::Updates => loop_step_func.body.append(&mut carrier_update_block), Pattern2StepKind::Tail => loop_step_func.body.append(&mut tail_block), + // Phase 47-A: P3 steps not used in P2 lowering (handled in Pattern3 lowerer) + Pattern2StepKind::IfCond | Pattern2StepKind::ThenUpdates | Pattern2StepKind::ElseUpdates => { + panic!("Pattern3 step kinds should not appear in Pattern2 lowering"); + } } } diff --git a/src/mir/join_ir/lowering/mod.rs b/src/mir/join_ir/lowering/mod.rs index 9d6c2681..976252f1 100644 --- a/src/mir/join_ir/lowering/mod.rs +++ b/src/mir/join_ir/lowering/mod.rs @@ -61,7 +61,7 @@ pub(crate) mod loop_view_builder; // Phase 33-23: Loop lowering dispatch pub mod loop_with_break_minimal; // Phase 188-Impl-2: Pattern 2 minimal lowerer pub mod loop_with_continue_minimal; pub mod method_call_lowerer; // Phase 224-B: MethodCall lowering (metadata-driven) -pub(crate) mod pattern2_step_schedule; // Phase 39: Pattern2 evaluation order scheduler +pub(crate) mod step_schedule; // Phase 47-A: Generic step scheduler for P2/P3 (renamed from pattern2_step_schedule) pub mod method_return_hint; // Phase 83: P3-D 既知メソッド戻り値型推論箱 pub mod scope_manager; // Phase 231: Unified variable scope management // Phase 195: Pattern 4 minimal lowerer // Phase 242-EX-A: loop_with_if_phi_minimal removed - replaced by loop_with_if_phi_if_sum diff --git a/src/mir/join_ir/lowering/pattern2_step_schedule.rs b/src/mir/join_ir/lowering/step_schedule.rs similarity index 77% rename from src/mir/join_ir/lowering/pattern2_step_schedule.rs rename to src/mir/join_ir/lowering/step_schedule.rs index 742d04dc..1b77bce6 100644 --- a/src/mir/join_ir/lowering/pattern2_step_schedule.rs +++ b/src/mir/join_ir/lowering/step_schedule.rs @@ -1,9 +1,11 @@ -//! Pattern 2 step scheduler (StepScheduleBox). +//! Phase 47-A: Generic step scheduling for Pattern2/Pattern3 loops //! -//! Decides the evaluation order for Pattern 2 lowering without hardcoding it -//! inside the lowerer. This keeps the lowerer focused on emitting fragments, -//! while this box decides how to interleave them (e.g., body-local init before -//! break checks when the break depends on body-local values). +//! Determines evaluation order for loop steps (header cond, body init, break check, etc). +//! Used by both P2 (break) and P3 (if-sum) patterns. +//! +//! This keeps the lowerer focused on emitting fragments, while this box decides +//! how to interleave them (e.g., body-local init before break checks when the +//! break depends on body-local values). use crate::config::env; use crate::config::env::joinir_dev::joinir_test_debug_enabled; @@ -13,11 +15,17 @@ use crate::mir::join_ir::lowering::loop_body_local_env::LoopBodyLocalEnv; /// Steps that can be reordered by the scheduler. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum Pattern2StepKind { - HeaderCond, - BodyInit, - BreakCheck, - Updates, - Tail, + // P2 (Pattern2 Break) steps + HeaderCond, // loop(cond) + BodyInit, // local ch = ... + BreakCheck, // if (cond) break + Updates, // sum = sum + 1 + Tail, // i = i + 1 + + // Phase 47-A: P3 (Pattern3 If-Sum) steps + IfCond, // if (cond) in body + ThenUpdates, // carrier updates in then branch + ElseUpdates, // carrier updates in else branch (if any) } impl Pattern2StepKind { @@ -28,6 +36,10 @@ impl Pattern2StepKind { Pattern2StepKind::BreakCheck => "break", Pattern2StepKind::Updates => "updates", Pattern2StepKind::Tail => "tail", + // Phase 47-A: P3 steps + Pattern2StepKind::IfCond => "if-cond", + Pattern2StepKind::ThenUpdates => "then-updates", + Pattern2StepKind::ElseUpdates => "else-updates", } } } @@ -136,6 +148,17 @@ fn log_schedule(ctx: &Pattern2ScheduleContext, schedule: &Pattern2StepSchedule) ); } +/// Phase 47-A: Generate step schedule for Pattern3 (if-sum) loops +pub(crate) fn pattern3_if_sum_schedule() -> Vec { + vec![ + Pattern2StepKind::HeaderCond, // loop(i < n) + Pattern2StepKind::IfCond, // if (i > 0) + Pattern2StepKind::ThenUpdates, // sum = sum + i + // ElseUpdates omitted for minimal (no else branch) + Pattern2StepKind::Tail, // i = i + 1 + ] +} + #[cfg(test)] mod tests { use super::*; @@ -221,4 +244,14 @@ mod tests { ); assert_eq!(schedule.reason(), "body-local break dependency"); } + + #[test] + fn test_pattern3_if_sum_schedule() { + let schedule = pattern3_if_sum_schedule(); + assert_eq!(schedule.len(), 4); + assert_eq!(schedule[0], Pattern2StepKind::HeaderCond); + assert_eq!(schedule[1], Pattern2StepKind::IfCond); + assert_eq!(schedule[2], Pattern2StepKind::ThenUpdates); + assert_eq!(schedule[3], Pattern2StepKind::Tail); + } } diff --git a/src/mir/join_ir/normalized.rs b/src/mir/join_ir/normalized.rs index 3e07e275..da0acc22 100644 --- a/src/mir/join_ir/normalized.rs +++ b/src/mir/join_ir/normalized.rs @@ -905,6 +905,11 @@ pub(crate) fn normalized_dev_roundtrip_structured( let norm = normalize_pattern2_minimal(module); normalized_pattern2_to_structured(&norm) })), + // Phase 47-A: P3 minimal uses P2 normalization for now + NormalizedDevShape::Pattern3IfSumMinimal => catch_unwind(AssertUnwindSafe(|| { + let norm = normalize_pattern2_minimal(module); + normalized_pattern2_to_structured(&norm) + })), }; match attempt { diff --git a/src/mir/join_ir/normalized/shape_guard.rs b/src/mir/join_ir/normalized/shape_guard.rs index 9f63c448..4aaa8a45 100644 --- a/src/mir/join_ir/normalized/shape_guard.rs +++ b/src/mir/join_ir/normalized/shape_guard.rs @@ -50,6 +50,8 @@ pub enum NormalizedDevShape { JsonparserAtoiMini, JsonparserAtoiReal, JsonparserParseNumberReal, + // Phase 47-A: Pattern3 (if-sum) minimal + Pattern3IfSumMinimal, } type Detector = fn(&JoinModule) -> bool; @@ -77,6 +79,11 @@ const SHAPE_DETECTORS: &[(NormalizedDevShape, Detector)] = &[ NormalizedDevShape::JsonparserParseNumberReal, detectors::is_jsonparser_parse_number_real, ), + // Phase 47-A: Pattern3 if-sum minimal + ( + NormalizedDevShape::Pattern3IfSumMinimal, + detectors::is_pattern3_if_sum_minimal, + ), ]; /// direct ブリッジで扱う shape(dev 限定)。 @@ -104,6 +111,8 @@ pub fn capability_for_shape(shape: &NormalizedDevShape) -> ShapeCapability { JsonparserAtoiMini | JsonparserAtoiReal => P2CoreAtoi, JsonparserParseNumberReal => P2MidParseNumber, Pattern1Mini => P2CoreSimple, // Also core simple pattern + // Phase 47-A: P3 minimal maps to P2CoreSimple for now (future: P3CoreSimple) + Pattern3IfSumMinimal => P2CoreSimple, }; ShapeCapability::new(kind) @@ -338,6 +347,18 @@ mod detectors { .any(|f| f.name == "jsonparser_parse_number_real") } + /// Phase 47-A: Check if module matches Pattern3 if-sum minimal shape + pub(crate) fn is_pattern3_if_sum_minimal(module: &JoinModule) -> bool { + // For now, simple heuristic: + // - Has Pattern3 structure (if-sum) + // - Single carrier (sum) + // - Simple loop condition + + // TODO: Implement proper detection based on fixture + // For Phase 47-A, this will be called explicitly in tests + false // Placeholder - will be refined in later commits + } + pub(super) fn find_loop_step(module: &JoinModule) -> Option<&JoinFunction> { module .functions diff --git a/src/mir/join_ir_vm_bridge/bridge.rs b/src/mir/join_ir_vm_bridge/bridge.rs index 7fd3049e..76d9d3b4 100644 --- a/src/mir/join_ir_vm_bridge/bridge.rs +++ b/src/mir/join_ir_vm_bridge/bridge.rs @@ -72,6 +72,10 @@ fn normalize_for_shape( | NormalizedDevShape::JsonparserParseNumberReal => { catch_unwind(AssertUnwindSafe(|| normalize_pattern2_minimal(module))) } + // Phase 47-A: P3 minimal normalization (stub - will use P2 for now) + NormalizedDevShape::Pattern3IfSumMinimal => { + catch_unwind(AssertUnwindSafe(|| normalize_pattern2_minimal(module))) + } }; match result {