phase29ao(p22): dedup pattern1 coreloop construction
This commit is contained in:
@ -18,9 +18,12 @@ Scope: Repo root の旧リンク互換。現行の入口は `docs/development/cu
|
||||
**CorePlan migration 道筋 SSOT**
|
||||
`docs/development/current/main/design/coreplan-migration-roadmap-ssot.md` が移行タスクの Done 判定の入口。
|
||||
|
||||
**Next implementation (Phase 29ao P22)**
|
||||
- 目的: Pattern1 の CoreLoop 構築コードを DomainPlan/Facts で二重化させず、1箇所へ統一する(divergence防止)
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ao/P22-DEDUP-PATTERN1-CORELOOP-CONSTRUCTION-INSTRUCTIONS.md`
|
||||
**Next implementation (Phase 29ao P23)**
|
||||
- 目的: TBD
|
||||
- 指示書: TBD
|
||||
|
||||
**2025-12-30: Phase 29ao P22 COMPLETE (Pattern1 CoreLoop dedup)**
|
||||
Pattern1 の CoreLoop 構築を SSOT で 1 箇所に統一し、DomainPlan/Facts の二重化を解消した。
|
||||
|
||||
**2025-12-30: Phase 29ao P21 COMPLETE (Pattern1 subset step-only gate)**
|
||||
Pattern1 subset を body=step のみに引き締め、strict/dev shadow adopt の誤マッチを遮断した。
|
||||
|
||||
@ -2,12 +2,17 @@
|
||||
|
||||
## Current Focus: Phase 29ao(CorePlan composition)
|
||||
|
||||
Next: Phase 29ao P22(dedup: Pattern1 coreloop construction)
|
||||
指示書: `docs/development/current/main/phases/phase-29ao/P22-DEDUP-PATTERN1-CORELOOP-CONSTRUCTION-INSTRUCTIONS.md`
|
||||
Next: Phase 29ao P23(TBD)
|
||||
指示書: TBD
|
||||
運用ルール: integration filter で phase143_* は回さない(JoinIR 回帰は phase29ae pack のみ)
|
||||
運用ルール: phase286_pattern9_* は legacy pack (SKIP) を使う
|
||||
移行道筋 SSOT: `docs/development/current/main/design/coreplan-migration-roadmap-ssot.md`
|
||||
|
||||
**2025-12-30: Phase 29ao P22 完了** ✅
|
||||
- 目的: Pattern1 の CoreLoop 構築を SSOT 化し、DomainPlan/Facts 経路の二重実装を排除
|
||||
- 変更: `src/mir/builder/control_flow/plan/normalizer/pattern1_coreloop_builder.rs` / `src/mir/builder/control_flow/plan/normalizer/pattern1_simple_while.rs` / `src/mir/builder/control_flow/plan/normalizer/skeleton_loop.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 P21 完了** ✅
|
||||
- 目的: Pattern1 subset を body=step のみに引き締め、strict/dev shadow adopt の誤マッチを遮断
|
||||
- 変更: `src/mir/builder/control_flow/plan/policies/pattern1_subset_policy.rs` / `src/mir/builder/control_flow/plan/facts/pattern1_simplewhile_facts.rs` / `src/mir/builder/control_flow/plan/extractors/pattern1.rs` / `apps/tests/phase29ao_pattern1_subset_reject_extra_stmt.hako` / `tools/smokes/v2/profiles/integration/joinir/phase29ao_pattern1_subset_reject_extra_stmt_vm.sh` / `tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` / `docs/development/current/main/phases/phase-29ae/README.md` / `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`
|
||||
|
||||
@ -15,8 +15,8 @@ Related:
|
||||
|
||||
- **Phase 29ao(active): CorePlan composition from Skeleton/Feature**
|
||||
- 入口: `docs/development/current/main/phases/phase-29ao/README.md`
|
||||
- 状況: P0–P21 ✅ 完了 / Next: P22(Pattern1 dedup)
|
||||
- Next 指示書: `docs/development/current/main/phases/phase-29ao/P22-DEDUP-PATTERN1-CORELOOP-CONSTRUCTION-INSTRUCTIONS.md`
|
||||
- 状況: P0–P22 ✅ 完了 / Next: P23(TBD)
|
||||
- Next 指示書: TBD
|
||||
|
||||
- **Phase 29af(✅ COMPLETE): Boundary hygiene / regression entrypoint / carrier layout SSOT**
|
||||
- 入口: `docs/development/current/main/phases/phase-29af/README.md`
|
||||
|
||||
@ -132,7 +132,11 @@ Gate(SSOT):
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ao/P21-PATTERN1-SUBSET-BODY-IS-STEP-ONLY-INSTRUCTIONS.md`
|
||||
- ねらい: Pattern1 subset を body=step のみに引き締め、strict/dev shadow adopt の誤マッチを遮断
|
||||
|
||||
## P22: Dedup Pattern1 CoreLoop construction(SSOT統一)✅
|
||||
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ao/P22-DEDUP-PATTERN1-CORELOOP-CONSTRUCTION-INSTRUCTIONS.md`
|
||||
- ねらい: DomainPlan/Facts 経路の CoreLoop 構築を 1 箇所へ統一し divergence を防ぐ
|
||||
|
||||
## Next(planned)
|
||||
|
||||
- P22: Pattern1 CoreLoop 構築の重複排除(DomainPlan/Facts の SSOT 統一)
|
||||
- 指示書: `docs/development/current/main/phases/phase-29ao/P22-DEDUP-PATTERN1-CORELOOP-CONSTRUCTION-INSTRUCTIONS.md`
|
||||
- P23: TBD
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
//! Lowerer processes CorePlan without any pattern knowledge.
|
||||
|
||||
mod helpers;
|
||||
mod pattern1_coreloop_builder;
|
||||
mod pattern1_simple_while;
|
||||
mod pattern2_break;
|
||||
mod pattern3_if_phi;
|
||||
|
||||
@ -0,0 +1,214 @@
|
||||
use super::helpers::{create_phi_bindings, LoopBlocksStandard5};
|
||||
use super::{CoreEffectPlan, CoreLoopPlan, CorePhiInfo};
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::basic_block::EdgeArgs;
|
||||
use crate::mir::builder::control_flow::edgecfg::api::{BranchStub, EdgeStub, ExitKind, Frag};
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
|
||||
use crate::mir::MirType;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub(super) fn build_pattern1_coreloop(
|
||||
builder: &mut MirBuilder,
|
||||
loop_var: &str,
|
||||
condition: &ASTNode,
|
||||
loop_increment: &ASTNode,
|
||||
_ctx: &LoopPatternContext,
|
||||
) -> Result<CoreLoopPlan, String> {
|
||||
let loop_var_init = builder
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.get(loop_var)
|
||||
.copied()
|
||||
.ok_or_else(|| format!("[normalizer] Loop variable {} not found", 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(&[(loop_var, loop_var_current)]);
|
||||
|
||||
let (loop_cond_lhs, loop_cond_op, loop_cond_rhs, loop_cond_consts) =
|
||||
super::PlanNormalizer::lower_compare_ast(condition, builder, &phi_bindings)?;
|
||||
|
||||
let (loop_inc_lhs, loop_inc_op, loop_inc_rhs, loop_inc_consts) =
|
||||
super::PlanNormalizer::lower_binop_ast(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_{}", 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,
|
||||
block_params: BTreeMap::new(),
|
||||
exits: BTreeMap::new(),
|
||||
wires,
|
||||
branches,
|
||||
};
|
||||
|
||||
let final_values = vec![(loop_var.to_string(), loop_var_current)];
|
||||
|
||||
Ok(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,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
|
||||
fn make_condition(loop_var: &str, limit: i64) -> ASTNode {
|
||||
ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(ASTNode::Variable {
|
||||
name: loop_var.to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
right: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(limit),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_increment(loop_var: &str) -> ASTNode {
|
||||
ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Add,
|
||||
left: Box::new(ASTNode::Variable {
|
||||
name: loop_var.to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
right: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_body(loop_var: &str) -> Vec<ASTNode> {
|
||||
vec![ASTNode::Assignment {
|
||||
target: Box::new(ASTNode::Variable {
|
||||
name: loop_var.to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
value: Box::new(make_increment(loop_var)),
|
||||
span: Span::unknown(),
|
||||
}]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_pattern1_coreloop_has_expected_frag_shape() {
|
||||
let mut builder = MirBuilder::new();
|
||||
builder.enter_function_for_test("pattern1_coreloop_test".to_string());
|
||||
|
||||
let loop_var = "i";
|
||||
let loop_var_init = builder.alloc_typed(MirType::Integer);
|
||||
builder
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.insert(loop_var.to_string(), loop_var_init);
|
||||
|
||||
let condition = make_condition(loop_var, 3);
|
||||
let loop_increment = make_increment(loop_var);
|
||||
let body = make_body(loop_var);
|
||||
let ctx = LoopPatternContext::new(&condition, &body, "pattern1_coreloop_test", false, false);
|
||||
|
||||
let loop_plan = build_pattern1_coreloop(
|
||||
&mut builder,
|
||||
loop_var,
|
||||
&condition,
|
||||
&loop_increment,
|
||||
&ctx,
|
||||
)
|
||||
.expect("pattern1 coreloop build should succeed");
|
||||
|
||||
assert_eq!(loop_plan.phis.len(), 1);
|
||||
assert_eq!(loop_plan.frag.branches.len(), 1);
|
||||
assert_eq!(loop_plan.frag.wires.len(), 2);
|
||||
assert!(loop_plan.frag.exits.is_empty());
|
||||
|
||||
builder.exit_function_for_test();
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,7 @@
|
||||
use super::helpers::{create_phi_bindings, LoopBlocksStandard5};
|
||||
use super::{CoreEffectPlan, CoreLoopPlan, CorePhiInfo, CorePlan, Pattern1SimpleWhilePlan};
|
||||
use crate::mir::basic_block::EdgeArgs;
|
||||
use crate::mir::builder::control_flow::edgecfg::api::{BranchStub, EdgeStub, ExitKind, Frag};
|
||||
use super::pattern1_coreloop_builder::build_pattern1_coreloop;
|
||||
use super::{CorePlan, Pattern1SimpleWhilePlan};
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
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 {
|
||||
/// Phase 286 P2.1: Pattern1SimpleWhile → CorePlan 変換
|
||||
@ -35,140 +30,13 @@ impl super::PlanNormalizer {
|
||||
);
|
||||
}
|
||||
|
||||
// Step 1: Get host ValueId for loop variable
|
||||
let loop_var_init = builder
|
||||
.variable_ctx
|
||||
.variable_map
|
||||
.get(&parts.loop_var)
|
||||
.copied()
|
||||
.ok_or_else(|| format!("[normalizer] Loop variable {} not found", parts.loop_var))?;
|
||||
|
||||
// Step 2-3: Allocate BasicBlockIds
|
||||
let blocks = LoopBlocksStandard5::allocate(builder)?;
|
||||
let LoopBlocksStandard5 {
|
||||
preheader_bb,
|
||||
header_bb,
|
||||
body_bb,
|
||||
step_bb,
|
||||
after_bb,
|
||||
} = blocks;
|
||||
|
||||
if debug {
|
||||
trace_logger.debug(
|
||||
"normalizer/pattern1_simple_while",
|
||||
&format!(
|
||||
"Allocated: preheader={:?}, header={:?}, body={:?}, step={:?}, after={:?}",
|
||||
preheader_bb, header_bb, body_bb, step_bb, after_bb
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Step 4: Allocate ValueIds for loop control
|
||||
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);
|
||||
|
||||
// Step 5: Build phi_bindings
|
||||
let phi_bindings = create_phi_bindings(&[(&parts.loop_var, loop_var_current)]);
|
||||
|
||||
// Step 6: Lower AST expressions
|
||||
let (loop_cond_lhs, loop_cond_op, loop_cond_rhs, loop_cond_consts) =
|
||||
Self::lower_compare_ast(&parts.condition, builder, &phi_bindings)?;
|
||||
|
||||
let (loop_inc_lhs, loop_inc_op, loop_inc_rhs, loop_inc_consts) =
|
||||
Self::lower_binop_ast(&parts.loop_increment, builder, &phi_bindings)?;
|
||||
|
||||
// Step 7: Build header_effects
|
||||
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,
|
||||
});
|
||||
|
||||
// Step 8: Build step_effects
|
||||
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,
|
||||
});
|
||||
|
||||
// Step 9: Build block_effects
|
||||
let block_effects = vec![
|
||||
(preheader_bb, vec![]),
|
||||
(header_bb, header_effects),
|
||||
(body_bb, vec![]),
|
||||
(step_bb, step_effects),
|
||||
];
|
||||
|
||||
// Step 10: Build PHI
|
||||
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_{}", parts.loop_var),
|
||||
}];
|
||||
|
||||
// Step 11: Build Frag
|
||||
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,
|
||||
block_params: BTreeMap::new(),
|
||||
exits: BTreeMap::new(),
|
||||
wires,
|
||||
branches,
|
||||
};
|
||||
|
||||
// Step 12: Build final_values
|
||||
let final_values = vec![(parts.loop_var.clone(), loop_var_current)];
|
||||
|
||||
// Step 13: Build CoreLoopPlan
|
||||
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,
|
||||
};
|
||||
let loop_plan = build_pattern1_coreloop(
|
||||
builder,
|
||||
&parts.loop_var,
|
||||
&parts.condition,
|
||||
&parts.loop_increment,
|
||||
ctx,
|
||||
)?;
|
||||
|
||||
if debug {
|
||||
trace_logger.debug(
|
||||
|
||||
@ -1,24 +1,15 @@
|
||||
use super::helpers::{create_phi_bindings, LoopBlocksStandard5};
|
||||
use super::{CoreEffectPlan, CoreLoopPlan, CorePhiInfo, CorePlan};
|
||||
use crate::mir::basic_block::{BasicBlockId, EdgeArgs};
|
||||
use super::pattern1_coreloop_builder::build_pattern1_coreloop;
|
||||
use super::CorePlan;
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
use crate::mir::builder::control_flow::plan::facts::feature_facts::{
|
||||
CleanupKindFacts, ExitKindFacts,
|
||||
};
|
||||
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::control_form::LoopId;
|
||||
use crate::mir::MirType;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
impl super::PlanNormalizer {
|
||||
pub(in crate::mir::builder) fn normalize_loop_skeleton_from_facts(
|
||||
builder: &mut MirBuilder,
|
||||
facts: &CanonicalLoopFacts,
|
||||
_ctx: &LoopPatternContext,
|
||||
ctx: &LoopPatternContext,
|
||||
) -> Result<Option<CorePlan>, String> {
|
||||
if facts.value_join_needed {
|
||||
return Ok(None);
|
||||
@ -30,165 +21,14 @@ impl super::PlanNormalizer {
|
||||
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,
|
||||
block_params: BTreeMap::new(),
|
||||
exits: build_exitmap_from_presence(
|
||||
&facts.exit_kinds_present,
|
||||
&facts.cleanup_kinds_present,
|
||||
body_bb,
|
||||
),
|
||||
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,
|
||||
};
|
||||
let loop_plan = build_pattern1_coreloop(
|
||||
builder,
|
||||
&pattern1.loop_var,
|
||||
&pattern1.condition,
|
||||
&pattern1.loop_increment,
|
||||
ctx,
|
||||
)?;
|
||||
|
||||
Ok(Some(CorePlan::Loop(loop_plan)))
|
||||
}
|
||||
}
|
||||
|
||||
fn build_exitmap_from_presence(
|
||||
exit_kinds_present: &BTreeSet<ExitKindFacts>,
|
||||
cleanup_kinds_present: &BTreeSet<CleanupKindFacts>,
|
||||
from: BasicBlockId,
|
||||
) -> BTreeMap<ExitKind, Vec<EdgeStub>> {
|
||||
let present = union_exit_kinds(exit_kinds_present, cleanup_kinds_present);
|
||||
let mut exits = BTreeMap::new();
|
||||
for kind in present {
|
||||
let exit_kind = match kind {
|
||||
ExitKindFacts::Return => ExitKind::Return,
|
||||
ExitKindFacts::Break => ExitKind::Break(LoopId(0)),
|
||||
ExitKindFacts::Continue => ExitKind::Continue(LoopId(0)),
|
||||
};
|
||||
exits.insert(exit_kind, vec![EdgeStub::without_args(from, exit_kind)]);
|
||||
}
|
||||
exits
|
||||
}
|
||||
|
||||
fn union_exit_kinds(
|
||||
exit_kinds_present: &BTreeSet<ExitKindFacts>,
|
||||
cleanup_kinds_present: &BTreeSet<CleanupKindFacts>,
|
||||
) -> BTreeSet<ExitKindFacts> {
|
||||
let mut combined = exit_kinds_present.clone();
|
||||
combined.extend(
|
||||
cleanup_kinds_present.iter().map(exit_kind_facts_from_cleanup_kind),
|
||||
);
|
||||
combined
|
||||
}
|
||||
|
||||
fn exit_kind_facts_from_cleanup_kind(kind: &CleanupKindFacts) -> ExitKindFacts {
|
||||
match kind {
|
||||
CleanupKindFacts::Return => ExitKindFacts::Return,
|
||||
CleanupKindFacts::Break => ExitKindFacts::Break,
|
||||
CleanupKindFacts::Continue => ExitKindFacts::Continue,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user