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:
2025-12-22 22:42:56 +09:00
parent f07c2e7874
commit 960241795d
20 changed files with 1728 additions and 388 deletions

View 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,
}