phase29ai(p14): add pattern2 promotion hint
This commit is contained in:
@ -2,7 +2,12 @@
|
||||
|
||||
## Current Focus: Phase 29ai(Plan/Frag single-planner)
|
||||
|
||||
Next: `docs/development/current/main/phases/phase-29ai/P14-PLANNER-PATTERN2-LOOPBODYLOCAL-PROMOTION-SUBSET-INSTRUCTIONS.md`
|
||||
Next: Phase 29ai P15(TBD: promotion hint を JoinIR 側の orchestrator へ配線、挙動不変)
|
||||
|
||||
**2025-12-29: Phase 29ai P14 完了** ✅
|
||||
- 目的: Pattern2 LoopBodyLocal promotion の要求を Plan に載せる(仕様不変)
|
||||
- 実装: `src/mir/builder/control_flow/plan/mod.rs` / `src/mir/builder/control_flow/plan/planner/build.rs` / `src/mir/builder/control_flow/plan/extractors/pattern2_break.rs`
|
||||
- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` PASS
|
||||
|
||||
**2025-12-29: Phase 29ai P13 完了** ✅
|
||||
- 目的: single_planner の planner 呼び出しを 1 回に memoize して二重スキャンを解消(仕様不変)
|
||||
|
||||
@ -19,7 +19,7 @@ Related:
|
||||
|
||||
- **Phase 29ai(candidate): Plan/Frag single-planner(Facts SSOT)**
|
||||
- 入口: `docs/development/current/main/phases/phase-29ai/README.md`
|
||||
- Next: `docs/development/current/main/phases/phase-29ai/P14-PLANNER-PATTERN2-LOOPBODYLOCAL-PROMOTION-SUBSET-INSTRUCTIONS.md`
|
||||
- Next: Phase 29ai P15(TBD: promotion hint を JoinIR 側の orchestrator へ配線、挙動不変)
|
||||
|
||||
- **Phase 29ae P1(✅ COMPLETE): JoinIR Regression Pack (SSOT固定)**
|
||||
- 入口: `docs/development/current/main/phases/phase-29ae/README.md`
|
||||
|
||||
@ -87,7 +87,9 @@ Goal: pattern 名による分岐を外部APIから消し、Facts(事実)→
|
||||
## P14: Planner support(Pattern2 LoopBodyLocal promotion subset)
|
||||
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ai/P14-PLANNER-PATTERN2-LOOPBODYLOCAL-PROMOTION-SUBSET-INSTRUCTIONS.md`
|
||||
- ねらい: LoopBodyLocal promotion の要求を DomainPlan に載せ、promotion の “解析” を Facts として固定した上で段階的に plan 系へ寄せる(仕様不変)
|
||||
- ねらい: LoopBodyLocal promotion の “要求” を Pattern2BreakPlan に付加し、挙動不変のまま Plan にメタ情報を載せる
|
||||
- 完了: promotion hint を plan vocab に追加し、planner が facts から hint を付与(legacy は None)
|
||||
- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
|
||||
|
||||
## Verification (SSOT)
|
||||
|
||||
|
||||
@ -264,6 +264,7 @@ pub(crate) fn extract_pattern2_plan(
|
||||
carrier_update_in_break,
|
||||
carrier_update_in_body,
|
||||
loop_increment,
|
||||
promotion: None,
|
||||
})))
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
//! This prevents "second language processor" from growing inside Lowerer.
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::builder::control_flow::plan::facts::pattern2_loopbodylocal_facts::Pattern2LoopBodyLocalFacts;
|
||||
use crate::mir::{BasicBlockId, BinaryOp, CompareOp, ConstValue, EffectMask, ValueId};
|
||||
use crate::mir::builder::control_flow::edgecfg::api::Frag;
|
||||
|
||||
@ -279,6 +280,16 @@ pub(in crate::mir::builder) struct Pattern2BreakPlan {
|
||||
pub carrier_update_in_body: ASTNode,
|
||||
/// Loop increment expression AST (e.g., `i + 1`)
|
||||
pub loop_increment: ASTNode,
|
||||
/// Optional promotion hint for LoopBodyLocal handling (planner-only metadata)
|
||||
#[allow(dead_code)]
|
||||
pub promotion: Option<Pattern2PromotionHint>,
|
||||
}
|
||||
|
||||
/// Phase 29ai P14: Promotion hint metadata for Pattern2BreakPlan
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) enum Pattern2PromotionHint {
|
||||
LoopBodyLocal(Pattern2LoopBodyLocalFacts),
|
||||
}
|
||||
|
||||
/// Phase 286 P3.2: Exit kind for Pattern5 infinite loop
|
||||
|
||||
@ -10,7 +10,8 @@ use crate::mir::builder::control_flow::plan::normalize::{canonicalize_loop_facts
|
||||
use super::candidates::{CandidateSet, PlanCandidate};
|
||||
use super::Freeze;
|
||||
use crate::mir::builder::control_flow::plan::{
|
||||
DomainPlan, Pattern2BreakPlan, ScanDirection, ScanWithInitPlan, SplitScanPlan,
|
||||
DomainPlan, Pattern2BreakPlan, Pattern2PromotionHint, ScanDirection, ScanWithInitPlan,
|
||||
SplitScanPlan,
|
||||
};
|
||||
|
||||
/// Phase 29ai P0: External-ish SSOT entrypoint (skeleton)
|
||||
@ -71,6 +72,11 @@ pub(in crate::mir::builder) fn build_plan_from_facts(
|
||||
}
|
||||
|
||||
if let Some(pattern2) = &facts.facts.pattern2_break {
|
||||
let promotion = facts
|
||||
.facts
|
||||
.pattern2_loopbodylocal
|
||||
.as_ref()
|
||||
.map(|facts| Pattern2PromotionHint::LoopBodyLocal(facts.clone()));
|
||||
candidates.push(PlanCandidate {
|
||||
plan: DomainPlan::Pattern2Break(Pattern2BreakPlan {
|
||||
loop_var: pattern2.loop_var.clone(),
|
||||
@ -80,6 +86,7 @@ pub(in crate::mir::builder) fn build_plan_from_facts(
|
||||
carrier_update_in_break: pattern2.carrier_update_in_break.clone(),
|
||||
carrier_update_in_body: pattern2.carrier_update_in_body.clone(),
|
||||
loop_increment: pattern2.loop_increment.clone(),
|
||||
promotion,
|
||||
}),
|
||||
rule: "loop/pattern2_break",
|
||||
});
|
||||
@ -97,7 +104,27 @@ mod tests {
|
||||
use crate::mir::builder::control_flow::plan::facts::loop_facts::{
|
||||
LoopFacts, ScanWithInitFacts, SplitScanFacts,
|
||||
};
|
||||
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,
|
||||
};
|
||||
use crate::mir::builder::control_flow::plan::normalize::canonicalize_loop_facts;
|
||||
use crate::mir::builder::control_flow::plan::Pattern2PromotionHint;
|
||||
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
|
||||
|
||||
fn v(name: &str) -> ASTNode {
|
||||
ASTNode::Variable {
|
||||
name: name.to_string(),
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
|
||||
fn lit_int(value: i64) -> ASTNode {
|
||||
ASTNode::Literal {
|
||||
value: LiteralValue::Integer(value),
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn planner_builds_split_scan_plan_from_facts() {
|
||||
@ -169,4 +196,74 @@ mod tests {
|
||||
other => panic!("expected scan_with_init plan, got {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn planner_sets_promotion_hint_for_pattern2_loopbodylocal() {
|
||||
let loop_condition = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(lit_int(3)),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let break_condition = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Equal,
|
||||
left: Box::new(v("seg")),
|
||||
right: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::String(" ".to_string()),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let carrier_update = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left: Box::new(v("sum")),
|
||||
right: Box::new(lit_int(1)),
|
||||
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,
|
||||
pattern2_break: Some(Pattern2BreakFacts {
|
||||
loop_var: "i".to_string(),
|
||||
carrier_var: "sum".to_string(),
|
||||
loop_condition,
|
||||
break_condition,
|
||||
carrier_update_in_break: None,
|
||||
carrier_update_in_body: carrier_update,
|
||||
loop_increment,
|
||||
}),
|
||||
pattern2_loopbodylocal: Some(Pattern2LoopBodyLocalFacts {
|
||||
loop_var: "i".to_string(),
|
||||
loopbodylocal_var: "seg".to_string(),
|
||||
break_uses_loopbodylocal: true,
|
||||
shape: LoopBodyLocalShape::TrimSeg {
|
||||
s_var: "s".to_string(),
|
||||
i_var: "i".to_string(),
|
||||
},
|
||||
}),
|
||||
};
|
||||
let canonical = canonicalize_loop_facts(facts);
|
||||
let plan = build_plan_from_facts(canonical).expect("Ok");
|
||||
|
||||
match plan {
|
||||
Some(DomainPlan::Pattern2Break(plan)) => {
|
||||
let promotion = plan.promotion.expect("promotion hint");
|
||||
match promotion {
|
||||
Pattern2PromotionHint::LoopBodyLocal(facts) => {
|
||||
assert_eq!(facts.loopbodylocal_var, "seg");
|
||||
}
|
||||
}
|
||||
}
|
||||
other => panic!("expected pattern2 break plan, got {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user