diff --git a/src/mir/builder/control_flow/plan/facts/loop_facts.rs b/src/mir/builder/control_flow/plan/facts/loop_facts.rs index b71541ee..32c8bbed 100644 --- a/src/mir/builder/control_flow/plan/facts/loop_facts.rs +++ b/src/mir/builder/control_flow/plan/facts/loop_facts.rs @@ -36,11 +36,13 @@ use super::pattern2_break_facts::{Pattern2BreakFacts, try_extract_pattern2_break use super::pattern2_loopbodylocal_facts::{ Pattern2LoopBodyLocalFacts, try_extract_pattern2_loopbodylocal_facts, }; +use super::skeleton_facts::{SkeletonFacts, try_extract_loop_skeleton_facts}; #[derive(Debug, Clone)] pub(in crate::mir::builder) struct LoopFacts { pub condition_shape: ConditionShape, pub step_shape: StepShape, + pub skeleton: Option, pub scan_with_init: Option, pub split_scan: Option, pub pattern1_simplewhile: Option, @@ -128,23 +130,26 @@ fn try_build_loop_facts_inner( let pattern2_break = try_extract_pattern2_break_facts(condition, body)?; let pattern2_loopbodylocal = try_extract_pattern2_loopbodylocal_facts(condition, body)?; - if scan_with_init.is_none() - && split_scan.is_none() - && pattern1_simplewhile.is_none() - && pattern3_ifphi.is_none() - && pattern4_continue.is_none() - && pattern5_infinite_early_exit.is_none() - && pattern8_bool_predicate_scan.is_none() - && pattern9_accum_const_loop.is_none() - && pattern2_break.is_none() - && pattern2_loopbodylocal.is_none() - { + let has_any = scan_with_init.is_some() + || split_scan.is_some() + || pattern1_simplewhile.is_some() + || pattern3_ifphi.is_some() + || pattern4_continue.is_some() + || pattern5_infinite_early_exit.is_some() + || pattern8_bool_predicate_scan.is_some() + || pattern9_accum_const_loop.is_some() + || pattern2_break.is_some() + || pattern2_loopbodylocal.is_some(); + if !has_any { return Ok(None); } + let skeleton = try_extract_loop_skeleton_facts(condition, body)?; + Ok(Some(LoopFacts { condition_shape, step_shape, + skeleton, scan_with_init, split_scan, pattern1_simplewhile, diff --git a/src/mir/builder/control_flow/plan/facts/mod.rs b/src/mir/builder/control_flow/plan/facts/mod.rs index f64b5e9d..948920ff 100644 --- a/src/mir/builder/control_flow/plan/facts/mod.rs +++ b/src/mir/builder/control_flow/plan/facts/mod.rs @@ -16,6 +16,7 @@ pub(in crate::mir::builder) mod pattern9_accum_const_loop_facts; pub(in crate::mir::builder) mod pattern2_break_facts; pub(in crate::mir::builder) mod pattern2_loopbodylocal_facts; pub(in crate::mir::builder) mod scan_shapes; +pub(in crate::mir::builder) mod skeleton_facts; pub(in crate::mir::builder) use loop_facts::{ try_build_loop_facts, try_build_loop_facts_with_ctx, LoopFacts, diff --git a/src/mir/builder/control_flow/plan/facts/skeleton_facts.rs b/src/mir/builder/control_flow/plan/facts/skeleton_facts.rs new file mode 100644 index 00000000..ec0c1050 --- /dev/null +++ b/src/mir/builder/control_flow/plan/facts/skeleton_facts.rs @@ -0,0 +1,82 @@ +//! Phase 29an P0: SkeletonFacts SSOT (Loop/If/BranchN/StraightLine) + +use crate::ast::ASTNode; +use crate::mir::builder::control_flow::plan::planner::Freeze; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(in crate::mir::builder) enum SkeletonKind { + Loop, + If2, + BranchN, + StraightLine, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(in crate::mir::builder) struct SkeletonFacts { + pub kind: SkeletonKind, +} + +pub(in crate::mir::builder) fn try_extract_skeleton_facts_from_stmt( + stmt: &ASTNode, +) -> Result, Freeze> { + let kind = match stmt { + ASTNode::Loop { .. } => SkeletonKind::Loop, + ASTNode::If { + else_body: Some(_), + .. + } => SkeletonKind::If2, + ASTNode::MatchExpr { .. } => SkeletonKind::BranchN, + _ => return Ok(None), + }; + + Ok(Some(SkeletonFacts { kind })) +} + +pub(in crate::mir::builder) fn try_extract_loop_skeleton_facts( + condition: &ASTNode, + body: &[ASTNode], +) -> Result, Freeze> { + let _ = (condition, body); + Ok(Some(SkeletonFacts { + kind: SkeletonKind::Loop, + })) +} + +#[cfg(test)] +mod tests { + use super::{try_extract_skeleton_facts_from_stmt, SkeletonKind}; + use crate::ast::{ASTNode, LiteralValue, Span}; + + #[test] + fn skeleton_facts_loop_is_detected() { + let loop_node = ASTNode::Loop { + condition: Box::new(ASTNode::Literal { + value: LiteralValue::Bool(true), + span: Span::unknown(), + }), + body: vec![], + span: Span::unknown(), + }; + let facts = try_extract_skeleton_facts_from_stmt(&loop_node) + .expect("Ok") + .expect("Some"); + assert_eq!(facts.kind, SkeletonKind::Loop); + } + + #[test] + fn skeleton_facts_straight_line_is_none() { + let assign = ASTNode::Assignment { + target: Box::new(ASTNode::Variable { + name: "x".to_string(), + span: Span::unknown(), + }), + value: Box::new(ASTNode::Literal { + value: LiteralValue::Integer(1), + span: Span::unknown(), + }), + span: Span::unknown(), + }; + let facts = try_extract_skeleton_facts_from_stmt(&assign).expect("Ok"); + assert!(facts.is_none()); + } +} diff --git a/src/mir/builder/control_flow/plan/planner/build.rs b/src/mir/builder/control_flow/plan/planner/build.rs index 6d9a63ac..99ce75d5 100644 --- a/src/mir/builder/control_flow/plan/planner/build.rs +++ b/src/mir/builder/control_flow/plan/planner/build.rs @@ -248,6 +248,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: Some(SplitScanFacts { s_var: "s".to_string(), @@ -285,6 +286,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: None, pattern1_simplewhile: None, @@ -306,6 +308,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: Some(ScanWithInitFacts { loop_var: "i".to_string(), haystack: "s".to_string(), @@ -350,6 +353,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: None, pattern1_simplewhile: Some(Pattern1SimpleWhileFacts { @@ -412,6 +416,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: None, pattern1_simplewhile: None, @@ -473,6 +478,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: None, pattern1_simplewhile: None, @@ -520,6 +526,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: None, pattern1_simplewhile: None, @@ -568,6 +575,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: None, pattern1_simplewhile: None, @@ -624,6 +632,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: None, pattern1_simplewhile: None, @@ -686,6 +695,7 @@ mod tests { let facts = LoopFacts { condition_shape: ConditionShape::Unknown, step_shape: StepShape::Unknown, + skeleton: None, scan_with_init: None, split_scan: None, pattern1_simplewhile: None,