phase29am(p1): flatten seq-of-effects in core loop body
This commit is contained in:
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user