feat(mir/llvm): Phase 273 P0-P1 DomainPlan→CorePlan + LLVM arg fix
Phase 273 P0-P1: Two-layer plan architecture - DomainPlan: Pattern-specific knowledge (ScanWithInit) - CorePlan: Fixed vocabulary (Seq, Loop, If, Effect, Exit) - ValueId references only (String expressions forbidden) - Pipeline: Extractor→Normalizer→Verifier→Lowerer New plan/ module: - mod.rs: Type definitions, SSOT spec - normalizer.rs: DomainPlan→CorePlan + ID allocation - verifier.rs: V1-V6 invariant checks (fail-fast) - lowerer.rs: CorePlan→MIR (pattern-agnostic) LLVM fix (ChatGPT): - function_lower.py: Fix argument reference bug - Phase 258 index_of_string now PASS on LLVM backend 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
230
src/mir/builder/control_flow/plan/mod.rs
Normal file
230
src/mir/builder/control_flow/plan/mod.rs
Normal file
@ -0,0 +1,230 @@
|
||||
//! Phase 273 P1: DomainPlan/CorePlan 二層構造 + PlanNormalizer + PlanVerifier
|
||||
//!
|
||||
//! This module provides a two-layer Plan architecture for loop pattern lowering:
|
||||
//!
|
||||
//! # Architecture
|
||||
//!
|
||||
//! ```text
|
||||
//! DomainPlan (Pattern固有)
|
||||
//! ↓ PlanNormalizer (SSOT)
|
||||
//! CorePlan (固定語彙 - 構造ノードのみ)
|
||||
//! ↓ PlanLowerer
|
||||
//! MIR (block/value/phi)
|
||||
//! ```
|
||||
//!
|
||||
//! - **DomainPlan**: Pattern-specific plans (ScanWithInit etc.)
|
||||
//! - **PlanNormalizer**: DomainPlan → CorePlan conversion (SSOT, scan knowledge here)
|
||||
//! - **CorePlan**: Fixed vocabulary, expressions as ValueId references (no String parsing)
|
||||
//! - **PlanVerifier**: Fail-fast validation for CorePlan invariants
|
||||
//! - **PlanLowerer**: Processes CorePlan only (no string interpretation)
|
||||
//!
|
||||
//! # Key Design Decision (String式禁止)
|
||||
//!
|
||||
//! CorePlan expressions use **ValueId references only** (String expressions forbidden).
|
||||
//! This prevents "second language processor" from growing inside Lowerer.
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::{BasicBlockId, BinaryOp, CompareOp, ConstValue, ValueId};
|
||||
|
||||
pub(in crate::mir::builder) mod lowerer;
|
||||
pub(in crate::mir::builder) mod normalizer;
|
||||
pub(in crate::mir::builder) mod verifier;
|
||||
|
||||
// ============================================================================
|
||||
// DomainPlan (Pattern固有)
|
||||
// ============================================================================
|
||||
|
||||
/// Phase 273 P1: DomainPlan - Pattern-specific plan vocabulary
|
||||
///
|
||||
/// DomainPlan contains pattern-specific knowledge (e.g., scan semantics).
|
||||
/// Normalizer converts DomainPlan → CorePlan with ValueId generation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) enum DomainPlan {
|
||||
/// Pattern6: index_of / find scan
|
||||
ScanWithInit(ScanWithInitPlan),
|
||||
// P2+: Split(SplitPlan), BoolPredicate(BoolPredicatePlan), etc.
|
||||
}
|
||||
|
||||
/// Phase 273 P0: Scan direction for forward/reverse scan
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(in crate::mir::builder) enum ScanDirection {
|
||||
/// Forward scan: i < s.length(), i = i + 1
|
||||
Forward,
|
||||
/// Reverse scan: i >= 0, i = i - 1
|
||||
Reverse,
|
||||
}
|
||||
|
||||
/// Phase 273 P0: Extracted structure for scan-with-init pattern
|
||||
///
|
||||
/// This structure contains all the information needed to lower an index_of-style loop.
|
||||
/// Moved from pattern6_scan_with_init.rs for centralization.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct ScanWithInitPlan {
|
||||
/// Loop variable name (e.g., "i")
|
||||
pub loop_var: String,
|
||||
/// Haystack variable name (e.g., "s")
|
||||
pub haystack: String,
|
||||
/// Needle variable name (e.g., "ch")
|
||||
pub needle: String,
|
||||
/// Step literal (Phase 257: can be 1 forward or -1 reverse)
|
||||
pub step_lit: i64,
|
||||
/// Early return expression (P0: must be Variable(loop_var))
|
||||
pub early_return_expr: ASTNode,
|
||||
/// Not-found return literal (P0: must be -1)
|
||||
pub not_found_return_lit: i64,
|
||||
/// Scan direction (Phase 257 P0)
|
||||
pub scan_direction: ScanDirection,
|
||||
/// Phase 258 P0: True if dynamic needle (substr.length()), false if fixed (ch)
|
||||
pub dynamic_needle: bool,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CorePlan (固定語彙 - 構造ノードのみ)
|
||||
// ============================================================================
|
||||
|
||||
/// Phase 273 P1: CorePlan - Fixed vocabulary plan (structure nodes only)
|
||||
///
|
||||
/// CorePlan expressions use **ValueId references only** (no String parsing).
|
||||
/// This prevents "second language processor" from growing inside Lowerer.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) enum CorePlan {
|
||||
/// Sequence: execute plans in order
|
||||
Seq(Vec<CorePlan>),
|
||||
|
||||
/// Loop with carriers (PHI variables)
|
||||
Loop(CoreLoopPlan),
|
||||
|
||||
/// Conditional branching
|
||||
If(CoreIfPlan),
|
||||
|
||||
/// Side effect (already lowered to ValueId)
|
||||
Effect(CoreEffectPlan),
|
||||
|
||||
/// Control flow exit (Return/Break/Continue)
|
||||
Exit(CoreExitPlan),
|
||||
}
|
||||
|
||||
/// Phase 273 P1: Loop plan with carriers
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct CoreLoopPlan {
|
||||
// === Block IDs (pre-allocated by Normalizer) ===
|
||||
|
||||
/// Preheader block (entry to loop)
|
||||
pub preheader_bb: BasicBlockId,
|
||||
|
||||
/// Header block (loop condition check)
|
||||
pub header_bb: BasicBlockId,
|
||||
|
||||
/// Body block (loop body start)
|
||||
pub body_bb: BasicBlockId,
|
||||
|
||||
/// Step block (increment and back-edge)
|
||||
pub step_bb: BasicBlockId,
|
||||
|
||||
/// After block (loop exit)
|
||||
pub after_bb: BasicBlockId,
|
||||
|
||||
/// Found block (early exit on match)
|
||||
pub found_bb: BasicBlockId,
|
||||
|
||||
// === Effects per block (emitted by Lowerer) ===
|
||||
|
||||
/// Header effects (emitted in header_bb before branch)
|
||||
pub header_effects: Vec<CoreEffectPlan>,
|
||||
|
||||
/// Body plans (emitted in body_bb, can contain If/Exit)
|
||||
pub body: Vec<CorePlan>,
|
||||
|
||||
/// Step effects (emitted in step_bb before back-edge)
|
||||
pub step_effects: Vec<CoreEffectPlan>,
|
||||
|
||||
// === Loop control ===
|
||||
|
||||
/// Loop carriers (PHI variables)
|
||||
pub carriers: Vec<CoreCarrierInfo>,
|
||||
|
||||
/// Loop condition (for header→body/after branch)
|
||||
pub cond_loop: ValueId,
|
||||
|
||||
/// Match condition (for body→found/step branch)
|
||||
pub cond_match: ValueId,
|
||||
|
||||
/// Loop variable name (for variable_map update after loop)
|
||||
pub loop_var_name: String,
|
||||
}
|
||||
|
||||
/// Phase 273 P1: Loop carrier (PHI variable)
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct CoreCarrierInfo {
|
||||
/// Variable name (for variable_map update)
|
||||
pub name: String,
|
||||
|
||||
/// Initial value (from preheader)
|
||||
pub init_value: ValueId,
|
||||
|
||||
/// Step value (from step block, back-edge)
|
||||
pub step_value: ValueId,
|
||||
|
||||
/// PHI destination (loop variable inside loop)
|
||||
pub phi_dst: ValueId,
|
||||
}
|
||||
|
||||
/// Phase 273 P1: Conditional plan
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct CoreIfPlan {
|
||||
/// Condition (ValueId reference, not String!)
|
||||
pub condition: ValueId,
|
||||
|
||||
/// Then branch plans
|
||||
pub then_plans: Vec<CorePlan>,
|
||||
|
||||
/// Else branch plans (optional)
|
||||
pub else_plans: Option<Vec<CorePlan>>,
|
||||
}
|
||||
|
||||
/// Phase 273 P1: Effect plan (side effects already lowered to ValueId)
|
||||
///
|
||||
/// Effect vocabulary is minimal (scan-specific variants forbidden):
|
||||
/// - MethodCall, BinOp, Compare, Const only
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) enum CoreEffectPlan {
|
||||
/// Method call (args are ValueIds, not Strings!)
|
||||
MethodCall {
|
||||
dst: ValueId,
|
||||
object: ValueId,
|
||||
method: String, // Method name only (OK as String)
|
||||
args: Vec<ValueId>,
|
||||
},
|
||||
|
||||
/// Binary operation
|
||||
BinOp {
|
||||
dst: ValueId,
|
||||
lhs: ValueId,
|
||||
op: BinaryOp,
|
||||
rhs: ValueId,
|
||||
},
|
||||
|
||||
/// Comparison
|
||||
Compare {
|
||||
dst: ValueId,
|
||||
lhs: ValueId,
|
||||
op: CompareOp,
|
||||
rhs: ValueId,
|
||||
},
|
||||
|
||||
/// Constant
|
||||
Const { dst: ValueId, value: ConstValue },
|
||||
}
|
||||
|
||||
/// Phase 273 P1: Exit plan (control flow exit)
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) enum CoreExitPlan {
|
||||
/// Return with optional value
|
||||
Return(Option<ValueId>),
|
||||
|
||||
/// Break from loop
|
||||
Break,
|
||||
|
||||
/// Continue to next iteration
|
||||
Continue,
|
||||
}
|
||||
Reference in New Issue
Block a user