phase29am(p1): flatten seq-of-effects in core loop body

This commit is contained in:
2025-12-29 16:54:22 +09:00
parent 3c76d8eabf
commit bee0c7f8e1

View File

@ -199,14 +199,7 @@ impl PlanLowerer {
// 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());
}
}
Self::emit_body_plan(builder, plan)?;
}
} else {
// Normal block: emit effects
@ -326,12 +319,26 @@ impl PlanLowerer {
}
Ok(())
}
fn emit_body_plan(builder: &mut MirBuilder, plan: &CorePlan) -> Result<(), String> {
match plan {
CorePlan::Effect(effect) => Self::emit_effect(builder, effect),
CorePlan::Seq(plans) => {
for nested in plans {
Self::emit_body_plan(builder, nested)?;
}
Ok(())
}
_ => Err("[lowerer] Non-Effect plan in Loop body not yet supported".to_string()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::{ASTNode, LiteralValue, Span};
use crate::mir::builder::control_flow::edgecfg::api::Frag;
use crate::mir::{ConstValue, MirInstruction};
fn make_ctx<'a>(condition: &'a ASTNode, body: &'a [ASTNode]) -> LoopPatternContext<'a> {
@ -412,4 +419,74 @@ mod tests {
"expected Branch terminator"
);
}
#[test]
fn test_lower_loop_body_seq_flattens() {
let mut builder = MirBuilder::new();
builder.enter_function_for_test("test_loop_body_seq".to_string());
let preheader_bb = builder.next_block_id();
let header_bb = builder.next_block_id();
let body_bb = builder.next_block_id();
let step_bb = builder.next_block_id();
let after_bb = builder.next_block_id();
let found_bb = builder.next_block_id();
let eff1 = CoreEffectPlan::Const {
dst: builder.alloc_value_for_test(),
value: ConstValue::Integer(1),
};
let eff2 = CoreEffectPlan::Const {
dst: builder.alloc_value_for_test(),
value: ConstValue::Integer(2),
};
let eff3 = CoreEffectPlan::Const {
dst: builder.alloc_value_for_test(),
value: ConstValue::Integer(3),
};
let loop_plan = CoreLoopPlan {
preheader_bb,
header_bb,
body_bb,
step_bb,
after_bb,
found_bb,
body: vec![CorePlan::Seq(vec![
CorePlan::Effect(eff1),
CorePlan::Seq(vec![CorePlan::Effect(eff2)]),
CorePlan::Effect(eff3),
])],
cond_loop: builder.alloc_value_for_test(),
cond_match: builder.alloc_value_for_test(),
block_effects: vec![
(preheader_bb, vec![]),
(header_bb, vec![]),
(body_bb, vec![]),
(step_bb, vec![]),
],
phis: vec![],
frag: Frag::new(header_bb),
final_values: vec![],
};
let cond = ASTNode::Literal {
value: LiteralValue::Bool(true),
span: Span::unknown(),
};
let body: Vec<ASTNode> = vec![];
let ctx = make_ctx(&cond, &body);
let result = PlanLowerer::lower(&mut builder, CorePlan::Loop(loop_plan), &ctx);
assert!(result.is_ok());
let func = builder.scope_ctx.current_function.as_ref().expect("function");
let block = func.get_block(body_bb).expect("body block");
let const_count = block
.instructions
.iter()
.filter(|inst| matches!(inst, MirInstruction::Const { .. }))
.count();
assert_eq!(const_count, 3, "expected 3 Const effects in body");
}
}