251 lines
8.2 KiB
Rust
251 lines
8.2 KiB
Rust
|
|
//! Phase 273 P1: 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.
|
||
|
|
|
||
|
|
use super::{CoreEffectPlan, CoreLoopPlan, CorePlan};
|
||
|
|
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||
|
|
use crate::mir::builder::MirBuilder;
|
||
|
|
use crate::mir::{Effect, EffectMask, 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.
|
||
|
|
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 P1: Lowering CoreLoopPlan for {}",
|
||
|
|
ctx.func_name
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 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))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 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 } => {
|
||
|
|
builder.emit_instruction(MirInstruction::BoxCall {
|
||
|
|
dst: Some(*dst),
|
||
|
|
box_val: *object,
|
||
|
|
method: method.clone(),
|
||
|
|
method_id: None,
|
||
|
|
args: args.clone(),
|
||
|
|
effects: EffectMask::PURE.add(Effect::Io),
|
||
|
|
})?;
|
||
|
|
}
|
||
|
|
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(())
|
||
|
|
}
|
||
|
|
}
|