phase29ao(p4): project exitmap presence into frag exits (unconnected)
This commit is contained in:
@ -70,7 +70,9 @@ mod tests {
|
||||
try_compose_domain_plan_from_canonical_facts,
|
||||
};
|
||||
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
|
||||
use crate::mir::builder::control_flow::plan::facts::feature_facts::LoopFeatureFacts;
|
||||
use crate::mir::builder::control_flow::plan::facts::feature_facts::{
|
||||
ExitKindFacts, ExitMapFacts, ExitUsageFacts, LoopFeatureFacts,
|
||||
};
|
||||
use crate::mir::builder::control_flow::plan::facts::loop_facts::LoopFacts;
|
||||
use crate::mir::builder::control_flow::plan::facts::pattern1_simplewhile_facts::Pattern1SimpleWhileFacts;
|
||||
use crate::mir::builder::control_flow::plan::facts::scan_shapes::{
|
||||
@ -82,9 +84,12 @@ mod tests {
|
||||
use crate::mir::builder::control_flow::plan::normalize::canonicalize_loop_facts;
|
||||
use crate::mir::builder::control_flow::plan::verifier::PlanVerifier;
|
||||
use crate::mir::builder::control_flow::plan::DomainPlan;
|
||||
use crate::mir::builder::control_flow::edgecfg::api::ExitKind;
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::control_form::LoopId;
|
||||
use crate::mir::MirType;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
fn v(name: &str) -> ASTNode {
|
||||
ASTNode::Variable {
|
||||
@ -336,7 +341,11 @@ mod tests {
|
||||
try_compose_core_plan_direct(&mut builder, &canonical, &ctx)
|
||||
.expect("Ok");
|
||||
let core = plan.expect("Some");
|
||||
assert!(matches!(core, super::CorePlan::Loop(_)));
|
||||
let loop_plan = match &core {
|
||||
super::CorePlan::Loop(loop_plan) => loop_plan,
|
||||
_ => panic!("expected CorePlan::Loop"),
|
||||
};
|
||||
assert!(loop_plan.frag.exits.is_empty());
|
||||
PlanVerifier::verify(&core).expect("verify");
|
||||
}
|
||||
|
||||
@ -375,4 +384,164 @@ mod tests {
|
||||
.expect("Ok");
|
||||
assert!(plan.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composer_direct_projects_return_exitmap_presence() {
|
||||
let pattern1 = Pattern1SimpleWhileFacts {
|
||||
loop_var: "i".to_string(),
|
||||
condition: ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(lit_int(3)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
loop_increment: ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(lit_int(1)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
};
|
||||
let mut kinds_present = BTreeSet::new();
|
||||
kinds_present.insert(ExitKindFacts::Return);
|
||||
let exit_usage = ExitUsageFacts {
|
||||
has_break: false,
|
||||
has_continue: false,
|
||||
has_return: true,
|
||||
};
|
||||
let facts = LoopFacts {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: SkeletonFacts {
|
||||
kind: SkeletonKind::Loop,
|
||||
},
|
||||
features: LoopFeatureFacts {
|
||||
exit_usage,
|
||||
exit_map: Some(ExitMapFacts { kinds_present }),
|
||||
..LoopFeatureFacts::default()
|
||||
},
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: Some(pattern1),
|
||||
pattern3_ifphi: None,
|
||||
pattern4_continue: None,
|
||||
pattern5_infinite_early_exit: None,
|
||||
pattern8_bool_predicate_scan: None,
|
||||
pattern9_accum_const_loop: None,
|
||||
pattern2_break: None,
|
||||
pattern2_loopbodylocal: None,
|
||||
};
|
||||
let canonical = canonicalize_loop_facts(facts);
|
||||
let condition = canonical
|
||||
.facts
|
||||
.pattern1_simplewhile
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.condition
|
||||
.clone();
|
||||
let ctx = LoopPatternContext::new(&condition, &[], "composer_test", false, false);
|
||||
let mut builder = MirBuilder::new();
|
||||
builder.enter_function_for_test("composer_test".to_string());
|
||||
let loop_var_init = builder.alloc_typed(MirType::Integer);
|
||||
builder
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.insert("i".to_string(), loop_var_init);
|
||||
let plan =
|
||||
try_compose_core_plan_direct(&mut builder, &canonical, &ctx)
|
||||
.expect("Ok")
|
||||
.expect("Some");
|
||||
let loop_plan = match plan {
|
||||
super::CorePlan::Loop(loop_plan) => loop_plan,
|
||||
_ => panic!("expected CorePlan::Loop"),
|
||||
};
|
||||
let exits = loop_plan.frag.exits.get(&ExitKind::Return).expect("Return exit");
|
||||
assert_eq!(exits.len(), 1);
|
||||
assert!(exits[0].target.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composer_direct_projects_break_continue_exitmap_presence() {
|
||||
let pattern1 = Pattern1SimpleWhileFacts {
|
||||
loop_var: "i".to_string(),
|
||||
condition: ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(lit_int(3)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
loop_increment: ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(lit_int(1)),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
};
|
||||
let mut kinds_present = BTreeSet::new();
|
||||
kinds_present.insert(ExitKindFacts::Break);
|
||||
kinds_present.insert(ExitKindFacts::Continue);
|
||||
let exit_usage = ExitUsageFacts {
|
||||
has_break: true,
|
||||
has_continue: true,
|
||||
has_return: false,
|
||||
};
|
||||
let facts = LoopFacts {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: SkeletonFacts {
|
||||
kind: SkeletonKind::Loop,
|
||||
},
|
||||
features: LoopFeatureFacts {
|
||||
exit_usage,
|
||||
exit_map: Some(ExitMapFacts { kinds_present }),
|
||||
..LoopFeatureFacts::default()
|
||||
},
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: Some(pattern1),
|
||||
pattern3_ifphi: None,
|
||||
pattern4_continue: None,
|
||||
pattern5_infinite_early_exit: None,
|
||||
pattern8_bool_predicate_scan: None,
|
||||
pattern9_accum_const_loop: None,
|
||||
pattern2_break: None,
|
||||
pattern2_loopbodylocal: None,
|
||||
};
|
||||
let canonical = canonicalize_loop_facts(facts);
|
||||
let condition = canonical
|
||||
.facts
|
||||
.pattern1_simplewhile
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.condition
|
||||
.clone();
|
||||
let ctx = LoopPatternContext::new(&condition, &[], "composer_test", false, false);
|
||||
let mut builder = MirBuilder::new();
|
||||
builder.enter_function_for_test("composer_test".to_string());
|
||||
let loop_var_init = builder.alloc_typed(MirType::Integer);
|
||||
builder
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.insert("i".to_string(), loop_var_init);
|
||||
let plan =
|
||||
try_compose_core_plan_direct(&mut builder, &canonical, &ctx)
|
||||
.expect("Ok")
|
||||
.expect("Some");
|
||||
let loop_plan = match plan {
|
||||
super::CorePlan::Loop(loop_plan) => loop_plan,
|
||||
_ => panic!("expected CorePlan::Loop"),
|
||||
};
|
||||
let break_kind = ExitKind::Break(LoopId(0));
|
||||
let continue_kind = ExitKind::Continue(LoopId(0));
|
||||
let break_exits = loop_plan.frag.exits.get(&break_kind).expect("Break exit");
|
||||
let continue_exits = loop_plan
|
||||
.frag
|
||||
.exits
|
||||
.get(&continue_kind)
|
||||
.expect("Continue exit");
|
||||
assert_eq!(break_exits.len(), 1);
|
||||
assert_eq!(continue_exits.len(), 1);
|
||||
assert!(break_exits[0].target.is_none());
|
||||
assert!(continue_exits[0].target.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
use super::helpers::{create_phi_bindings, LoopBlocksStandard5};
|
||||
use super::{CoreEffectPlan, CoreLoopPlan, CorePhiInfo, CorePlan};
|
||||
use crate::mir::basic_block::EdgeArgs;
|
||||
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
use crate::mir::builder::control_flow::plan::facts::feature_facts::ExitKindFacts;
|
||||
use crate::mir::builder::control_flow::plan::facts::skeleton_facts::SkeletonKind;
|
||||
use crate::mir::builder::control_flow::plan::normalize::CanonicalLoopFacts;
|
||||
use crate::mir::builder::control_flow::edgecfg::api::{BranchStub, EdgeStub, ExitKind, Frag};
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
|
||||
use crate::mir::control_form::LoopId;
|
||||
use crate::mir::MirType;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
impl super::PlanNormalizer {
|
||||
pub(in crate::mir::builder) fn normalize_loop_skeleton_from_facts(
|
||||
@ -117,7 +119,7 @@ impl super::PlanNormalizer {
|
||||
|
||||
let frag = Frag {
|
||||
entry: header_bb,
|
||||
exits: BTreeMap::new(),
|
||||
exits: build_exitmap_from_presence(&facts.exit_kinds_present, body_bb),
|
||||
wires,
|
||||
branches,
|
||||
};
|
||||
@ -143,3 +145,19 @@ impl super::PlanNormalizer {
|
||||
Ok(Some(CorePlan::Loop(loop_plan)))
|
||||
}
|
||||
}
|
||||
|
||||
fn build_exitmap_from_presence(
|
||||
present: &BTreeSet<ExitKindFacts>,
|
||||
from: BasicBlockId,
|
||||
) -> BTreeMap<ExitKind, Vec<EdgeStub>> {
|
||||
let mut exits = BTreeMap::new();
|
||||
for kind in present {
|
||||
let exit_kind = match kind {
|
||||
ExitKindFacts::Return => ExitKind::Return,
|
||||
ExitKindFacts::Break => ExitKind::Break(LoopId(0)),
|
||||
ExitKindFacts::Continue => ExitKind::Continue(LoopId(0)),
|
||||
};
|
||||
exits.insert(exit_kind, vec![EdgeStub::without_args(from, exit_kind)]);
|
||||
}
|
||||
exits
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user