Fixes test compilation errors caused by adding callee: Option<Callee> field to MirInstruction::Call in previous commits. Changes: - tests/mir_instruction_unit.rs: - Add callee: None to all Call instruction constructions - Ensures backward compatibility with existing tests - src/mir/instruction/tests.rs: - Add callee: None to Call instruction in phi_merge_if test - Maintains test correctness after Call signature change - src/mir/value_id.rs: - Add ValueId::INVALID constant (u32::MAX) - Provides clear sentinel value for invalid/placeholder IDs - src/mir/phi_core/loopform_builder.rs: - Replace deprecated ValueId::from() with ValueId::new() - Replace deprecated BasicBlockId::from() with BasicBlockId::new() - Ensures consistency with updated ID construction patterns Test Status: - Original errors from our commit: 6 → 0 ✅ - Remaining errors: 45 (pre-existing, unrelated to our changes) - 14: Missing interpreter module (legacy) - 11: Missing VM in backend::vm (moved) - 7: Missing jit module (archived) - 5: Missing MirInterpreter methods (legacy) - 4: Missing Box operator methods (pre-existing) All test errors related to LocalSSA and Call instruction changes are resolved. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
201 lines
4.2 KiB
Rust
201 lines
4.2 KiB
Rust
/*!
|
|
* MIR Value ID System - SSA value tracking
|
|
*
|
|
* Implements unique identifiers for SSA values with type safety
|
|
*/
|
|
|
|
use std::fmt;
|
|
|
|
/// Unique identifier for SSA values within a function
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
pub struct ValueId(pub u32);
|
|
|
|
impl ValueId {
|
|
/// Invalid/uninitialized ValueId sentinel
|
|
pub const INVALID: Self = ValueId(u32::MAX);
|
|
|
|
/// Create a new ValueId
|
|
pub fn new(id: u32) -> Self {
|
|
ValueId(id)
|
|
}
|
|
|
|
/// Get the raw ID value
|
|
pub fn as_u32(self) -> u32 {
|
|
self.0
|
|
}
|
|
|
|
/// Create ValueId from usize (for array indexing)
|
|
pub fn from_usize(id: usize) -> Self {
|
|
ValueId(id as u32)
|
|
}
|
|
|
|
/// Convert to usize (for array indexing)
|
|
pub fn to_usize(self) -> usize {
|
|
self.0 as usize
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for ValueId {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "%{}", self.0)
|
|
}
|
|
}
|
|
|
|
/// Local variable identifier (before SSA conversion)
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub struct LocalId(pub u32);
|
|
|
|
impl LocalId {
|
|
/// Create a new LocalId
|
|
pub fn new(id: u32) -> Self {
|
|
LocalId(id)
|
|
}
|
|
|
|
/// Get the raw ID value
|
|
pub fn as_u32(self) -> u32 {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for LocalId {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "local_{}", self.0)
|
|
}
|
|
}
|
|
|
|
/// Value ID generator for unique SSA value creation
|
|
#[derive(Debug, Clone)]
|
|
pub struct ValueIdGenerator {
|
|
next_id: u32,
|
|
}
|
|
|
|
impl ValueIdGenerator {
|
|
/// Create a new generator starting from 0
|
|
pub fn new() -> Self {
|
|
Self { next_id: 0 }
|
|
}
|
|
|
|
/// Generate the next unique ValueId
|
|
pub fn next(&mut self) -> ValueId {
|
|
let id = ValueId(self.next_id);
|
|
self.next_id += 1;
|
|
id
|
|
}
|
|
|
|
/// Peek at the next ID without consuming it
|
|
pub fn peek_next(&self) -> ValueId {
|
|
ValueId(self.next_id)
|
|
}
|
|
|
|
/// Reset the generator (for testing)
|
|
pub fn reset(&mut self) {
|
|
self.next_id = 0;
|
|
}
|
|
}
|
|
|
|
impl Default for ValueIdGenerator {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
/// Local ID generator for variable naming
|
|
#[derive(Debug, Clone)]
|
|
pub struct LocalIdGenerator {
|
|
next_id: u32,
|
|
}
|
|
|
|
impl LocalIdGenerator {
|
|
/// Create a new generator starting from 0
|
|
pub fn new() -> Self {
|
|
Self { next_id: 0 }
|
|
}
|
|
|
|
/// Generate the next unique LocalId
|
|
pub fn next(&mut self) -> LocalId {
|
|
let id = LocalId(self.next_id);
|
|
self.next_id += 1;
|
|
id
|
|
}
|
|
|
|
/// Reset the generator (for testing)
|
|
pub fn reset(&mut self) {
|
|
self.next_id = 0;
|
|
}
|
|
}
|
|
|
|
impl Default for LocalIdGenerator {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_value_id_creation() {
|
|
let id1 = ValueId::new(0);
|
|
let id2 = ValueId::new(1);
|
|
|
|
assert_eq!(id1.as_u32(), 0);
|
|
assert_eq!(id2.as_u32(), 1);
|
|
assert_ne!(id1, id2);
|
|
|
|
assert_eq!(format!("{}", id1), "%0");
|
|
assert_eq!(format!("{}", id2), "%1");
|
|
}
|
|
|
|
#[test]
|
|
fn test_value_id_generator() {
|
|
let mut gen = ValueIdGenerator::new();
|
|
|
|
let id1 = gen.next();
|
|
let id2 = gen.next();
|
|
let id3 = gen.next();
|
|
|
|
assert_eq!(id1, ValueId(0));
|
|
assert_eq!(id2, ValueId(1));
|
|
assert_eq!(id3, ValueId(2));
|
|
|
|
assert_eq!(gen.peek_next(), ValueId(3));
|
|
}
|
|
|
|
#[test]
|
|
fn test_local_id_creation() {
|
|
let local1 = LocalId::new(0);
|
|
let local2 = LocalId::new(1);
|
|
|
|
assert_eq!(format!("{}", local1), "local_0");
|
|
assert_eq!(format!("{}", local2), "local_1");
|
|
}
|
|
|
|
#[test]
|
|
fn test_local_id_generator() {
|
|
let mut gen = LocalIdGenerator::new();
|
|
|
|
let local1 = gen.next();
|
|
let local2 = gen.next();
|
|
|
|
assert_eq!(local1, LocalId(0));
|
|
assert_eq!(local2, LocalId(1));
|
|
}
|
|
|
|
#[test]
|
|
fn test_value_id_ordering() {
|
|
let id1 = ValueId(1);
|
|
let id2 = ValueId(2);
|
|
let id3 = ValueId(3);
|
|
|
|
assert!(id1 < id2);
|
|
assert!(id2 < id3);
|
|
assert!(id1 < id3);
|
|
|
|
let mut ids = vec![id3, id1, id2];
|
|
ids.sort();
|
|
|
|
assert_eq!(ids, vec![id1, id2, id3]);
|
|
}
|
|
}
|