feat(edgecfg): Phase 281 P3 - cleanup Normal wiring + docs
This commit is contained in:
@ -21,6 +21,7 @@ use crate::mir::{BinaryOp, CompareOp, ConstValue, Effect, EffectMask, MirType};
|
||||
use crate::mir::builder::control_flow::edgecfg::api::{BranchStub, EdgeStub, ExitKind, Frag};
|
||||
use crate::mir::basic_block::EdgeArgs;
|
||||
use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Phase 273 P1: PlanNormalizer - DomainPlan → CorePlan 変換 (SSOT)
|
||||
pub(in crate::mir::builder) struct PlanNormalizer;
|
||||
@ -295,11 +296,13 @@ impl PlanNormalizer {
|
||||
values: vec![i_current],
|
||||
};
|
||||
|
||||
// Phase 280 TODO: Hand-rolled Frag construction for early exit pattern
|
||||
// Reason: `found_bb` is early Return, doesn't fit compose::if_() model
|
||||
// Future: Consider compose::cleanup() for early exit normalization (Phase 281+)
|
||||
// Current structure: 2 BranchStub (header→body/after, body→found/step) + 2 EdgeStub (step→header, found→Return)
|
||||
let branches = vec![
|
||||
// Phase 281 P2: compose::cleanup() for early exit pattern
|
||||
// Reason: `found_bb` is early Return, handled by cleanup() wiring
|
||||
// Structure: main Frag (header, body, step) + cleanup Frag (found Return)
|
||||
use crate::mir::builder::control_flow::edgecfg::api::compose;
|
||||
|
||||
// Build main Frag (loop structure: header, body, step)
|
||||
let main_branches = vec![
|
||||
BranchStub {
|
||||
from: header_bb,
|
||||
cond: cond_loop,
|
||||
@ -311,31 +314,49 @@ impl PlanNormalizer {
|
||||
BranchStub {
|
||||
from: body_bb,
|
||||
cond: cond_match,
|
||||
then_target: found_bb,
|
||||
then_target: found_bb, // Early exit (handled by cleanup)
|
||||
then_args: empty_args.clone(),
|
||||
else_target: step_bb,
|
||||
else_args: empty_args.clone(),
|
||||
},
|
||||
];
|
||||
|
||||
let wires = vec![
|
||||
let main_wires = vec![
|
||||
EdgeStub {
|
||||
from: step_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: Some(header_bb),
|
||||
args: empty_args,
|
||||
args: empty_args.clone(),
|
||||
},
|
||||
];
|
||||
|
||||
let main_frag = Frag {
|
||||
entry: header_bb,
|
||||
exits: BTreeMap::new(), // No exits from main (only wires)
|
||||
wires: main_wires,
|
||||
branches: main_branches,
|
||||
};
|
||||
|
||||
// Build cleanup Frag (found_bb Return)
|
||||
let cleanup_exits = vec![
|
||||
EdgeStub {
|
||||
from: found_bb,
|
||||
kind: ExitKind::Return,
|
||||
target: None,
|
||||
target: None, // Will be wired by cleanup()
|
||||
args: ret_found_args,
|
||||
},
|
||||
];
|
||||
|
||||
let mut frag = Frag::new(header_bb);
|
||||
frag.branches = branches;
|
||||
frag.wires = wires;
|
||||
let cleanup_frag = Frag {
|
||||
entry: found_bb, // cleanup entry (not used, but required)
|
||||
exits: BTreeMap::from([(ExitKind::Return, cleanup_exits)]),
|
||||
wires: vec![], // Return is in exits, not wires
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Compose! normal_target=None, ret_target=None → Return を上へ伝播
|
||||
let frag = compose::cleanup(main_frag, cleanup_frag, None, None)
|
||||
.expect("compose::cleanup() failed in normalize_scan_with_init");
|
||||
|
||||
// Step 11: Build final_values (Phase 273 P2)
|
||||
let final_values = vec![(parts.loop_var.clone(), i_current)];
|
||||
@ -381,6 +402,8 @@ impl PlanNormalizer {
|
||||
ctx: &LoopPatternContext,
|
||||
) -> Result<CorePlan, String> {
|
||||
use crate::mir::builder::control_flow::joinir::trace;
|
||||
use crate::mir::builder::control_flow::edgecfg::api::compose;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
let trace_logger = trace::trace();
|
||||
let debug = ctx.debug;
|
||||
@ -637,6 +660,72 @@ impl PlanNormalizer {
|
||||
},
|
||||
];
|
||||
|
||||
// Step 9.5: Build Frags for compose::if_() (Phase 281 P0)
|
||||
// Create empty_args for EdgeStub construction
|
||||
let empty_args = EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![],
|
||||
};
|
||||
|
||||
// Build then_frag: entry=then_bb, Normal exit to step
|
||||
// IMPORTANT: Use explicit EdgeStub construction with empty_args (not without_args)
|
||||
let mut then_exits = BTreeMap::new();
|
||||
then_exits.insert(
|
||||
ExitKind::Normal,
|
||||
vec![EdgeStub {
|
||||
from: then_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: None, // Unresolved exit (compose will wire to join)
|
||||
args: empty_args.clone(), // CarriersOnly layout
|
||||
}],
|
||||
);
|
||||
let then_frag = Frag {
|
||||
entry: then_bb,
|
||||
exits: then_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Build else_frag: entry=else_bb, Normal exit to step
|
||||
// IMPORTANT: Use explicit EdgeStub construction with empty_args (not without_args)
|
||||
let mut else_exits = BTreeMap::new();
|
||||
else_exits.insert(
|
||||
ExitKind::Normal,
|
||||
vec![EdgeStub {
|
||||
from: else_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: None, // Unresolved exit (compose will wire to join)
|
||||
args: empty_args.clone(), // CarriersOnly layout
|
||||
}],
|
||||
);
|
||||
let else_frag = Frag {
|
||||
entry: else_bb,
|
||||
exits: else_exits,
|
||||
wires: vec![],
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Build step_frag: entry=step_bb, EMPTY (no back-edge here)
|
||||
// Reason: step→header back-edge is loop-level responsibility, not body_if_frag's
|
||||
// The back-edge will be added manually in Step 12 (final merge)
|
||||
let step_frag = Frag {
|
||||
entry: step_bb,
|
||||
exits: BTreeMap::new(),
|
||||
wires: vec![], // Empty - no back-edge here
|
||||
branches: vec![],
|
||||
};
|
||||
|
||||
// Phase 281 P0: Use compose::if_() for body branch (cond_match: then/else → step)
|
||||
let body_if_frag = compose::if_(
|
||||
body_bb, // header: where cond_match is evaluated
|
||||
cond_match, // condition ValueId
|
||||
then_frag, // then branch
|
||||
empty_args.clone(), // then_entry_args
|
||||
else_frag, // else branch
|
||||
empty_args.clone(), // else_entry_args
|
||||
step_frag, // join target (step_bb)
|
||||
);
|
||||
|
||||
// Step 10: Build block_effects (SSOT ordering: preheader, header, body, then, else, step)
|
||||
let block_effects = vec![
|
||||
(preheader_bb, vec![]), // No effects in preheader
|
||||
@ -691,20 +780,12 @@ impl PlanNormalizer {
|
||||
},
|
||||
];
|
||||
|
||||
// Step 12: Build Frag (2 branches + 3 wires)
|
||||
//
|
||||
// Phase 280 TODO: Hand-rolled Frag construction for split scan pattern
|
||||
// Target (Phase 281): compose::if_(body_bb, cond_match, then_frag, else_frag, step_frag)
|
||||
// Reason deferred: 挙動不変保証が難しい、Phase 280 は SSOT positioning 優先
|
||||
// Migration: Phase 281+ で compose::if_() への移行を検討
|
||||
// Current structure: 2 BranchStub (header→body/after, body→then/else) + 3 EdgeStub (then→step, else→step, step→header)
|
||||
let empty_args = EdgeArgs {
|
||||
layout: JumpArgsLayout::CarriersOnly,
|
||||
values: vec![],
|
||||
};
|
||||
|
||||
let branches = vec![
|
||||
// header -> body/after
|
||||
// Step 12: Build Frag - Phase 281 P0 Complete
|
||||
// - Header branch (hand-rolled): header → body/after
|
||||
// - Body branch (composed): body → then/else → step (from compose::if_())
|
||||
// - Step back-edge (hand-rolled): step → header
|
||||
let mut branches = vec![
|
||||
// Header branch (cond_loop) - hand-rolled
|
||||
BranchStub {
|
||||
from: header_bb,
|
||||
cond: cond_loop,
|
||||
@ -713,44 +794,34 @@ impl PlanNormalizer {
|
||||
else_target: after_bb,
|
||||
else_args: empty_args.clone(),
|
||||
},
|
||||
// body -> then/else
|
||||
BranchStub {
|
||||
from: body_bb,
|
||||
cond: cond_match,
|
||||
then_target: then_bb,
|
||||
then_args: empty_args.clone(),
|
||||
else_target: else_bb,
|
||||
else_args: empty_args.clone(),
|
||||
},
|
||||
];
|
||||
|
||||
let wires = vec![
|
||||
// then -> step
|
||||
EdgeStub {
|
||||
from: then_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: Some(step_bb),
|
||||
args: empty_args.clone(),
|
||||
},
|
||||
// else -> step
|
||||
EdgeStub {
|
||||
from: else_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: Some(step_bb),
|
||||
args: empty_args.clone(),
|
||||
},
|
||||
// step -> header (back-edge)
|
||||
EdgeStub {
|
||||
from: step_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: Some(header_bb),
|
||||
args: empty_args,
|
||||
},
|
||||
];
|
||||
// Merge body_if_frag branches (body → then/else)
|
||||
branches.extend(body_if_frag.branches);
|
||||
|
||||
let mut frag = Frag::new(header_bb);
|
||||
frag.branches = branches;
|
||||
frag.wires = wires;
|
||||
// Merge body_if_frag wires (then/else → step)
|
||||
let mut wires = Vec::new();
|
||||
wires.extend(body_if_frag.wires);
|
||||
|
||||
// Add step back-edge (hand-rolled) - loop-level responsibility
|
||||
wires.push(EdgeStub {
|
||||
from: step_bb,
|
||||
kind: ExitKind::Normal,
|
||||
target: Some(header_bb),
|
||||
args: empty_args.clone(),
|
||||
});
|
||||
|
||||
let mut exits = BTreeMap::new();
|
||||
for (kind, stubs) in body_if_frag.exits {
|
||||
exits.insert(kind, stubs);
|
||||
}
|
||||
|
||||
let frag = Frag {
|
||||
entry: header_bb,
|
||||
exits,
|
||||
wires,
|
||||
branches,
|
||||
};
|
||||
|
||||
// Step 13: Build final_values (i, start for post-loop)
|
||||
let final_values = vec![
|
||||
|
||||
Reference in New Issue
Block a user