phase29an(p1): add loop feature facts ssot (exit usage)
This commit is contained in:
119
src/mir/builder/control_flow/plan/facts/feature_facts.rs
Normal file
119
src/mir/builder/control_flow/plan/facts/feature_facts.rs
Normal file
@ -0,0 +1,119 @@
|
||||
//! Phase 29an P1: FeatureFacts SSOT (ExitUsage placeholders)
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::builder::control_flow::plan::planner::Freeze;
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub(in crate::mir::builder) struct ExitUsageFacts {
|
||||
pub has_break: bool,
|
||||
pub has_continue: bool,
|
||||
pub has_return: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub(in crate::mir::builder) struct LoopFeatureFacts {
|
||||
pub exit_usage: ExitUsageFacts,
|
||||
pub value_join: Option<ValueJoinFacts>,
|
||||
pub cleanup: Option<CleanupFacts>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(in crate::mir::builder) struct ValueJoinFacts;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(in crate::mir::builder) struct CleanupFacts;
|
||||
|
||||
pub(in crate::mir::builder) fn try_extract_loop_feature_facts(
|
||||
body: &[ASTNode],
|
||||
) -> Result<LoopFeatureFacts, Freeze> {
|
||||
let mut exit_usage = ExitUsageFacts::default();
|
||||
for stmt in body {
|
||||
update_exit_usage_from_stmt(stmt, &mut exit_usage);
|
||||
}
|
||||
Ok(LoopFeatureFacts {
|
||||
exit_usage,
|
||||
value_join: None,
|
||||
cleanup: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn update_exit_usage_from_stmt(stmt: &ASTNode, usage: &mut ExitUsageFacts) {
|
||||
match stmt {
|
||||
ASTNode::Break { .. } => usage.has_break = true,
|
||||
ASTNode::Continue { .. } => usage.has_continue = true,
|
||||
ASTNode::Return { .. } => usage.has_return = true,
|
||||
ASTNode::If {
|
||||
then_body,
|
||||
else_body,
|
||||
..
|
||||
} => {
|
||||
for nested in then_body {
|
||||
update_exit_usage_from_stmt(nested, usage);
|
||||
}
|
||||
if let Some(else_body) = else_body {
|
||||
for nested in else_body {
|
||||
update_exit_usage_from_stmt(nested, usage);
|
||||
}
|
||||
}
|
||||
}
|
||||
ASTNode::Loop { .. }
|
||||
| ASTNode::While { .. }
|
||||
| ASTNode::ForRange { .. } => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{try_extract_loop_feature_facts, ExitUsageFacts};
|
||||
use crate::ast::{ASTNode, LiteralValue, Span};
|
||||
|
||||
fn lit_bool(value: bool) -> ASTNode {
|
||||
ASTNode::Literal {
|
||||
value: LiteralValue::Bool(value),
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exit_usage_tracks_break_continue_return_in_if() {
|
||||
let body = vec![
|
||||
ASTNode::If {
|
||||
condition: Box::new(lit_bool(true)),
|
||||
then_body: vec![ASTNode::Break {
|
||||
span: Span::unknown(),
|
||||
}],
|
||||
else_body: Some(vec![ASTNode::Continue {
|
||||
span: Span::unknown(),
|
||||
}]),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
ASTNode::Return {
|
||||
value: None,
|
||||
span: Span::unknown(),
|
||||
},
|
||||
];
|
||||
let facts = try_extract_loop_feature_facts(&body).expect("Ok");
|
||||
assert_eq!(
|
||||
facts.exit_usage,
|
||||
ExitUsageFacts {
|
||||
has_break: true,
|
||||
has_continue: true,
|
||||
has_return: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exit_usage_ignores_nested_loops() {
|
||||
let nested = ASTNode::Loop {
|
||||
condition: Box::new(lit_bool(true)),
|
||||
body: vec![ASTNode::Break {
|
||||
span: Span::unknown(),
|
||||
}],
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let facts = try_extract_loop_feature_facts(&[nested]).expect("Ok");
|
||||
assert_eq!(facts.exit_usage, ExitUsageFacts::default());
|
||||
}
|
||||
}
|
||||
@ -37,12 +37,14 @@ use super::pattern2_loopbodylocal_facts::{
|
||||
Pattern2LoopBodyLocalFacts, try_extract_pattern2_loopbodylocal_facts,
|
||||
};
|
||||
use super::skeleton_facts::{SkeletonFacts, try_extract_loop_skeleton_facts};
|
||||
use super::feature_facts::{LoopFeatureFacts, try_extract_loop_feature_facts};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct LoopFacts {
|
||||
pub condition_shape: ConditionShape,
|
||||
pub step_shape: StepShape,
|
||||
pub skeleton: Option<SkeletonFacts>,
|
||||
pub features: Option<LoopFeatureFacts>,
|
||||
pub scan_with_init: Option<ScanWithInitFacts>,
|
||||
pub split_scan: Option<SplitScanFacts>,
|
||||
pub pattern1_simplewhile: Option<Pattern1SimpleWhileFacts>,
|
||||
@ -145,11 +147,13 @@ fn try_build_loop_facts_inner(
|
||||
}
|
||||
|
||||
let skeleton = try_extract_loop_skeleton_facts(condition, body)?;
|
||||
let features = Some(try_extract_loop_feature_facts(body)?);
|
||||
|
||||
Ok(Some(LoopFacts {
|
||||
condition_shape,
|
||||
step_shape,
|
||||
skeleton,
|
||||
features,
|
||||
scan_with_init,
|
||||
split_scan,
|
||||
pattern1_simplewhile,
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub(in crate::mir::builder) mod loop_facts;
|
||||
pub(in crate::mir::builder) mod feature_facts;
|
||||
pub(in crate::mir::builder) mod pattern1_simplewhile_facts;
|
||||
pub(in crate::mir::builder) mod pattern3_ifphi_facts;
|
||||
pub(in crate::mir::builder) mod pattern4_continue_facts;
|
||||
|
||||
@ -249,6 +249,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: Some(SplitScanFacts {
|
||||
s_var: "s".to_string(),
|
||||
@ -287,6 +288,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
@ -309,6 +311,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: Some(ScanWithInitFacts {
|
||||
loop_var: "i".to_string(),
|
||||
haystack: "s".to_string(),
|
||||
@ -354,6 +357,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: Some(Pattern1SimpleWhileFacts {
|
||||
@ -417,6 +421,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
@ -479,6 +484,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
@ -527,6 +533,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
@ -576,6 +583,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
@ -633,6 +641,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
@ -696,6 +705,7 @@ mod tests {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: None,
|
||||
features: None,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
|
||||
Reference in New Issue
Block a user