Extended PatternPipelineContext and CarrierUpdateInfo for Pattern 3 AST-based generalization. Changes: 1. PatternPipelineContext: - Added loop_condition: Option<ASTNode> - Added loop_body: Option<Vec<ASTNode>> - Added loop_update_summary: Option<LoopUpdateSummary> - Updated build_pattern_context() for Pattern 3 2. CarrierUpdateInfo: - Added then_expr: Option<ASTNode> - Added else_expr: Option<ASTNode> - Updated analyze_loop_updates() with None defaults Status: Phase 213-2 Steps 2-2 & 2-3 complete Next: Create Pattern3IfAnalyzer to extract if statement and populate update summary
265 lines
8.1 KiB
Rust
265 lines
8.1 KiB
Rust
//! ValueId Range Allocation for JoinIR Lowering Modules
|
|
//!
|
|
//! This module manages ValueId ranges for each JoinIR lowering module to prevent
|
|
//! ID conflicts when multiple lowerings coexist.
|
|
//!
|
|
//! ## Current Allocations
|
|
//!
|
|
//! | Module | Range | Entry | Loop | Notes |
|
|
//! |-------------------------|------------|--------|--------|-------|
|
|
//! | min_loop | 1000-2999 | 1000+ | 2000+ | Minimal loop test |
|
|
//! | skip_ws | 3000-4999 | 3000+ | 4000+ | Skip whitespace |
|
|
//! | funcscanner_trim | 5000-6999 | 5000+ | 6000+ | Trim whitespace |
|
|
//! | stage1_using_resolver | 7000-8999 | 7000+ | 8000+ | Stage-1 using resolver |
|
|
//! | funcscanner_append_defs | 9000-10999 | 9000+ | 10000+ | FuncScanner append defs |
|
|
//! | stageb_body_extract | 11000-12999| 11000+ | 12000+ | Stage-B body extractor |
|
|
//! | stageb_funcscanner | 13000-14999| 13000+ | 14000+ | Stage-B FuncScanner (scan_all_boxes) |
|
|
//!
|
|
//! ## Usage Example
|
|
//!
|
|
//! ```rust,ignore
|
|
//! use crate::mir::join_ir::lowering::value_id_ranges::stage1_using_resolver as vid;
|
|
//!
|
|
//! let entries_param = vid::entry(0); // ValueId(7000)
|
|
//! let n_param = vid::entry(1); // ValueId(7001)
|
|
//! let entries_loop = vid::loop_step(0); // ValueId(8000)
|
|
//! let n_loop = vid::loop_step(1); // ValueId(8001)
|
|
//! ```
|
|
//!
|
|
//! ## Future Extensions
|
|
//!
|
|
//! When adding new lowering modules, allocate ranges in increments of 2000:
|
|
//! - 9000-10999 (next available)
|
|
//! - 11000-12999
|
|
//! - 13000-14999
|
|
//! - etc.
|
|
|
|
use crate::mir::ValueId;
|
|
|
|
/// Base addresses for each lowering module's ValueId range
|
|
pub mod base {
|
|
/// min_loop: Minimal loop test (1000-2999)
|
|
#[allow(dead_code)]
|
|
pub const MIN_LOOP: u32 = 1000;
|
|
|
|
/// skip_ws: Skip whitespace loop (3000-4999)
|
|
pub const SKIP_WS: u32 = 3000;
|
|
|
|
/// funcscanner_trim: Trim whitespace loop (5000-6999)
|
|
pub const FUNCSCANNER_TRIM: u32 = 5000;
|
|
|
|
/// stage1_using_resolver: Stage-1 using resolver entries loop (7000-8999)
|
|
pub const STAGE1_USING_RESOLVER: u32 = 7000;
|
|
|
|
/// funcscanner_append_defs: FuncScanner append defs loop (9000-10999)
|
|
pub const FUNCSCANNER_APPEND_DEFS: u32 = 9000;
|
|
|
|
/// stageb_body_extract: Stage-B body extractor loop (11000-12999)
|
|
pub const STAGEB_BODY_EXTRACT: u32 = 11000;
|
|
|
|
/// stageb_funcscanner: Stage-B FuncScanner scan_all_boxes loop (13000-14999)
|
|
pub const STAGEB_FUNCSCANNER: u32 = 13000;
|
|
}
|
|
|
|
/// Helper function to create ValueId from base + offset
|
|
///
|
|
/// This is a const fn, so it's computed at compile time with zero runtime cost.
|
|
#[inline]
|
|
pub const fn id(base: u32, offset: u32) -> ValueId {
|
|
ValueId(base + offset)
|
|
}
|
|
|
|
/// ValueId helpers for min_loop lowering module
|
|
pub mod min_loop {
|
|
use super::{base, id};
|
|
use crate::mir::ValueId;
|
|
|
|
/// Entry function ValueIds (1000-1999)
|
|
#[inline]
|
|
#[allow(dead_code)]
|
|
pub const fn entry(offset: u32) -> ValueId {
|
|
id(base::MIN_LOOP, offset)
|
|
}
|
|
|
|
/// Loop function ValueIds (2000-2999)
|
|
#[inline]
|
|
#[allow(dead_code)]
|
|
pub const fn loop_step(offset: u32) -> ValueId {
|
|
id(base::MIN_LOOP, 1000 + offset)
|
|
}
|
|
}
|
|
|
|
/// ValueId helpers for skip_ws lowering module
|
|
pub mod skip_ws {
|
|
use super::{base, id};
|
|
use crate::mir::ValueId;
|
|
|
|
/// Entry function ValueIds (3000-3999)
|
|
#[inline]
|
|
pub const fn entry(offset: u32) -> ValueId {
|
|
id(base::SKIP_WS, offset)
|
|
}
|
|
|
|
/// Loop function ValueIds (4000-4999)
|
|
#[inline]
|
|
pub const fn loop_step(offset: u32) -> ValueId {
|
|
id(base::SKIP_WS, 1000 + offset)
|
|
}
|
|
}
|
|
|
|
/// ValueId helpers for funcscanner_trim lowering module
|
|
pub mod funcscanner_trim {
|
|
use super::{base, id};
|
|
use crate::mir::ValueId;
|
|
|
|
/// Entry function ValueIds (5000-5999)
|
|
#[inline]
|
|
pub const fn entry(offset: u32) -> ValueId {
|
|
id(base::FUNCSCANNER_TRIM, offset)
|
|
}
|
|
|
|
/// Loop function ValueIds (6000-6999)
|
|
#[inline]
|
|
pub const fn loop_step(offset: u32) -> ValueId {
|
|
id(base::FUNCSCANNER_TRIM, 1000 + offset)
|
|
}
|
|
}
|
|
|
|
/// ValueId helpers for stage1_using_resolver lowering module
|
|
pub mod stage1_using_resolver {
|
|
use super::{base, id};
|
|
use crate::mir::ValueId;
|
|
|
|
/// Entry function ValueIds (7000-7999)
|
|
#[inline]
|
|
pub const fn entry(offset: u32) -> ValueId {
|
|
id(base::STAGE1_USING_RESOLVER, offset)
|
|
}
|
|
|
|
/// Loop function ValueIds (8000-8999)
|
|
#[inline]
|
|
pub const fn loop_step(offset: u32) -> ValueId {
|
|
id(base::STAGE1_USING_RESOLVER, 1000 + offset)
|
|
}
|
|
}
|
|
|
|
/// ValueId helpers for funcscanner_append_defs lowering module
|
|
pub mod funcscanner_append_defs {
|
|
use super::{base, id};
|
|
use crate::mir::ValueId;
|
|
|
|
/// Entry function ValueIds (9000-9999)
|
|
#[inline]
|
|
pub const fn entry(offset: u32) -> ValueId {
|
|
id(base::FUNCSCANNER_APPEND_DEFS, offset)
|
|
}
|
|
|
|
/// Loop function ValueIds (10000-10999)
|
|
#[inline]
|
|
pub const fn loop_step(offset: u32) -> ValueId {
|
|
id(base::FUNCSCANNER_APPEND_DEFS, 1000 + offset)
|
|
}
|
|
}
|
|
|
|
/// ValueId helpers for Stage-B body extractor lowering module
|
|
pub mod stageb_body_extract {
|
|
use super::{base, id};
|
|
use crate::mir::ValueId;
|
|
|
|
/// Entry function ValueIds (11000-11999)
|
|
#[inline]
|
|
pub const fn entry(offset: u32) -> ValueId {
|
|
id(base::STAGEB_BODY_EXTRACT, offset)
|
|
}
|
|
|
|
/// Loop function ValueIds (12000-12999)
|
|
#[inline]
|
|
pub const fn loop_step(offset: u32) -> ValueId {
|
|
id(base::STAGEB_BODY_EXTRACT, 1000 + offset)
|
|
}
|
|
}
|
|
|
|
/// ValueId helpers for Stage-B FuncScanner lowering module
|
|
pub mod stageb_funcscanner {
|
|
use super::{base, id};
|
|
use crate::mir::ValueId;
|
|
|
|
/// Entry function ValueIds (13000-13999)
|
|
#[inline]
|
|
pub const fn entry(offset: u32) -> ValueId {
|
|
id(base::STAGEB_FUNCSCANNER, offset)
|
|
}
|
|
|
|
/// Loop function ValueIds (14000-14999)
|
|
#[inline]
|
|
pub const fn loop_step(offset: u32) -> ValueId {
|
|
id(base::STAGEB_FUNCSCANNER, 1000 + offset)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
/// Macro to test ValueId range boundaries for a lowering module
|
|
///
|
|
/// Verifies that entry(0) and loop_step(999) produce the expected ValueIds
|
|
/// based on the module's allocated range.
|
|
macro_rules! test_value_id_range {
|
|
($module:ident, $entry_base:expr, $loop_base:expr) => {
|
|
assert_eq!(
|
|
$module::entry(0).0,
|
|
$entry_base,
|
|
"{} entry(0) should be {}",
|
|
stringify!($module),
|
|
$entry_base
|
|
);
|
|
assert_eq!(
|
|
$module::loop_step(999).0,
|
|
$loop_base + 999,
|
|
"{} loop_step(999) should be {}",
|
|
stringify!($module),
|
|
$loop_base + 999
|
|
);
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn test_value_id_ranges_no_overlap() {
|
|
// Test each module's range boundaries
|
|
test_value_id_range!(min_loop, 1000, 2000);
|
|
test_value_id_range!(skip_ws, 3000, 4000);
|
|
test_value_id_range!(funcscanner_trim, 5000, 6000);
|
|
test_value_id_range!(stage1_using_resolver, 7000, 8000);
|
|
test_value_id_range!(funcscanner_append_defs, 9000, 10000);
|
|
test_value_id_range!(stageb_body_extract, 11000, 12000);
|
|
test_value_id_range!(stageb_funcscanner, 13000, 14000);
|
|
|
|
// Automated overlap detection
|
|
// Each range is 2000 units: (base, base+1999)
|
|
let ranges = vec![
|
|
(1000, 2999), // min_loop
|
|
(3000, 4999), // skip_ws
|
|
(5000, 6999), // funcscanner_trim
|
|
(7000, 8999), // stage1_using_resolver
|
|
(9000, 10999), // funcscanner_append_defs
|
|
(11000, 12999), // stageb_body_extract
|
|
(13000, 14999), // stageb_funcscanner
|
|
];
|
|
|
|
// Verify no overlaps between consecutive ranges
|
|
for i in 0..ranges.len() - 1 {
|
|
let (_, end_i) = ranges[i];
|
|
let (start_next, _) = ranges[i + 1];
|
|
assert!(
|
|
end_i < start_next,
|
|
"Overlap detected: range {} ends at {} but range {} starts at {}",
|
|
i,
|
|
end_i,
|
|
i + 1,
|
|
start_next
|
|
);
|
|
}
|
|
}
|
|
}
|