phase29aj(p2): planner-first pattern1 simplewhile subset
This commit is contained in:
@ -13,6 +13,9 @@ use super::scan_shapes::{ConditionShape, StepShape};
|
||||
use crate::mir::builder::control_flow::plan::planner::Freeze;
|
||||
use crate::ast::{BinaryOperator, LiteralValue};
|
||||
use super::scan_shapes::LengthMethod;
|
||||
use super::pattern1_simplewhile_facts::{
|
||||
Pattern1SimpleWhileFacts, try_extract_pattern1_simplewhile_facts,
|
||||
};
|
||||
use super::pattern2_break_facts::{Pattern2BreakFacts, try_extract_pattern2_break_facts};
|
||||
use super::pattern2_loopbodylocal_facts::{
|
||||
Pattern2LoopBodyLocalFacts, try_extract_pattern2_loopbodylocal_facts,
|
||||
@ -24,6 +27,7 @@ pub(in crate::mir::builder) struct LoopFacts {
|
||||
pub step_shape: StepShape,
|
||||
pub scan_with_init: Option<ScanWithInitFacts>,
|
||||
pub split_scan: Option<SplitScanFacts>,
|
||||
pub pattern1_simplewhile: Option<Pattern1SimpleWhileFacts>,
|
||||
pub pattern2_break: Option<Pattern2BreakFacts>,
|
||||
pub pattern2_loopbodylocal: Option<Pattern2LoopBodyLocalFacts>,
|
||||
}
|
||||
@ -57,11 +61,13 @@ pub(in crate::mir::builder) fn try_build_loop_facts(
|
||||
let step_shape = try_extract_step_shape(body)?.unwrap_or(StepShape::Unknown);
|
||||
let scan_with_init = try_extract_scan_with_init_facts(body, &condition_shape, &step_shape)?;
|
||||
let split_scan = try_extract_split_scan_facts(condition, body)?;
|
||||
let pattern1_simplewhile = try_extract_pattern1_simplewhile_facts(condition, body)?;
|
||||
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()
|
||||
&& pattern2_break.is_none()
|
||||
&& pattern2_loopbodylocal.is_none()
|
||||
{
|
||||
@ -73,6 +79,7 @@ pub(in crate::mir::builder) fn try_build_loop_facts(
|
||||
step_shape,
|
||||
scan_with_init,
|
||||
split_scan,
|
||||
pattern1_simplewhile,
|
||||
pattern2_break,
|
||||
pattern2_loopbodylocal,
|
||||
}))
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub(in crate::mir::builder) mod loop_facts;
|
||||
pub(in crate::mir::builder) mod pattern1_simplewhile_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;
|
||||
|
||||
@ -0,0 +1,99 @@
|
||||
//! Phase 29aj P2: Pattern1SimpleWhileFacts (Facts SSOT)
|
||||
|
||||
use crate::ast::{ASTNode, BinaryOperator, LiteralValue};
|
||||
use crate::mir::builder::control_flow::plan::planner::Freeze;
|
||||
use crate::mir::builder::control_flow::plan::extractors::common_helpers::{
|
||||
extract_loop_increment_plan, has_break_statement, has_continue_statement, has_if_else_statement,
|
||||
has_return_statement,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct Pattern1SimpleWhileFacts {
|
||||
pub loop_var: String,
|
||||
pub condition: ASTNode,
|
||||
pub loop_increment: ASTNode,
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn try_extract_pattern1_simplewhile_facts(
|
||||
condition: &ASTNode,
|
||||
body: &[ASTNode],
|
||||
) -> Result<Option<Pattern1SimpleWhileFacts>, Freeze> {
|
||||
let Some(loop_var) = extract_loop_var_for_subset(condition) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if has_break_statement(body) || has_continue_statement(body) || has_return_statement(body) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if has_if_else_statement(body) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let loop_increment = match extract_loop_increment_plan(body, &loop_var) {
|
||||
Ok(Some(inc)) => inc,
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
if !is_increment_step_one(&loop_increment, &loop_var) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(Pattern1SimpleWhileFacts {
|
||||
loop_var,
|
||||
condition: condition.clone(),
|
||||
loop_increment,
|
||||
}))
|
||||
}
|
||||
|
||||
fn extract_loop_var_for_subset(condition: &ASTNode) -> Option<String> {
|
||||
let ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left,
|
||||
right,
|
||||
..
|
||||
} = condition
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let ASTNode::Variable { name, .. } = left.as_ref() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if !matches!(
|
||||
right.as_ref(),
|
||||
ASTNode::Literal {
|
||||
value: LiteralValue::Integer(_),
|
||||
..
|
||||
}
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(name.clone())
|
||||
}
|
||||
|
||||
fn is_increment_step_one(loop_increment: &ASTNode, loop_var: &str) -> bool {
|
||||
let ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left,
|
||||
right,
|
||||
..
|
||||
} = loop_increment
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if !matches!(left.as_ref(), ASTNode::Variable { name, .. } if name == loop_var) {
|
||||
return false;
|
||||
}
|
||||
|
||||
matches!(
|
||||
right.as_ref(),
|
||||
ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -10,8 +10,8 @@ use super::candidates::{CandidateSet, PlanCandidate};
|
||||
use super::outcome::build_plan_with_facts;
|
||||
use super::Freeze;
|
||||
use crate::mir::builder::control_flow::plan::{
|
||||
DomainPlan, Pattern2BreakPlan, Pattern2PromotionHint, ScanDirection, ScanWithInitPlan,
|
||||
SplitScanPlan,
|
||||
DomainPlan, Pattern1SimpleWhilePlan, Pattern2BreakPlan, Pattern2PromotionHint, ScanDirection,
|
||||
ScanWithInitPlan, SplitScanPlan,
|
||||
};
|
||||
|
||||
/// Phase 29ai P0: External-ish SSOT entrypoint (skeleton)
|
||||
@ -88,6 +88,17 @@ pub(in crate::mir::builder) fn build_plan_from_facts(
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(pattern1) = &facts.facts.pattern1_simplewhile {
|
||||
candidates.push(PlanCandidate {
|
||||
plan: DomainPlan::Pattern1SimpleWhile(Pattern1SimpleWhilePlan {
|
||||
loop_var: pattern1.loop_var.clone(),
|
||||
condition: pattern1.condition.clone(),
|
||||
loop_increment: pattern1.loop_increment.clone(),
|
||||
}),
|
||||
rule: "loop/pattern1_simplewhile",
|
||||
});
|
||||
}
|
||||
|
||||
candidates.finalize()
|
||||
}
|
||||
|
||||
@ -100,6 +111,9 @@ mod tests {
|
||||
use crate::mir::builder::control_flow::plan::facts::loop_facts::{
|
||||
LoopFacts, ScanWithInitFacts, SplitScanFacts,
|
||||
};
|
||||
use crate::mir::builder::control_flow::plan::facts::pattern1_simplewhile_facts::{
|
||||
Pattern1SimpleWhileFacts,
|
||||
};
|
||||
use crate::mir::builder::control_flow::plan::facts::pattern2_break_facts::Pattern2BreakFacts;
|
||||
use crate::mir::builder::control_flow::plan::facts::pattern2_loopbodylocal_facts::{
|
||||
LoopBodyLocalShape, Pattern2LoopBodyLocalFacts,
|
||||
@ -135,6 +149,7 @@ mod tests {
|
||||
i_var: "i".to_string(),
|
||||
start_var: "start".to_string(),
|
||||
}),
|
||||
pattern1_simplewhile: None,
|
||||
pattern2_break: None,
|
||||
pattern2_loopbodylocal: None,
|
||||
};
|
||||
@ -160,6 +175,7 @@ mod tests {
|
||||
step_shape: StepShape::Unknown,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
pattern2_break: None,
|
||||
pattern2_loopbodylocal: None,
|
||||
};
|
||||
@ -180,6 +196,7 @@ mod tests {
|
||||
step_lit: 1,
|
||||
}),
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
pattern2_break: None,
|
||||
pattern2_loopbodylocal: None,
|
||||
};
|
||||
@ -193,6 +210,45 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn planner_builds_pattern1_simplewhile_plan_from_facts() {
|
||||
let loop_condition = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(lit_int(3)),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let loop_increment = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(lit_int(1)),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
let facts = LoopFacts {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: Some(Pattern1SimpleWhileFacts {
|
||||
loop_var: "i".to_string(),
|
||||
condition: loop_condition.clone(),
|
||||
loop_increment: loop_increment.clone(),
|
||||
}),
|
||||
pattern2_break: None,
|
||||
pattern2_loopbodylocal: None,
|
||||
};
|
||||
let canonical = canonicalize_loop_facts(facts);
|
||||
let plan = build_plan_from_facts(canonical).expect("Ok");
|
||||
|
||||
match plan {
|
||||
Some(DomainPlan::Pattern1SimpleWhile(plan)) => {
|
||||
assert_eq!(plan.loop_var, "i");
|
||||
}
|
||||
other => panic!("expected pattern1 simplewhile plan, got {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn planner_sets_promotion_hint_for_pattern2_loopbodylocal() {
|
||||
let loop_condition = ASTNode::BinaryOp {
|
||||
@ -228,6 +284,7 @@ mod tests {
|
||||
step_shape: StepShape::Unknown,
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
pattern2_break: Some(Pattern2BreakFacts {
|
||||
loop_var: "i".to_string(),
|
||||
carrier_var: "sum".to_string(),
|
||||
|
||||
@ -14,8 +14,6 @@ use super::Freeze;
|
||||
pub(in crate::mir::builder) struct PlanBuildOutcome {
|
||||
pub facts: Option<CanonicalLoopFacts>,
|
||||
pub plan: Option<DomainPlan>,
|
||||
#[allow(dead_code)]
|
||||
pub chosen_rule: Option<&'static str>,
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn build_plan_with_facts(
|
||||
@ -26,7 +24,6 @@ pub(in crate::mir::builder) fn build_plan_with_facts(
|
||||
return Ok(PlanBuildOutcome {
|
||||
facts: None,
|
||||
plan: None,
|
||||
chosen_rule: None,
|
||||
});
|
||||
};
|
||||
let canonical = canonicalize_loop_facts(facts);
|
||||
@ -35,6 +32,5 @@ pub(in crate::mir::builder) fn build_plan_with_facts(
|
||||
Ok(PlanBuildOutcome {
|
||||
facts: Some(canonical),
|
||||
plan,
|
||||
chosen_rule: None,
|
||||
})
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ pub(super) fn try_build_domain_plan(ctx: &LoopPatternContext) -> Result<Option<D
|
||||
},
|
||||
RuleEntry {
|
||||
name: "Pattern1_SimpleWhile (Phase 286 P2.1)",
|
||||
kind: RuleKind::Simple(extractors::pattern1::extract_pattern1_plan),
|
||||
kind: RuleKind::Pattern1,
|
||||
},
|
||||
];
|
||||
|
||||
@ -110,6 +110,12 @@ pub(super) fn try_build_domain_plan(ctx: &LoopPatternContext) -> Result<Option<D
|
||||
),
|
||||
}
|
||||
}
|
||||
RuleKind::Pattern1 => {
|
||||
match planner_opt.as_ref() {
|
||||
Some(DomainPlan::Pattern1SimpleWhile(_)) => (planner_opt.clone(), false),
|
||||
_ => (extractors::pattern1::extract_pattern1_plan(ctx.condition, ctx.body)?, true),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let promotion_tag = if matches!(entry.kind, RuleKind::Pattern2)
|
||||
@ -169,4 +175,5 @@ enum RuleKind {
|
||||
Pattern6,
|
||||
Pattern7,
|
||||
Pattern2,
|
||||
Pattern1,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user