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:
2025-12-22 23:18:51 +09:00
parent ec792983cc
commit d16800741f
3 changed files with 260 additions and 3 deletions

View File

@ -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 {

View File

@ -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)

View File

@ -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 {