From b2587d5de3d22294f0b3c075844dcbb3a34be9fe Mon Sep 17 00:00:00 2001 From: tomoaki Date: Tue, 30 Dec 2025 21:10:17 +0900 Subject: [PATCH] phase29ao(p52): split-scan v0 reject + adopt gating --- docs/development/current/main/10-Now.md | 2 +- docs/development/current/main/30-Backlog.md | 2 +- .../design/coreplan-migration-roadmap-ssot.md | 2 +- .../current/main/phases/phase-29ao/README.md | 5 ++ .../control_flow/plan/composer/coreloop_v0.rs | 50 +++++++++++++++++ .../control_flow/plan/composer/coreloop_v1.rs | 55 +++++++++---------- .../plan/composer/shadow_adopt.rs | 9 ++- 7 files changed, 87 insertions(+), 38 deletions(-) diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index 2fcc752d..c9a36043 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -3,7 +3,7 @@ ## Current Focus - Phase: `docs/development/current/main/phases/phase-29ao/README.md` -- Next: TBD (P51 done; see `docs/development/current/main/phases/phase-29ao/README.md`) +- Next: TBD (P52 done; see `docs/development/current/main/phases/phase-29ao/README.md`) ## Gate (SSOT) diff --git a/docs/development/current/main/30-Backlog.md b/docs/development/current/main/30-Backlog.md index 1da5d160..ad1eb694 100644 --- a/docs/development/current/main/30-Backlog.md +++ b/docs/development/current/main/30-Backlog.md @@ -5,7 +5,7 @@ Scope: 「次にやる候補」を短く列挙するメモ。入口は `docs/dev ## Active -- CorePlan migration: `docs/development/current/main/phases/phase-29ao/README.md`(Next: TBD, P51 done) +- CorePlan migration: `docs/development/current/main/phases/phase-29ao/README.md`(Next: TBD, P52 done) ## Near-Term Candidates diff --git a/docs/development/current/main/design/coreplan-migration-roadmap-ssot.md b/docs/development/current/main/design/coreplan-migration-roadmap-ssot.md index 16207b91..60bba121 100644 --- a/docs/development/current/main/design/coreplan-migration-roadmap-ssot.md +++ b/docs/development/current/main/design/coreplan-migration-roadmap-ssot.md @@ -34,7 +34,7 @@ Related: ## 1.1 Current (active) - Active phase: `docs/development/current/main/phases/phase-29ao/README.md` -- Next step: TBD (P51 done) +- Next step: TBD (P52 done) ## 2. すでに固めた SSOT(再発防止の土台) diff --git a/docs/development/current/main/phases/phase-29ao/README.md b/docs/development/current/main/phases/phase-29ao/README.md index dbf1791e..85b66e61 100644 --- a/docs/development/current/main/phases/phase-29ao/README.md +++ b/docs/development/current/main/phases/phase-29ao/README.md @@ -281,6 +281,11 @@ Gate(SSOT): - 指示書: `docs/development/current/main/phases/phase-29ao/P51-CORELOOPCOMPOSER-V1-PATTERN7-VALUEJOIN-UNIFY-INSTRUCTIONS.md` - ねらい: Pattern7 の value-join を v1 に統一し、v0 は no-join 専用に固定(仕様不変) +## P52: CoreLoopComposer v0/v1 — SplitScan v0 reject + adopt branching ✅ + +- 指示書: `docs/development/current/main/phases/phase-29ao/P52-SPLITSCAN-V0-REJECT-AND-ADOPT-GATE-INSTRUCTIONS.md` +- ねらい: SplitScan の v0/v1 分離を両側の reject で固定し、adopt 分岐を value_join_needed だけに単純化(仕様不変) + ## Next(planned) - Next: TBD diff --git a/src/mir/builder/control_flow/plan/composer/coreloop_v0.rs b/src/mir/builder/control_flow/plan/composer/coreloop_v0.rs index 14a225c4..af175f16 100644 --- a/src/mir/builder/control_flow/plan/composer/coreloop_v0.rs +++ b/src/mir/builder/control_flow/plan/composer/coreloop_v0.rs @@ -606,4 +606,54 @@ mod tests { try_compose_core_loop_v0(&mut builder, &canonical, &ctx).expect("Ok"); assert!(composed.is_none()); } + + #[test] + fn coreloop_v0_split_scan_rejects_value_join_direct() { + let condition = ASTNode::Literal { + value: LiteralValue::Bool(true), + span: Span::unknown(), + }; + let features = LoopFeatureFacts { + value_join: Some(ValueJoinFacts { needed: true }), + ..LoopFeatureFacts::default() + }; + let facts = LoopFacts { + condition_shape: ConditionShape::Unknown, + step_shape: StepShape::Unknown, + skeleton: SkeletonFacts { + kind: SkeletonKind::Loop, + }, + features, + scan_with_init: None, + split_scan: Some(crate::mir::builder::control_flow::plan::facts::loop_facts::SplitScanFacts { + s_var: "s".to_string(), + sep_var: "sep".to_string(), + result_var: "result".to_string(), + i_var: "i".to_string(), + start_var: "start".to_string(), + shape: SplitScanShape::Minimal, + }), + 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 mut builder = MirBuilder::new(); + builder.enter_function_for_test("coreloop_v0_split_scan_join_direct".to_string()); + let ctx = LoopPatternContext::new( + &condition, + &[], + "coreloop_v0_split_scan_join_direct", + false, + false, + ); + let composed = + try_compose_core_loop_v0_split_scan(&mut builder, &canonical, &ctx).expect("Ok"); + assert!(composed.is_none()); + } } diff --git a/src/mir/builder/control_flow/plan/composer/coreloop_v1.rs b/src/mir/builder/control_flow/plan/composer/coreloop_v1.rs index 3fbe8d05..913006a8 100644 --- a/src/mir/builder/control_flow/plan/composer/coreloop_v1.rs +++ b/src/mir/builder/control_flow/plan/composer/coreloop_v1.rs @@ -12,26 +12,7 @@ use crate::mir::builder::control_flow::plan::{ }; use crate::mir::builder::MirBuilder; -pub(in crate::mir::builder) fn try_compose_core_loop_v1( - builder: &mut MirBuilder, - facts: &CanonicalLoopFacts, - ctx: &LoopPatternContext, -) -> Result, String> { - if let Some(core) = try_compose_core_loop_v1_pattern2_break(builder, facts, ctx)? { - return Ok(Some(core)); - } - if let Some(core) = try_compose_core_loop_v1_pattern5_infinite_early_exit( - builder, facts, ctx, - )? { - return Ok(Some(core)); - } - if let Some(core) = try_compose_core_loop_v1_pattern3_ifphi(builder, facts, ctx)? { - return Ok(Some(core)); - } - try_compose_core_loop_v1_split_scan(builder, facts, ctx) -} - -fn try_compose_core_loop_v1_split_scan( +pub(in crate::mir::builder) fn try_compose_core_loop_v1_split_scan( builder: &mut MirBuilder, facts: &CanonicalLoopFacts, ctx: &LoopPatternContext, @@ -148,7 +129,11 @@ pub(in crate::mir::builder) fn try_compose_core_loop_v1_pattern3_ifphi( #[cfg(test)] mod tests { - use super::try_compose_core_loop_v1; + use super::{ + try_compose_core_loop_v1_pattern2_break, try_compose_core_loop_v1_pattern3_ifphi, + try_compose_core_loop_v1_pattern5_infinite_early_exit, + try_compose_core_loop_v1_split_scan, + }; use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span}; use crate::mir::builder::control_flow::plan::facts::feature_facts::{ CleanupFacts, CleanupKindFacts, ExitKindFacts, ExitMapFacts, LoopFeatureFacts, @@ -251,7 +236,7 @@ mod tests { let ctx = LoopPatternContext::new(&condition, &[], "coreloop_v1_split_scan", false, false); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_split_scan(&mut builder, &canonical, &ctx).expect("Ok"); assert!(matches!(composed, Some(crate::mir::builder::control_flow::plan::CorePlan::Loop(_)))); } @@ -292,7 +277,7 @@ mod tests { let ctx = LoopPatternContext::new(&condition, &[], "coreloop_v1_split_scan_no_join", false, false); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_split_scan(&mut builder, &canonical, &ctx).expect("Ok"); assert!(composed.is_none()); } @@ -345,7 +330,7 @@ mod tests { false, ); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_split_scan(&mut builder, &canonical, &ctx).expect("Ok"); assert!(composed.is_none()); } @@ -422,7 +407,8 @@ mod tests { let ctx = LoopPatternContext::new(&loop_condition, &[], "coreloop_v1_pattern2", false, false); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_pattern2_break(&mut builder, &canonical, &ctx) + .expect("Ok"); assert!(matches!(composed, Some(crate::mir::builder::control_flow::plan::CorePlan::Loop(_)))); } @@ -476,7 +462,8 @@ mod tests { false, ); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_pattern2_break(&mut builder, &canonical, &ctx) + .expect("Ok"); assert!(composed.is_none()); } @@ -551,7 +538,10 @@ mod tests { let ctx = LoopPatternContext::new(&condition, &[], "coreloop_v1_pattern5", false, false); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_pattern5_infinite_early_exit( + &mut builder, &canonical, &ctx, + ) + .expect("Ok"); assert!(matches!(composed, Some(crate::mir::builder::control_flow::plan::CorePlan::Loop(_)))); } @@ -605,7 +595,10 @@ mod tests { false, ); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_pattern5_infinite_early_exit( + &mut builder, &canonical, &ctx, + ) + .expect("Ok"); assert!(composed.is_none()); } @@ -688,7 +681,8 @@ mod tests { let ctx = LoopPatternContext::new(&condition, &[], "coreloop_v1_pattern3", false, false); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_pattern3_ifphi(&mut builder, &canonical, &ctx) + .expect("Ok"); assert!(matches!(composed, Some(crate::mir::builder::control_flow::plan::CorePlan::Loop(_)))); } @@ -742,7 +736,8 @@ mod tests { false, ); let composed = - try_compose_core_loop_v1(&mut builder, &canonical, &ctx).expect("Ok"); + try_compose_core_loop_v1_pattern3_ifphi(&mut builder, &canonical, &ctx) + .expect("Ok"); assert!(composed.is_none()); } } diff --git a/src/mir/builder/control_flow/plan/composer/shadow_adopt.rs b/src/mir/builder/control_flow/plan/composer/shadow_adopt.rs index beb04666..84035eda 100644 --- a/src/mir/builder/control_flow/plan/composer/shadow_adopt.rs +++ b/src/mir/builder/control_flow/plan/composer/shadow_adopt.rs @@ -3,10 +3,9 @@ use super::coreloop_v0::{ try_compose_core_loop_v0_scan_with_init, try_compose_core_loop_v0_split_scan, }; -use super::coreloop_v1::try_compose_core_loop_v1; use super::coreloop_v1::{ try_compose_core_loop_v1_pattern2_break, try_compose_core_loop_v1_pattern3_ifphi, - try_compose_core_loop_v1_pattern5_infinite_early_exit, + try_compose_core_loop_v1_pattern5_infinite_early_exit, try_compose_core_loop_v1_split_scan, }; use super::PlanNormalizer; use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext; @@ -105,7 +104,7 @@ pub(in crate::mir::builder) fn try_release_adopt_core_plan_for_pattern7_split_sc } let composed = if facts.value_join_needed { - try_compose_core_loop_v1(builder, facts, ctx) + try_compose_core_loop_v1_split_scan(builder, facts, ctx) } else { try_compose_core_loop_v0_split_scan(builder, facts, ctx) }; @@ -394,11 +393,11 @@ pub(in crate::mir::builder) fn try_shadow_adopt_core_plan( return Err("pattern7 strict/dev adopt failed: facts mismatch".to_string()); } let core_plan = if facts.value_join_needed { - try_compose_core_loop_v1(builder, facts, ctx)? + try_compose_core_loop_v1_split_scan(builder, facts, ctx)? } else { try_compose_core_loop_v0_split_scan(builder, facts, ctx)? } - .ok_or_else(|| "pattern7 strict/dev adopt failed: compose rejected".to_string())?; + .ok_or_else(|| "pattern7 strict/dev adopt failed: compose rejected".to_string())?; Ok(Some(ShadowAdoptOutcome { core_plan, tag: "[coreplan/shadow_adopt:pattern7_split_scan]",