Files
hakorune/src/mir/builder/control_flow/plan/lowerer.rs
tomoaki 0664526d99 feat(plan): Phase 273 P3 - Plan Lowering SSOT Finalize
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 <noreply@anthropic.com>
2025-12-23 00:01:58 +09:00

268 lines
9.2 KiB
Rust

//! Phase 273 P3: PlanLowerer - CorePlan → MIR 生成 (SSOT)
//!
//! # Responsibilities
//!
//! - Receive CorePlan from PlanNormalizer
//! - Emit MIR instructions using pre-allocated ValueIds
//! - No pattern-specific knowledge (pattern-agnostic)
//!
//! # Key Design Decision
//!
//! 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;
use crate::mir::builder::MirBuilder;
use crate::mir::{MirInstruction, ValueId};
/// Phase 273 P1: PlanLowerer - CorePlan → MIR 生成 (SSOT)
pub(in crate::mir::builder) struct PlanLowerer;
impl PlanLowerer {
/// CorePlan を受け取り、MIR を生成
///
/// # Arguments
///
/// * `builder` - MIR builder (mutable access for instruction emission)
/// * `plan` - CorePlan from Normalizer (pre-allocated ValueIds)
/// * `ctx` - Loop pattern context for debug/func_name
pub(in crate::mir::builder) fn lower(
builder: &mut MirBuilder,
plan: CorePlan,
ctx: &LoopPatternContext,
) -> Result<Option<ValueId>, String> {
match plan {
CorePlan::Seq(plans) => Self::lower_seq(builder, plans, ctx),
CorePlan::Loop(loop_plan) => Self::lower_loop(builder, loop_plan, ctx),
CorePlan::If(_if_plan) => {
// P1: If is handled inline in Loop body
Err("[lowerer] Standalone CorePlan::If not yet supported".to_string())
}
CorePlan::Effect(effect) => {
Self::emit_effect(builder, &effect)?;
Ok(None)
}
CorePlan::Exit(_exit) => {
// P1: Exit is handled by edge CFG in Loop
Err("[lowerer] Standalone CorePlan::Exit not yet supported".to_string())
}
}
}
/// Seq: process plans in order
fn lower_seq(
builder: &mut MirBuilder,
plans: Vec<CorePlan>,
ctx: &LoopPatternContext,
) -> Result<Option<ValueId>, String> {
let mut result = None;
for plan in plans {
result = Self::lower(builder, plan, ctx)?;
}
Ok(result)
}
/// Loop: emit blocks, effects, PHI, and edge CFG
///
/// This is pattern-agnostic. All pattern knowledge is in Normalizer.
/// Phase 273 P3: Generalized fields are now REQUIRED (Fail-Fast).
fn lower_loop(
builder: &mut MirBuilder,
loop_plan: CoreLoopPlan,
ctx: &LoopPatternContext,
) -> Result<Option<ValueId>, String> {
use crate::mir::builder::control_flow::joinir::trace;
let trace_logger = trace::trace();
let debug = ctx.debug;
if debug {
trace_logger.debug(
"lowerer/loop",
&format!(
"Phase 273 P3: Lowering CoreLoopPlan for {}",
ctx.func_name
),
);
}
// Phase 273 P3: Generalized fields are now struct fields (not Option)
// No validation needed - type system guarantees presence
if debug {
trace_logger.debug("lowerer/loop", "Processing generalized fields (SSOT)");
}
Self::lower_loop_generalized(builder, loop_plan, ctx)
}
/// Phase 273 P3: Generalized loop lowering (SSOT)
fn lower_loop_generalized(
builder: &mut MirBuilder,
loop_plan: CoreLoopPlan,
ctx: &LoopPatternContext,
) -> Result<Option<ValueId>, String> {
use crate::mir::builder::control_flow::joinir::trace;
use crate::mir::builder::control_flow::edgecfg::api::emit_frag;
let trace_logger = trace::trace();
let debug = ctx.debug;
// 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() {
builder.emit_instruction(MirInstruction::Jump {
target: frag.entry,
edge_args: None,
})?;
}
// Step 2: Emit block effects in SSOT order (preheader, header, body, step)
// Note: Body effects are handled separately via body CorePlan
for (block_id, effects) in block_effects {
builder.start_new_block(*block_id)?;
// Special handling for body block: emit body CorePlan instead of effects
if *block_id == loop_plan.body_bb {
for plan in &loop_plan.body {
match plan {
CorePlan::Effect(effect) => {
Self::emit_effect(builder, effect)?;
}
_ => {
return Err("[lowerer] Non-Effect plan in Loop body not yet supported".to_string());
}
}
}
} else {
// Normal block: emit effects
for effect in effects {
Self::emit_effect(builder, effect)?;
}
}
}
if debug {
trace_logger.debug(
"lowerer/loop_generalized",
&format!("Block effects emitted: {} blocks", block_effects.len()),
);
}
// Step 3: Ensure non-effect blocks exist (after_bb, found_bb, etc.)
builder.ensure_block_exists(loop_plan.after_bb)?;
builder.ensure_block_exists(loop_plan.found_bb)?;
// Step 4: Insert PHIs
use crate::mir::builder::emission::phi::insert_loop_phi;
for phi in phis {
insert_loop_phi(
builder,
phi.block,
phi.dst,
phi.inputs.clone(),
&phi.tag,
)?;
}
if debug {
trace_logger.debug(
"lowerer/loop_generalized",
&format!("PHI inserted: {} PHIs", phis.len()),
);
}
// Step 5: Emit Frag (terminators)
if let Some(ref mut func) = builder.scope_ctx.current_function {
emit_frag(func, frag)?;
} else {
return Err("[lowerer] current_function is None".to_string());
}
if debug {
trace_logger.debug("lowerer/loop_generalized", "Frag emitted");
}
// Step 6: Update variable_map for final values
for (name, value_id) in final_values {
builder
.variable_ctx
.variable_map
.insert(name.clone(), *value_id);
}
// Step 7: Setup after_bb for subsequent AST lowering
builder.start_new_block(loop_plan.after_bb)?;
// Step 8: 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_generalized",
&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> {
match effect {
CoreEffectPlan::Const { dst, value } => {
builder.emit_instruction(MirInstruction::Const {
dst: *dst,
value: value.clone(),
})?;
}
CoreEffectPlan::MethodCall { dst, object, method, args, effects } => {
// P2: dst and effects are now specified by Normalizer
builder.emit_instruction(MirInstruction::BoxCall {
dst: *dst,
box_val: *object,
method: method.clone(),
method_id: None,
args: args.clone(),
effects: *effects,
})?;
}
CoreEffectPlan::BinOp { dst, lhs, op, rhs } => {
builder.emit_instruction(MirInstruction::BinOp {
dst: *dst,
lhs: *lhs,
op: *op,
rhs: *rhs,
})?;
}
CoreEffectPlan::Compare { dst, lhs, op, rhs } => {
builder.emit_instruction(MirInstruction::Compare {
dst: *dst,
lhs: *lhs,
op: *op,
rhs: *rhs,
})?;
}
}
Ok(())
}
}