Skip to main content

gcrecomp_core/recompiler/codegen/
register.rs

1//! Register Allocation
2//!
3//! This module provides register allocation for code generation, mapping PowerPC registers
4//! to Rust variables. In a full implementation, this would use graph coloring or linear scan
5//! algorithms for optimal register allocation.
6//!
7//! # Memory Optimizations
8//! - Uses `HashMap` for register mapping (efficient lookup)
9//! - String interning could be added for repeated register names
10//!
11//! # Allocation Strategy
12//! Currently uses a simple mapping strategy. A full implementation would:
13//! - Use graph coloring to minimize register pressure
14//! - Implement register spilling when registers are exhausted
15//! - Track register liveness to optimize allocation
16
17use std::collections::HashMap;
18
19/// Register allocator for mapping PowerPC registers to Rust variables.
20///
21/// Maps PowerPC general-purpose registers (r0-r31) to Rust variable names.
22/// In a full implementation, would use graph coloring or linear scan algorithms.
23pub struct RegisterAllocator {
24    /// Map from PowerPC register number to Rust variable name
25    register_map: HashMap<u8, String>,
26    /// Next temporary variable number (for unique variable names)
27    next_temp: usize,
28    /// List of spilled registers (registers moved to stack)
29    spilled_registers: Vec<u8>,
30}
31
32impl RegisterAllocator {
33    /// Create a new register allocator.
34    ///
35    /// # Returns
36    /// `RegisterAllocator` - New register allocator instance
37    ///
38    /// # Examples
39    /// ```rust
40    /// let mut allocator = RegisterAllocator::new();
41    /// ```
42    #[inline] // Constructor - simple, may be inlined
43    pub fn new() -> Self {
44        Self {
45            register_map: HashMap::new(),
46            next_temp: 0usize,
47            spilled_registers: Vec::new(),
48        }
49    }
50    
51    /// Allocate a Rust variable name for a PowerPC register.
52    ///
53    /// # Algorithm
54    /// Maps PowerPC register to Rust variable name. If register hasn't been allocated,
55    /// creates a new variable name. Otherwise, returns existing variable name.
56    ///
57    /// # Arguments
58    /// * `ppc_reg` - PowerPC register number (0-31)
59    ///
60    /// # Returns
61    /// `String` - Rust variable name for the register
62    ///
63    /// # Examples
64    /// ```rust
65    /// let var_name = allocator.allocate_register(3); // Returns "r3"
66    /// ```
67    #[inline] // Hot path - may be inlined
68    pub fn allocate_register(&mut self, ppc_reg: u8) -> String {
69        // Map PowerPC register to Rust variable
70        // In a full implementation, would use graph coloring or linear scan
71        self.register_map
72            .entry(ppc_reg)
73            .or_insert_with(|| {
74                let name: String = format!("r{}", ppc_reg);
75                self.next_temp = self.next_temp.wrapping_add(1);
76                name
77            })
78            .clone()
79    }
80    
81    /// Spill a register to the stack.
82    ///
83    /// # Algorithm
84    /// When registers are exhausted, spill a register to stack memory.
85    /// Returns a stack variable name for the spilled register.
86    ///
87    /// # Arguments
88    /// * `reg` - PowerPC register number to spill
89    ///
90    /// # Returns
91    /// `String` - Stack variable name for the spilled register
92    ///
93    /// # Examples
94    /// ```rust
95    /// let stack_var = allocator.spill_register(3); // Returns "spilled_r3"
96    /// ```
97    #[inline] // May be called frequently
98    pub fn spill_register(&mut self, reg: u8) -> String {
99        // Spill register to stack
100        let stack_var: String = format!("spilled_r{}", reg);
101        self.spilled_registers.push(reg);
102        stack_var
103    }
104}
105
106impl Default for RegisterAllocator {
107    #[inline] // Simple default implementation
108    fn default() -> Self {
109        Self::new()
110    }
111}