phase29ao(p3): direct coreloop skeleton from facts (pattern1 subset)
This commit is contained in:
@ -18,8 +18,8 @@ Scope: Repo root の旧リンク互換。現行の入口は `docs/development/cu
|
||||
**CorePlan migration 道筋 SSOT**
|
||||
`docs/development/current/main/design/coreplan-migration-roadmap-ssot.md` が移行タスクの Done 判定の入口。
|
||||
|
||||
**Next implementation (Phase 29ao P3)**
|
||||
`docs/development/current/main/phases/phase-29ao/P3-CORELOOP-SKELETON-COMPOSE-INSTRUCTIONS.md`
|
||||
**Next implementation (Phase 29ao P4)**
|
||||
`docs/development/current/main/phases/phase-29ao/README.md`
|
||||
|
||||
**2025-12-29: Phase 29am P0 COMPLETE (CorePlan If/Exit lowerer/verifier)**
|
||||
CorePlan の If/Exit を lowerer/verifier で扱えるようにして、CorePlan 移行の土台を作った。
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
## Current Focus: Phase 29ao(CorePlan composition)
|
||||
|
||||
Next: Phase 29ao P3(CoreLoop skeleton → CorePlan)
|
||||
Next: Phase 29ao P4(ExitMap presence → Frag/ExitMap)
|
||||
運用ルール: integration filter で phase143_* は回さない(JoinIR 回帰は phase29ae pack のみ)
|
||||
運用ルール: phase286_pattern9_* は legacy pack (SKIP) を使う
|
||||
移行道筋 SSOT: `docs/development/current/main/design/coreplan-migration-roadmap-ssot.md`
|
||||
@ -22,6 +22,11 @@ Next: Phase 29ao P3(CoreLoop skeleton → CorePlan)
|
||||
- 変更: `src/mir/builder/control_flow/plan/composer/mod.rs` / `docs/development/current/main/phases/phase-29ao/README.md` / `docs/development/current/main/10-Now.md` / `docs/development/current/main/30-Backlog.md` / `CURRENT_TASK.md`
|
||||
- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
|
||||
|
||||
**2025-12-30: Phase 29ao P3 完了** ✅
|
||||
- 目的: `CanonicalLoopFacts` から `CorePlan::Loop`(skeleton)を direct 生成(Pattern1 subset のみ)
|
||||
- 変更: `src/mir/builder/control_flow/plan/normalizer/skeleton_loop.rs` / `src/mir/builder/control_flow/plan/normalizer/mod.rs` / `src/mir/builder/control_flow/plan/composer/mod.rs` / `docs/development/current/main/phases/phase-29ao/README.md` / `docs/development/current/main/10-Now.md` / `docs/development/current/main/30-Backlog.md` / `CURRENT_TASK.md`
|
||||
- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh`
|
||||
|
||||
**2025-12-29: Phase 29an P15 完了** ✅
|
||||
- 目的: P0–P14 の成果を closeout 形式でまとめ、次フェーズ(Phase 29ao)入口を固定
|
||||
- 変更: `docs/development/current/main/phases/phase-29an/README.md` / `docs/development/current/main/10-Now.md` / `docs/development/current/main/30-Backlog.md` / `CURRENT_TASK.md`
|
||||
|
||||
@ -15,7 +15,7 @@ Related:
|
||||
|
||||
- **Phase 29ao(active): CorePlan composition from Skeleton/Feature**
|
||||
- 入口: `docs/development/current/main/phases/phase-29ao/README.md`
|
||||
- 状況: P0/P1/P2 ✅ 完了 / Next: P3
|
||||
- 状況: P0/P1/P2/P3 ✅ 完了 / Next: P4
|
||||
|
||||
- **Phase 29af(✅ COMPLETE): Boundary hygiene / regression entrypoint / carrier layout SSOT**
|
||||
- 入口: `docs/development/current/main/phases/phase-29af/README.md`
|
||||
|
||||
@ -33,10 +33,13 @@ Gate(SSOT):
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ao/P2-COREPLAN-COMPOSER-VIA-NORMALIZER-INSTRUCTIONS.md`
|
||||
- ねらい: `CanonicalLoopFacts → DomainPlan → PlanNormalizer → CorePlan` の橋渡しを未接続で固定
|
||||
|
||||
## P3: CoreLoop skeleton を CorePlan で直接生成(未接続・仕様不変)✅
|
||||
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ao/P3-CORELOOP-SKELETON-COMPOSE-INSTRUCTIONS.md`
|
||||
- ねらい: `CanonicalLoopFacts` から `CorePlan::Loop`(skeleton)を direct 生成(Pattern1 subset のみ)
|
||||
|
||||
## Next(planned)
|
||||
|
||||
- P3: CoreLoop skeleton を `CorePlan` 語彙で直接生成(DomainPlan 非依存・未接続)
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ao/P3-CORELOOP-SKELETON-COMPOSE-INSTRUCTIONS.md`
|
||||
- P4: ExitMap presence を `Frag/ExitMap` と結ぶ(break/continue/return を feature 合成へ寄せる)
|
||||
- P5: Cleanup presence を ExitKind 単位で wire(effect/cleanup SSOT に従う、観測差分なし)
|
||||
- P6: ValueJoin presence を post-phi SSOT に沿って wire(局所 verify から)
|
||||
|
||||
@ -41,6 +41,15 @@ pub(in crate::mir::builder) fn try_compose_core_plan_via_normalizer(
|
||||
Ok(Some(core))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(in crate::mir::builder) fn try_compose_core_plan_direct(
|
||||
builder: &mut MirBuilder,
|
||||
facts: &CanonicalLoopFacts,
|
||||
ctx: &LoopPatternContext,
|
||||
) -> Result<Option<CorePlan>, String> {
|
||||
PlanNormalizer::normalize_loop_skeleton_from_facts(builder, facts, ctx)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(in crate::mir::builder) fn try_compose_core_plan_from_canonical_facts(
|
||||
facts: &CanonicalLoopFacts,
|
||||
@ -55,6 +64,7 @@ pub(in crate::mir::builder) fn try_compose_core_plan_from_canonical_facts(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
try_compose_core_plan_direct,
|
||||
try_compose_core_plan_from_canonical_facts,
|
||||
try_compose_core_plan_via_normalizer,
|
||||
try_compose_domain_plan_from_canonical_facts,
|
||||
@ -70,6 +80,7 @@ mod tests {
|
||||
SkeletonFacts, SkeletonKind,
|
||||
};
|
||||
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::joinir::patterns::router::LoopPatternContext;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
@ -269,4 +280,99 @@ mod tests {
|
||||
.expect("Ok");
|
||||
assert!(plan.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composer_direct_builds_coreloop_for_pattern1() {
|
||||
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 facts = LoopFacts {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: SkeletonFacts {
|
||||
kind: SkeletonKind::Loop,
|
||||
},
|
||||
features: 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");
|
||||
let core = plan.expect("Some");
|
||||
assert!(matches!(core, super::CorePlan::Loop(_)));
|
||||
PlanVerifier::verify(&core).expect("verify");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composer_direct_returns_none_without_pattern1() {
|
||||
let facts = LoopFacts {
|
||||
condition_shape: ConditionShape::Unknown,
|
||||
step_shape: StepShape::Unknown,
|
||||
skeleton: SkeletonFacts {
|
||||
kind: SkeletonKind::Loop,
|
||||
},
|
||||
features: LoopFeatureFacts::default(),
|
||||
scan_with_init: None,
|
||||
split_scan: None,
|
||||
pattern1_simplewhile: None,
|
||||
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 = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(v("i")),
|
||||
right: Box::new(lit_int(3)),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let ctx = LoopPatternContext::new(&condition, &[], "composer_test", false, false);
|
||||
let mut builder = MirBuilder::new();
|
||||
builder.enter_function_for_test("composer_test".to_string());
|
||||
let plan =
|
||||
try_compose_core_plan_direct(&mut builder, &canonical, &ctx)
|
||||
.expect("Ok");
|
||||
assert!(plan.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ mod pattern8_bool_predicate_scan;
|
||||
mod pattern9_accum_const_loop;
|
||||
mod pattern_scan_with_init;
|
||||
mod pattern_split_scan;
|
||||
mod skeleton_loop;
|
||||
mod common;
|
||||
|
||||
use super::{
|
||||
|
||||
145
src/mir/builder/control_flow/plan/normalizer/skeleton_loop.rs
Normal file
145
src/mir/builder/control_flow/plan/normalizer/skeleton_loop.rs
Normal file
@ -0,0 +1,145 @@
|
||||
use super::helpers::{create_phi_bindings, LoopBlocksStandard5};
|
||||
use super::{CoreEffectPlan, CoreLoopPlan, CorePhiInfo, CorePlan};
|
||||
use crate::mir::basic_block::EdgeArgs;
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
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::MirType;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
impl super::PlanNormalizer {
|
||||
pub(in crate::mir::builder) fn normalize_loop_skeleton_from_facts(
|
||||
builder: &mut MirBuilder,
|
||||
facts: &CanonicalLoopFacts,
|
||||
_ctx: &LoopPatternContext,
|
||||
) -> Result<Option<CorePlan>, String> {
|
||||
if !matches!(facts.skeleton_kind, SkeletonKind::Loop) {
|
||||
return Ok(None);
|
||||
}
|
||||
let Some(pattern1) = facts.facts.pattern1_simplewhile.as_ref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let loop_var_init = builder
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.get(&pattern1.loop_var)
|
||||
.copied()
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"[normalizer] Loop variable {} not found",
|
||||
pattern1.loop_var
|
||||
)
|
||||
})?;
|
||||
|
||||
let blocks = LoopBlocksStandard5::allocate(builder)?;
|
||||
let LoopBlocksStandard5 {
|
||||
preheader_bb,
|
||||
header_bb,
|
||||
body_bb,
|
||||
step_bb,
|
||||
after_bb,
|
||||
} = blocks;
|
||||
|
||||
let loop_var_current = builder.alloc_typed(MirType::Integer);
|
||||
let cond_loop = builder.alloc_typed(MirType::Bool);
|
||||
let loop_var_next = builder.alloc_typed(MirType::Integer);
|
||||
|
||||
let phi_bindings = create_phi_bindings(&[(&pattern1.loop_var, loop_var_current)]);
|
||||
|
||||
let (loop_cond_lhs, loop_cond_op, loop_cond_rhs, loop_cond_consts) =
|
||||
Self::lower_compare_ast(&pattern1.condition, builder, &phi_bindings)?;
|
||||
|
||||
let (loop_inc_lhs, loop_inc_op, loop_inc_rhs, loop_inc_consts) =
|
||||
Self::lower_binop_ast(&pattern1.loop_increment, builder, &phi_bindings)?;
|
||||
|
||||
let mut header_effects = loop_cond_consts;
|
||||
header_effects.push(CoreEffectPlan::Compare {
|
||||
dst: cond_loop,
|
||||
lhs: loop_cond_lhs,
|
||||
op: loop_cond_op,
|
||||
rhs: loop_cond_rhs,
|
||||
});
|
||||
|
||||
let mut step_effects = loop_inc_consts;
|
||||
step_effects.push(CoreEffectPlan::BinOp {
|
||||
dst: loop_var_next,
|
||||
lhs: loop_inc_lhs,
|
||||
op: loop_inc_op,
|
||||
rhs: loop_inc_rhs,
|
||||
});
|
||||
|
||||
let block_effects = vec![
|
||||
(preheader_bb, vec![]),
|
||||
(header_bb, header_effects),
|
||||
(body_bb, vec![]),
|
||||
(step_bb, step_effects),
|
||||
];
|
||||
|
||||
let phis = vec![CorePhiInfo {
|
||||
block: header_bb,
|
||||
dst: loop_var_current,
|
||||
inputs: vec![(preheader_bb, loop_var_init), (step_bb, loop_var_next)],
|
||||
tag: format!("loop_var_{}", pattern1.loop_var),
|
||||
}];
|
||||
|
||||
let empty_args = EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![],
|
||||
};
|
||||
|
||||
let branches = vec![BranchStub {
|
||||
from: header_bb,
|
||||
cond: cond_loop,
|
||||
then_target: body_bb,
|
||||
then_args: empty_args.clone(),
|
||||
else_target: after_bb,
|
||||
else_args: empty_args.clone(),
|
||||
}];
|
||||
|
||||
let wires = vec![
|
||||
EdgeStub {
|
||||
from: body_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: Some(step_bb),
|
||||
args: empty_args.clone(),
|
||||
},
|
||||
EdgeStub {
|
||||
from: step_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: Some(header_bb),
|
||||
args: empty_args.clone(),
|
||||
},
|
||||
];
|
||||
|
||||
let frag = Frag {
|
||||
entry: header_bb,
|
||||
exits: BTreeMap::new(),
|
||||
wires,
|
||||
branches,
|
||||
};
|
||||
|
||||
let final_values = vec![(pattern1.loop_var.clone(), loop_var_current)];
|
||||
|
||||
let loop_plan = CoreLoopPlan {
|
||||
preheader_bb,
|
||||
header_bb,
|
||||
body_bb,
|
||||
step_bb,
|
||||
after_bb,
|
||||
found_bb: after_bb,
|
||||
body: vec![],
|
||||
cond_loop,
|
||||
cond_match: cond_loop,
|
||||
block_effects,
|
||||
phis,
|
||||
frag,
|
||||
final_values,
|
||||
};
|
||||
|
||||
Ok(Some(CorePlan::Loop(loop_plan)))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user