From 0664526d996c42a28a9266f7f2ca651b5c048d4b Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 23 Dec 2025 00:01:58 +0900 Subject: [PATCH] feat(plan): Phase 273 P3 - Plan Lowering SSOT Finalize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 273 P3 完成: CoreLoopPlan SSOT 化、legacy fallback 撤去 Changes: - CoreLoopPlan: Option<...> → 必須フィールド化(構造で "揺れ" を消す) - block_effects, phis, frag, final_values が必須に - legacy fields 削除 (header_effects, step_effects, carriers, loop_var_name) - Lowerer: lower_loop_legacy() 撤去、generalized 経路のみ - emit_scan_with_init_edgecfg() 参照が完全に消えた - Normalizer: Pattern6/7 両方が generalized fields のみを使用 - Verifier: generalized 専用の不変条件追加 (V7-V9) - V7: PHI non-empty - V8: frag.entry == header_bb - V9: block_effects contains header_bb Acceptance Criteria: - ✅ Lowerer から pattern 固有参照が消えている - ✅ Pattern6/7 が generalized CoreLoopPlan を使用 - ✅ legacy fallback 撤去、欠落時は型エラー (Fail-Fast) - ✅ VM テスト PASS (phase254/256/258) - ✅ LLVM テスト PASS (phase256/258) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/mir/builder/control_flow/plan/lowerer.rs | 180 +++--------------- src/mir/builder/control_flow/plan/mod.rs | 35 ++-- .../builder/control_flow/plan/normalizer.rs | 37 ++-- src/mir/builder/control_flow/plan/verifier.rs | 73 +++++-- 4 files changed, 105 insertions(+), 220 deletions(-) diff --git a/src/mir/builder/control_flow/plan/lowerer.rs b/src/mir/builder/control_flow/plan/lowerer.rs index 703eb1a6..2e036ade 100644 --- a/src/mir/builder/control_flow/plan/lowerer.rs +++ b/src/mir/builder/control_flow/plan/lowerer.rs @@ -1,4 +1,4 @@ -//! Phase 273 P1: PlanLowerer - CorePlan → MIR 生成 (SSOT) +//! Phase 273 P3: PlanLowerer - CorePlan → MIR 生成 (SSOT) //! //! # Responsibilities //! @@ -10,6 +10,12 @@ //! //! Lowerer processes CorePlan ONLY. It does not know about scan, split, or //! any other pattern-specific semantics. All pattern knowledge is in Normalizer. +//! +//! # Phase 273 P3: SSOT Finalization +//! +//! - Generalized fields (block_effects/phis/frag/final_values) are now REQUIRED +//! - Legacy fallback has been removed (Fail-Fast on missing fields) +//! - Pattern-specific emission functions (emit_scan_with_init_edgecfg) no longer used use super::{CoreEffectPlan, CoreLoopPlan, CorePlan}; use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext; @@ -66,7 +72,7 @@ impl PlanLowerer { /// Loop: emit blocks, effects, PHI, and edge CFG /// /// This is pattern-agnostic. All pattern knowledge is in Normalizer. - /// Phase 273 P2: Now supports generalized fields with fallback to legacy. + /// Phase 273 P3: Generalized fields are now REQUIRED (Fail-Fast). fn lower_loop( builder: &mut MirBuilder, loop_plan: CoreLoopPlan, @@ -81,32 +87,23 @@ impl PlanLowerer { trace_logger.debug( "lowerer/loop", &format!( - "Phase 273 P2: Lowering CoreLoopPlan for {}", + "Phase 273 P3: Lowering CoreLoopPlan for {}", ctx.func_name ), ); } - // Phase 273 P2: Check if using generalized fields - let use_generalized = loop_plan.block_effects.is_some() - && loop_plan.phis.is_some() - && loop_plan.frag.is_some() - && loop_plan.final_values.is_some(); + // Phase 273 P3: Generalized fields are now struct fields (not Option) + // No validation needed - type system guarantees presence - if use_generalized { - if debug { - trace_logger.debug("lowerer/loop", "Using generalized fields"); - } - Self::lower_loop_generalized(builder, loop_plan, ctx) - } else { - if debug { - trace_logger.debug("lowerer/loop", "Using legacy fields (fallback)"); - } - Self::lower_loop_legacy(builder, loop_plan, ctx) + if debug { + trace_logger.debug("lowerer/loop", "Processing generalized fields (SSOT)"); } + + Self::lower_loop_generalized(builder, loop_plan, ctx) } - /// Phase 273 P2: Generalized loop lowering + /// Phase 273 P3: Generalized loop lowering (SSOT) fn lower_loop_generalized( builder: &mut MirBuilder, loop_plan: CoreLoopPlan, @@ -118,10 +115,11 @@ impl PlanLowerer { let trace_logger = trace::trace(); let debug = ctx.debug; - let block_effects = loop_plan.block_effects.as_ref().unwrap(); - let phis = loop_plan.phis.as_ref().unwrap(); - let frag = loop_plan.frag.as_ref().unwrap(); - let final_values = loop_plan.final_values.as_ref().unwrap(); + // Phase 273 P3: Direct access (not Option - type system guarantees presence) + let block_effects = &loop_plan.block_effects; + let phis = &loop_plan.phis; + let frag = &loop_plan.frag; + let final_values = &loop_plan.final_values; // Step 1: Emit Jump from current block to loop entry if builder.current_block.is_some() { @@ -223,139 +221,9 @@ impl PlanLowerer { Ok(Some(void_val)) } - /// Phase 273 P2: Legacy loop lowering (fallback for old Normalizer) - fn lower_loop_legacy( - builder: &mut MirBuilder, - loop_plan: CoreLoopPlan, - ctx: &LoopPatternContext, - ) -> Result, String> { - use crate::mir::builder::control_flow::joinir::trace; - - let trace_logger = trace::trace(); - let debug = ctx.debug; - - // Step 1: Emit Jump from preheader (current block) to header - if builder.current_block.is_some() { - builder.emit_instruction(MirInstruction::Jump { - target: loop_plan.header_bb, - edge_args: None, - })?; - } - - // Step 2: Start header block and emit header effects - builder.start_new_block(loop_plan.header_bb)?; - - for effect in &loop_plan.header_effects { - Self::emit_effect(builder, effect)?; - } - - if debug { - trace_logger.debug( - "lowerer/loop", - &format!("Header effects emitted: {} effects", loop_plan.header_effects.len()), - ); - } - - // Step 3: Start body block and emit body plans - builder.start_new_block(loop_plan.body_bb)?; - - for plan in loop_plan.body { - match plan { - CorePlan::Effect(effect) => { - Self::emit_effect(builder, &effect)?; - } - _ => { - // P1: Only Effect plans in body for now - return Err("[lowerer] Non-Effect plan in Loop body not yet supported".to_string()); - } - } - } - - if debug { - trace_logger.debug("lowerer/loop", "Body plans emitted"); - } - - // Step 4: Start step block and emit step effects - builder.start_new_block(loop_plan.step_bb)?; - - for effect in &loop_plan.step_effects { - Self::emit_effect(builder, effect)?; - } - - if debug { - trace_logger.debug( - "lowerer/loop", - &format!("Step effects emitted: {} effects", loop_plan.step_effects.len()), - ); - } - - // Step 5: Ensure found_bb and after_bb exist - builder.ensure_block_exists(loop_plan.found_bb)?; - builder.ensure_block_exists(loop_plan.after_bb)?; - - // Step 6: Insert PHI at header for each carrier - use crate::mir::builder::emission::phi::insert_loop_phi; - - for carrier in &loop_plan.carriers { - insert_loop_phi( - builder, - loop_plan.header_bb, - carrier.phi_dst, - vec![ - (loop_plan.preheader_bb, carrier.init_value), - (loop_plan.step_bb, carrier.step_value), - ], - "lowerer/loop_phi", - )?; - } - - if debug { - trace_logger.debug("lowerer/loop", "PHI inserted at header_bb"); - } - - // Step 7: Emit edge CFG (terminators) - use crate::mir::builder::emission::loop_scan_with_init::emit_scan_with_init_edgecfg; - - emit_scan_with_init_edgecfg( - builder, - loop_plan.header_bb, - loop_plan.body_bb, - loop_plan.step_bb, - loop_plan.after_bb, - loop_plan.found_bb, - loop_plan.cond_loop, - loop_plan.cond_match, - loop_plan.carriers.first().map(|c| c.phi_dst).unwrap_or(ValueId(0)), - )?; - - if debug { - trace_logger.debug("lowerer/loop", "Edge CFG emitted"); - } - - // Step 8: Update variable_map for carriers - for carrier in &loop_plan.carriers { - builder - .variable_ctx - .variable_map - .insert(carrier.name.clone(), carrier.phi_dst); - } - - // Step 9: Setup after_bb for subsequent AST lowering - builder.start_new_block(loop_plan.after_bb)?; - - // Step 10: Return Void (pattern applied successfully) - use crate::mir::builder::emission::constant::emit_void; - let void_val = emit_void(builder); - - if debug { - trace_logger.debug( - "lowerer/loop", - &format!("Loop complete, returning Void {:?}", void_val), - ); - } - - Ok(Some(void_val)) - } + // Phase 273 P3: lower_loop_legacy() has been REMOVED + // All patterns must use generalized fields (block_effects/phis/frag/final_values) + // Pattern-specific emission functions (emit_scan_with_init_edgecfg) are no longer used /// Emit a single CoreEffectPlan as MirInstruction fn emit_effect(builder: &mut MirBuilder, effect: &CoreEffectPlan) -> Result<(), String> { diff --git a/src/mir/builder/control_flow/plan/mod.rs b/src/mir/builder/control_flow/plan/mod.rs index 11c2f781..c3a34a89 100644 --- a/src/mir/builder/control_flow/plan/mod.rs +++ b/src/mir/builder/control_flow/plan/mod.rs @@ -137,7 +137,10 @@ pub(in crate::mir::builder) struct CorePhiInfo { pub tag: String, } -/// Phase 273 P1: Loop plan with carriers +/// Phase 273 P3: Loop plan with generalized fields (SSOT) +/// +/// All fields are now REQUIRED (Option removed for structural SSOT). +/// Legacy fields (header_effects, step_effects, carriers) have been removed. #[derive(Debug, Clone)] pub(in crate::mir::builder) struct CoreLoopPlan { // === Block IDs (pre-allocated by Normalizer) === @@ -157,24 +160,15 @@ pub(in crate::mir::builder) struct CoreLoopPlan { /// After block (loop exit) pub after_bb: BasicBlockId, - /// Found block (early exit on match) + /// Found block (early exit on match, or same as after_bb for patterns without early exit) pub found_bb: BasicBlockId, - // === Effects per block (emitted by Lowerer) === - - /// Header effects (emitted in header_bb before branch) - pub header_effects: Vec, + // === Body (for lowerer body emission) === /// Body plans (emitted in body_bb, can contain If/Exit) pub body: Vec, - /// Step effects (emitted in step_bb before back-edge) - pub step_effects: Vec, - - // === Loop control === - - /// Loop carriers (PHI variables) - pub carriers: Vec, + // === Loop control (ValueId references for Frag) === /// Loop condition (for header→body/after branch) pub cond_loop: ValueId, @@ -182,23 +176,20 @@ pub(in crate::mir::builder) struct CoreLoopPlan { /// Match condition (for body→found/step branch) pub cond_match: ValueId, - /// Loop variable name (for variable_map update after loop) - pub loop_var_name: String, - - // === Phase 273 P2: Generalized fields (for Pattern7+ support) === + // === Phase 273 P3: Generalized fields (REQUIRED - SSOT) === /// Block-level effects (generalized for multiple blocks) - /// Order: SSOT - preheader, header, body, step - pub block_effects: Option)>>, + /// Order: SSOT - preheader, header, body, then, else, step (pattern dependent) + pub block_effects: Vec<(BasicBlockId, Vec)>, /// PHI information (generalized for multiple blocks) - pub phis: Option>, + pub phis: Vec, /// Edge CFG fragment (generalized terminator structure) - pub frag: Option, + pub frag: Frag, /// Final values for variable_map update (after loop exit) - pub final_values: Option>, + pub final_values: Vec<(String, ValueId)>, } /// Phase 273 P1: Loop carrier (PHI variable) diff --git a/src/mir/builder/control_flow/plan/normalizer.rs b/src/mir/builder/control_flow/plan/normalizer.rs index 0cad79bc..08e27edd 100644 --- a/src/mir/builder/control_flow/plan/normalizer.rs +++ b/src/mir/builder/control_flow/plan/normalizer.rs @@ -336,7 +336,7 @@ impl PlanNormalizer { // Step 11: Build final_values (Phase 273 P2) let final_values = vec![(parts.loop_var.clone(), i_current)]; - // Step 12: Build CoreLoopPlan + // Step 12: Build CoreLoopPlan (Phase 273 P3: all generalized fields REQUIRED) let loop_plan = CoreLoopPlan { preheader_bb, header_bb, @@ -344,23 +344,14 @@ impl PlanNormalizer { step_bb, after_bb, found_bb, - header_effects, - body, - step_effects, - carriers: vec![CoreCarrierInfo { - name: parts.loop_var.clone(), - init_value: i_init_val, - step_value: i_next_val, - phi_dst: i_current, - }], + body, // Keep body for lowerer body emission cond_loop, cond_match, - loop_var_name: parts.loop_var, - // Phase 273 P2: Generalized fields populated - block_effects: Some(block_effects), - phis: Some(phis), - frag: Some(frag), - final_values: Some(final_values), + // Phase 273 P3: Generalized fields (REQUIRED - SSOT) + block_effects, + phis, + frag, + final_values, }; if debug { @@ -765,18 +756,14 @@ impl PlanNormalizer { step_bb, after_bb, found_bb: after_bb, // No early exit for split pattern - header_effects, body, - step_effects: vec![], // No step_effects (done in then/else) - carriers: vec![], // Legacy field (not used with generalized) cond_loop, cond_match, - loop_var_name: parts.i_var, - // Phase 273 P2: Generalized fields populated - block_effects: Some(block_effects), - phis: Some(phis), - frag: Some(frag), - final_values: Some(final_values), + // Phase 273 P3: Generalized fields (REQUIRED - SSOT) + block_effects, + phis, + frag, + final_values, }; if debug { diff --git a/src/mir/builder/control_flow/plan/verifier.rs b/src/mir/builder/control_flow/plan/verifier.rs index ee81aa05..e8f958a0 100644 --- a/src/mir/builder/control_flow/plan/verifier.rs +++ b/src/mir/builder/control_flow/plan/verifier.rs @@ -57,23 +57,50 @@ impl PlanVerifier { Ok(()) } - /// V1: Carrier completeness, V2: Condition validity + /// Phase 273 P3: Verify loop with generalized fields + /// + /// Invariants: + /// - V2: Condition validity (cond_loop, cond_match) + /// - V7: PHI non-empty (at least one carrier) + /// - V8: Frag entry matches header_bb + /// - V9: block_effects contains header_bb fn verify_loop(loop_plan: &CoreLoopPlan, depth: usize) -> Result<(), String> { - // V1: Carrier completeness - for (i, carrier) in loop_plan.carriers.iter().enumerate() { - Self::verify_carrier(carrier, depth, i)?; - } - // V2: Condition validity (basic check - ValueId should be non-zero for safety) - // Note: Full ValueId validity check would require builder context Self::verify_value_id_basic(loop_plan.cond_loop, depth, "cond_loop")?; Self::verify_value_id_basic(loop_plan.cond_match, depth, "cond_match")?; - // Verify header_effects - for (i, effect) in loop_plan.header_effects.iter().enumerate() { - Self::verify_effect(effect, depth).map_err(|e| { - format!("[Loop.header_effects[{}]] {}", i, e) - })?; + // V7: PHI non-empty (loops must have at least one carrier) + if loop_plan.phis.is_empty() { + return Err(format!( + "[V7] Loop at depth {} has no PHI nodes (loops require at least one carrier)", + depth + )); + } + + // V8: Frag entry matches header_bb (loop entry SSOT) + if loop_plan.frag.entry != loop_plan.header_bb { + return Err(format!( + "[V8] Loop at depth {} has frag.entry {:?} != header_bb {:?}", + depth, loop_plan.frag.entry, loop_plan.header_bb + )); + } + + // V9: block_effects contains header_bb + let has_header = loop_plan.block_effects.iter().any(|(bb, _)| *bb == loop_plan.header_bb); + if !has_header { + return Err(format!( + "[V9] Loop at depth {} block_effects missing header_bb {:?}", + depth, loop_plan.header_bb + )); + } + + // Verify block_effects + for (i, (bb, effects)) in loop_plan.block_effects.iter().enumerate() { + for (j, effect) in effects.iter().enumerate() { + Self::verify_effect(effect, depth).map_err(|e| { + format!("[Loop.block_effects[{}={:?}][{}]] {}", i, bb, j, e) + })?; + } } // Verify body plans (now in_loop = true) @@ -83,11 +110,23 @@ impl PlanVerifier { })?; } - // Verify step_effects - for (i, effect) in loop_plan.step_effects.iter().enumerate() { - Self::verify_effect(effect, depth).map_err(|e| { - format!("[Loop.step_effects[{}]] {}", i, e) - })?; + // Verify PHIs + for (i, phi) in loop_plan.phis.iter().enumerate() { + Self::verify_value_id_basic(phi.dst, depth, &format!("phi[{}].dst", i))?; + for (j, (_, val)) in phi.inputs.iter().enumerate() { + Self::verify_value_id_basic(*val, depth, &format!("phi[{}].inputs[{}]", i, j))?; + } + } + + // Verify final_values + for (i, (name, val)) in loop_plan.final_values.iter().enumerate() { + if name.is_empty() { + return Err(format!( + "[V6] final_values[{}] at depth {} has empty name", + i, depth + )); + } + Self::verify_value_id_basic(*val, depth, &format!("final_values[{}]", i))?; } Ok(())