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:
2025-12-22 22:42:56 +09:00
parent f07c2e7874
commit 960241795d
20 changed files with 1728 additions and 388 deletions

View 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(())
}
}