feat(mir/llvm): Phase 273 P0-P1 DomainPlan→CorePlan + LLVM arg fix
Phase 273 P0-P1: Two-layer plan architecture - DomainPlan: Pattern-specific knowledge (ScanWithInit) - CorePlan: Fixed vocabulary (Seq, Loop, If, Effect, Exit) - ValueId references only (String expressions forbidden) - Pipeline: Extractor→Normalizer→Verifier→Lowerer New plan/ module: - mod.rs: Type definitions, SSOT spec - normalizer.rs: DomainPlan→CorePlan + ID allocation - verifier.rs: V1-V6 invariant checks (fail-fast) - lowerer.rs: CorePlan→MIR (pattern-agnostic) LLVM fix (ChatGPT): - function_lower.py: Fix argument reference bug - Phase 258 index_of_string now PASS on LLVM backend 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
250
src/mir/builder/control_flow/plan/lowerer.rs
Normal file
250
src/mir/builder/control_flow/plan/lowerer.rs
Normal file
@ -0,0 +1,250 @@
|
||||
//! 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(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user