feat(plan): Phase 273 P2 Step 1-2 - CoreLoopPlan generalization
Generalize CoreLoopPlan for Pattern7+ support: New structures (mod.rs): - CorePhiInfo: PHI info with block, dst, inputs, tag - CoreLoopPlan new optional fields: - block_effects: Vec<(BasicBlockId, Vec<CoreEffectPlan>)> - phis: Vec<CorePhiInfo> - frag: Frag (EdgeCFG) - final_values: Vec<(String, ValueId)> Normalizer (normalizer.rs): - Pattern6 now populates all new fields - Frag construction matches emit_scan_with_init_edgecfg - SSOT ordering: preheader → header → body → step Lowerer (lowerer.rs): - lower_loop() dispatches to generalized or legacy path - lower_loop_generalized(): emit blocks → PHI → emit_frag() - lower_loop_legacy(): backward compatible fallback Test: phase258_p0_index_of_string_vm PASS (exit=6) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -66,6 +66,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.
|
||||
fn lower_loop(
|
||||
builder: &mut MirBuilder,
|
||||
loop_plan: CoreLoopPlan,
|
||||
@ -80,12 +81,159 @@ impl PlanLowerer {
|
||||
trace_logger.debug(
|
||||
"lowerer/loop",
|
||||
&format!(
|
||||
"Phase 273 P1: Lowering CoreLoopPlan for {}",
|
||||
"Phase 273 P2: 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();
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 273 P2: Generalized loop lowering
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
// 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 P2: Legacy loop lowering (fallback for old Normalizer)
|
||||
fn lower_loop_legacy(
|
||||
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;
|
||||
|
||||
// Step 1: Emit Jump from preheader (current block) to header
|
||||
if builder.current_block.is_some() {
|
||||
builder.emit_instruction(MirInstruction::Jump {
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::{BasicBlockId, BinaryOp, CompareOp, ConstValue, EffectMask, ValueId};
|
||||
use crate::mir::builder::control_flow::edgecfg::api::Frag;
|
||||
|
||||
pub(in crate::mir::builder) mod lowerer;
|
||||
pub(in crate::mir::builder) mod normalizer;
|
||||
@ -104,6 +105,19 @@ pub(in crate::mir::builder) enum CorePlan {
|
||||
Exit(CoreExitPlan),
|
||||
}
|
||||
|
||||
/// Phase 273 P2: PHI information for generalized CoreLoopPlan
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct CorePhiInfo {
|
||||
/// Block where PHI is located
|
||||
pub block: BasicBlockId,
|
||||
/// Destination ValueId for PHI
|
||||
pub dst: ValueId,
|
||||
/// PHI inputs: (predecessor_block, value)
|
||||
pub inputs: Vec<(BasicBlockId, ValueId)>,
|
||||
/// Tag for debugging (e.g., "loop_carrier_i")
|
||||
pub tag: String,
|
||||
}
|
||||
|
||||
/// Phase 273 P1: Loop plan with carriers
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct CoreLoopPlan {
|
||||
@ -151,6 +165,21 @@ pub(in crate::mir::builder) struct CoreLoopPlan {
|
||||
|
||||
/// Loop variable name (for variable_map update after loop)
|
||||
pub loop_var_name: String,
|
||||
|
||||
// === Phase 273 P2: Generalized fields (for Pattern7+ support) ===
|
||||
|
||||
/// Block-level effects (generalized for multiple blocks)
|
||||
/// Order: SSOT - preheader, header, body, step
|
||||
pub block_effects: Option<Vec<(BasicBlockId, Vec<CoreEffectPlan>)>>,
|
||||
|
||||
/// PHI information (generalized for multiple blocks)
|
||||
pub phis: Option<Vec<CorePhiInfo>>,
|
||||
|
||||
/// Edge CFG fragment (generalized terminator structure)
|
||||
pub frag: Option<Frag>,
|
||||
|
||||
/// Final values for variable_map update (after loop exit)
|
||||
pub final_values: Option<Vec<(String, ValueId)>>,
|
||||
}
|
||||
|
||||
/// Phase 273 P1: Loop carrier (PHI variable)
|
||||
|
||||
@ -12,11 +12,14 @@
|
||||
//! Lowerer processes CorePlan without any pattern knowledge.
|
||||
|
||||
use super::{
|
||||
CoreCarrierInfo, CoreEffectPlan, CoreLoopPlan, CorePlan, DomainPlan, ScanWithInitPlan,
|
||||
CoreCarrierInfo, CoreEffectPlan, CoreLoopPlan, CorePhiInfo, CorePlan, DomainPlan, ScanWithInitPlan,
|
||||
};
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::{BinaryOp, CompareOp, ConstValue, Effect, EffectMask, MirType};
|
||||
use crate::mir::builder::control_flow::edgecfg::api::{BranchStub, EdgeStub, ExitKind, Frag};
|
||||
use crate::mir::basic_block::EdgeArgs;
|
||||
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
|
||||
|
||||
/// Phase 273 P1: PlanNormalizer - DomainPlan → CorePlan 変換 (SSOT)
|
||||
pub(in crate::mir::builder) struct PlanNormalizer;
|
||||
@ -259,7 +262,79 @@ impl PlanNormalizer {
|
||||
},
|
||||
];
|
||||
|
||||
// Step 8: Build CoreLoopPlan
|
||||
// Step 8: Build block_effects (Phase 273 P2)
|
||||
// SSOT ordering: preheader (empty), header, body (already in body plan), step
|
||||
let block_effects = vec![
|
||||
(preheader_bb, vec![]), // No effects in preheader
|
||||
(header_bb, header_effects.clone()),
|
||||
(body_bb, vec![]), // Body effects are in body CorePlan
|
||||
(step_bb, step_effects.clone()),
|
||||
];
|
||||
|
||||
// Step 9: Build phis (Phase 273 P2)
|
||||
let phis = vec![CorePhiInfo {
|
||||
block: header_bb,
|
||||
dst: i_current,
|
||||
inputs: vec![
|
||||
(preheader_bb, i_init_val),
|
||||
(step_bb, i_next_val),
|
||||
],
|
||||
tag: format!("loop_carrier_{}", parts.loop_var),
|
||||
}];
|
||||
|
||||
// Step 10: Build Frag (Phase 273 P2)
|
||||
let empty_args = EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![],
|
||||
};
|
||||
|
||||
let ret_found_args = EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![i_current],
|
||||
};
|
||||
|
||||
let branches = vec![
|
||||
BranchStub {
|
||||
from: header_bb,
|
||||
cond: cond_loop,
|
||||
then_target: body_bb,
|
||||
then_args: empty_args.clone(),
|
||||
else_target: after_bb,
|
||||
else_args: empty_args.clone(),
|
||||
},
|
||||
BranchStub {
|
||||
from: body_bb,
|
||||
cond: cond_match,
|
||||
then_target: found_bb,
|
||||
then_args: empty_args.clone(),
|
||||
else_target: step_bb,
|
||||
else_args: empty_args.clone(),
|
||||
},
|
||||
];
|
||||
|
||||
let wires = vec![
|
||||
EdgeStub {
|
||||
from: step_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: Some(header_bb),
|
||||
args: empty_args,
|
||||
},
|
||||
EdgeStub {
|
||||
from: found_bb,
|
||||
kind: ExitKind::Return,
|
||||
target: None,
|
||||
args: ret_found_args,
|
||||
},
|
||||
];
|
||||
|
||||
let mut frag = Frag::new(header_bb);
|
||||
frag.branches = branches;
|
||||
frag.wires = wires;
|
||||
|
||||
// Step 11: Build final_values (Phase 273 P2)
|
||||
let final_values = vec![(parts.loop_var.clone(), i_current)];
|
||||
|
||||
// Step 12: Build CoreLoopPlan
|
||||
let loop_plan = CoreLoopPlan {
|
||||
preheader_bb,
|
||||
header_bb,
|
||||
@ -279,6 +354,11 @@ impl PlanNormalizer {
|
||||
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),
|
||||
};
|
||||
|
||||
if debug {
|
||||
|
||||
Reference in New Issue
Block a user