@@ -21,6 +21,9 @@ use crate::state::rb_zjit_record_exit_stack;
2121#[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug , PartialOrd , Ord ) ]
2222pub struct BlockId ( pub usize ) ;
2323
24+ #[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug , PartialOrd , Ord ) ]
25+ pub struct VRegId ( pub usize ) ;
26+
2427impl From < BlockId > for usize {
2528 fn from ( val : BlockId ) -> Self {
2629 val. 0
@@ -131,7 +134,7 @@ pub enum MemBase
131134 /// Register: Every Opnd::Mem should have MemBase::Reg as of emit.
132135 Reg ( u8 ) ,
133136 /// Virtual register: Lowered to MemBase::Reg or MemBase::Stack in alloc_regs.
134- VReg ( usize ) ,
137+ VReg ( VRegId ) ,
135138 /// Stack slot: Lowered to MemBase::Reg in scratch_split.
136139 Stack { stack_idx : usize , num_bits : u8 } ,
137140}
@@ -158,7 +161,7 @@ impl fmt::Display for Mem {
158161 write ! ( f, "[" ) ?;
159162 match self . base {
160163 MemBase :: Reg ( reg_no) => write ! ( f, "{}" , mem_base_reg( reg_no) ) ?,
161- MemBase :: VReg ( idx) => write ! ( f, "v{idx}" ) ?,
164+ MemBase :: VReg ( idx) => write ! ( f, "v{}" , idx . 0 ) ?,
162165 MemBase :: Stack { stack_idx, num_bits } if num_bits == 64 => write ! ( f, "Stack[{stack_idx}]" ) ?,
163166 MemBase :: Stack { stack_idx, num_bits } => write ! ( f, "Stack{num_bits}[{stack_idx}]" ) ?,
164167 }
@@ -196,7 +199,7 @@ pub enum Opnd
196199 Value ( VALUE ) ,
197200
198201 /// Virtual register. Lowered to Reg or Mem in Assembler::alloc_regs().
199- VReg { idx : usize , num_bits : u8 } ,
202+ VReg { idx : VRegId , num_bits : u8 } ,
200203
201204 // Low-level operands, for lowering
202205 Imm ( i64 ) , // Raw signed immediate
@@ -212,8 +215,8 @@ impl fmt::Display for Opnd {
212215 None => write ! ( f, "None" ) ,
213216 Value ( VALUE ( value) ) if * value < 10 => write ! ( f, "Value({value:x})" ) ,
214217 Value ( VALUE ( value) ) => write ! ( f, "Value(0x{value:x})" ) ,
215- VReg { idx, num_bits } if * num_bits == 64 => write ! ( f, "v{idx}" ) ,
216- VReg { idx, num_bits } => write ! ( f, "VReg{num_bits}(v{idx })" ) ,
218+ VReg { idx, num_bits } if * num_bits == 64 => write ! ( f, "v{}" , idx . 0 ) ,
219+ VReg { idx, num_bits } => write ! ( f, "VReg{num_bits}(v{})" , idx . 0 ) ,
217220 Imm ( value) if value. abs ( ) < 10 => write ! ( f, "Imm({value:x})" ) ,
218221 Imm ( value) => write ! ( f, "Imm(0x{value:x})" ) ,
219222 UImm ( value) if * value < 10 => write ! ( f, "{value:x}" ) ,
@@ -230,8 +233,8 @@ impl fmt::Debug for Opnd {
230233 match self {
231234 Self :: None => write ! ( fmt, "None" ) ,
232235 Value ( val) => write ! ( fmt, "Value({val:?})" ) ,
233- VReg { idx, num_bits } if * num_bits == 64 => write ! ( fmt, "VReg({idx })" ) ,
234- VReg { idx, num_bits } => write ! ( fmt, "VReg{num_bits}({idx })" ) ,
236+ VReg { idx, num_bits } if * num_bits == 64 => write ! ( fmt, "VReg({})" , idx . 0 ) ,
237+ VReg { idx, num_bits } => write ! ( fmt, "VReg{num_bits}({})" , idx . 0 ) ,
235238 Imm ( signed) => write ! ( fmt, "{signed:x}_i64" ) ,
236239 UImm ( unsigned) => write ! ( fmt, "{unsigned:x}_u64" ) ,
237240 // Say Mem and Reg only once
@@ -282,7 +285,7 @@ impl Opnd
282285 }
283286
284287 /// Unwrap the index of a VReg
285- pub fn vreg_idx ( & self ) -> usize {
288+ pub fn vreg_idx ( & self ) -> VRegId {
286289 match self {
287290 Opnd :: VReg { idx, .. } => * idx,
288291 _ => unreachable ! ( "trying to unwrap {self:?} into VReg" ) ,
@@ -321,10 +324,10 @@ impl Opnd
321324 pub fn map_index ( self , indices : & [ usize ] ) -> Opnd {
322325 match self {
323326 Opnd :: VReg { idx, num_bits } => {
324- Opnd :: VReg { idx : indices[ idx] , num_bits }
327+ Opnd :: VReg { idx : VRegId ( indices[ idx. 0 ] ) , num_bits }
325328 }
326329 Opnd :: Mem ( Mem { base : MemBase :: VReg ( idx) , disp, num_bits } ) => {
327- Opnd :: Mem ( Mem { base : MemBase :: VReg ( indices[ idx] ) , disp, num_bits } )
330+ Opnd :: Mem ( Mem { base : MemBase :: VReg ( VRegId ( indices[ idx. 0 ] ) ) , disp, num_bits } )
328331 } ,
329332 _ => self
330333 }
@@ -1355,12 +1358,44 @@ impl LiveRange {
13551358 }
13561359}
13571360
1361+ /// Type-safe wrapper around Vec<LiveRange> that can be indexed by VRegId
1362+ #[ derive( Clone , Debug , Default ) ]
1363+ pub struct LiveRanges ( Vec < LiveRange > ) ;
1364+
1365+ impl std:: ops:: Index < VRegId > for LiveRanges {
1366+ type Output = LiveRange ;
1367+
1368+ fn index ( & self , idx : VRegId ) -> & Self :: Output {
1369+ & self . 0 [ idx. 0 ]
1370+ }
1371+ }
1372+
1373+ impl std:: ops:: IndexMut < VRegId > for LiveRanges {
1374+ fn index_mut ( & mut self , idx : VRegId ) -> & mut Self :: Output {
1375+ & mut self . 0 [ idx. 0 ]
1376+ }
1377+ }
1378+
1379+ impl std:: ops:: Deref for LiveRanges {
1380+ type Target = Vec < LiveRange > ;
1381+
1382+ fn deref ( & self ) -> & Self :: Target {
1383+ & self . 0
1384+ }
1385+ }
1386+
1387+ impl std:: ops:: DerefMut for LiveRanges {
1388+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
1389+ & mut self . 0
1390+ }
1391+ }
1392+
13581393/// StackState manages which stack slots are used by which VReg
13591394pub struct StackState {
13601395 /// The maximum number of spilled VRegs at a time
13611396 stack_size : usize ,
13621397 /// Map from index at the C stack for spilled VRegs to Some(vreg_idx) if allocated
1363- stack_slots : Vec < Option < usize > > ,
1398+ stack_slots : Vec < Option < VRegId > > ,
13641399 /// Copy of Assembler::stack_base_idx. Used for calculating stack slot offsets.
13651400 stack_base_idx : usize ,
13661401}
@@ -1376,7 +1411,7 @@ impl StackState {
13761411 }
13771412
13781413 /// Allocate a stack slot for a given vreg_idx
1379- fn alloc_stack ( & mut self , vreg_idx : usize ) -> Opnd {
1414+ fn alloc_stack ( & mut self , vreg_idx : VRegId ) -> Opnd {
13801415 for stack_idx in 0 ..self . stack_size {
13811416 if self . stack_slots [ stack_idx] . is_none ( ) {
13821417 self . stack_slots [ stack_idx] = Some ( vreg_idx) ;
@@ -1437,7 +1472,7 @@ struct RegisterPool {
14371472
14381473 /// Some(vreg_idx) if the register at the index in `pool` is used by the VReg.
14391474 /// None if the register is not in use.
1440- pool : Vec < Option < usize > > ,
1475+ pool : Vec < Option < VRegId > > ,
14411476
14421477 /// The number of live registers.
14431478 /// Provides a quick way to query `pool.filter(|r| r.is_some()).count()`
@@ -1461,7 +1496,7 @@ impl RegisterPool {
14611496
14621497 /// Mutate the pool to indicate that the register at the index
14631498 /// has been allocated and is live.
1464- fn alloc_opnd ( & mut self , vreg_idx : usize ) -> Opnd {
1499+ fn alloc_opnd ( & mut self , vreg_idx : VRegId ) -> Opnd {
14651500 for ( reg_idx, reg) in self . regs . iter ( ) . enumerate ( ) {
14661501 if self . pool [ reg_idx] . is_none ( ) {
14671502 self . pool [ reg_idx] = Some ( vreg_idx) ;
@@ -1473,7 +1508,7 @@ impl RegisterPool {
14731508 }
14741509
14751510 /// Allocate a specific register
1476- fn take_reg ( & mut self , reg : & Reg , vreg_idx : usize ) -> Opnd {
1511+ fn take_reg ( & mut self , reg : & Reg , vreg_idx : VRegId ) -> Opnd {
14771512 let reg_idx = self . regs . iter ( ) . position ( |elem| elem. reg_no == reg. reg_no )
14781513 . unwrap_or_else ( || panic ! ( "Unable to find register: {}" , reg. reg_no) ) ;
14791514 assert_eq ! ( self . pool[ reg_idx] , None , "register already allocated for VReg({:?})" , self . pool[ reg_idx] ) ;
@@ -1499,7 +1534,7 @@ impl RegisterPool {
14991534 }
15001535
15011536 /// Return a list of (Reg, vreg_idx) tuples for all live registers
1502- fn live_regs ( & self ) -> Vec < ( Reg , usize ) > {
1537+ fn live_regs ( & self ) -> Vec < ( Reg , VRegId ) > {
15031538 let mut live_regs = Vec :: with_capacity ( self . live_regs ) ;
15041539 for ( reg_idx, & reg) in self . regs . iter ( ) . enumerate ( ) {
15051540 if let Some ( vreg_idx) = self . pool [ reg_idx] {
@@ -1510,7 +1545,7 @@ impl RegisterPool {
15101545 }
15111546
15121547 /// Return vreg_idx if a given register is already in use
1513- fn vreg_for ( & self , reg : & Reg ) -> Option < usize > {
1548+ fn vreg_for ( & self , reg : & Reg ) -> Option < VRegId > {
15141549 let reg_idx = self . regs . iter ( ) . position ( |elem| elem. reg_no == reg. reg_no ) . unwrap ( ) ;
15151550 self . pool [ reg_idx]
15161551 }
@@ -1536,7 +1571,7 @@ pub struct Assembler {
15361571 current_block_id : BlockId ,
15371572
15381573 /// Live range for each VReg indexed by its `idx``
1539- pub ( super ) live_ranges : Vec < LiveRange > ,
1574+ pub ( super ) live_ranges : LiveRanges ,
15401575
15411576 /// Names of labels
15421577 pub ( super ) label_names : Vec < String > ,
@@ -1568,7 +1603,7 @@ impl Assembler
15681603 leaf_ccall_stack_size : None ,
15691604 basic_blocks : Vec :: default ( ) ,
15701605 current_block_id : BlockId ( 0 ) ,
1571- live_ranges : Vec :: default ( ) ,
1606+ live_ranges : LiveRanges :: default ( ) ,
15721607 idx : 0 ,
15731608 }
15741609 }
@@ -1780,7 +1815,7 @@ impl Assembler
17801815
17811816 /// Build an Opnd::VReg and initialize its LiveRange
17821817 pub ( super ) fn new_vreg ( & mut self , num_bits : u8 ) -> Opnd {
1783- let vreg = Opnd :: VReg { idx : self . live_ranges . len ( ) , num_bits } ;
1818+ let vreg = Opnd :: VReg { idx : VRegId ( self . live_ranges . len ( ) ) , num_bits } ;
17841819 self . live_ranges . push ( LiveRange { start : None , end : None } ) ;
17851820 vreg
17861821 }
@@ -1794,7 +1829,7 @@ impl Assembler
17941829
17951830 // Initialize the live range of the output VReg to insn_idx..=insn_idx
17961831 if let Some ( Opnd :: VReg { idx, .. } ) = insn. out_opnd ( ) {
1797- assert ! ( * idx < self . live_ranges. len( ) ) ;
1832+ assert ! ( idx. 0 < self . live_ranges. len( ) ) ;
17981833 assert_eq ! ( self . live_ranges[ * idx] , LiveRange { start: None , end: None } ) ;
17991834 self . live_ranges [ * idx] = LiveRange { start : Some ( insn_idx) , end : Some ( insn_idx) } ;
18001835 }
@@ -1805,7 +1840,7 @@ impl Assembler
18051840 match * opnd {
18061841 Opnd :: VReg { idx, .. } |
18071842 Opnd :: Mem ( Mem { base : MemBase :: VReg ( idx) , .. } ) => {
1808- assert ! ( idx < self . live_ranges. len( ) ) ;
1843+ assert ! ( idx. 0 < self . live_ranges. len( ) ) ;
18091844 assert_ne ! ( self . live_ranges[ idx] . end, None ) ;
18101845 self . live_ranges [ idx] . end = Some ( self . live_ranges [ idx] . end ( ) . max ( insn_idx) ) ;
18111846 }
@@ -1894,7 +1929,7 @@ impl Assembler
18941929 let mut vreg_opnd: Vec < Option < Opnd > > = vec ! [ None ; self . live_ranges. len( ) ] ;
18951930
18961931 // List of registers saved before a C call, paired with the VReg index.
1897- let mut saved_regs: Vec < ( Reg , usize ) > = vec ! [ ] ;
1932+ let mut saved_regs: Vec < ( Reg , VRegId ) > = vec ! [ ] ;
18981933
18991934 // Remember the indexes of Insn::FrameSetup to update the stack size later
19001935 let mut frame_setup_idxs: Vec < ( BlockId , usize ) > = vec ! [ ] ;
@@ -1924,7 +1959,7 @@ impl Assembler
19241959 let new_opnd = pool. alloc_opnd ( vreg_idx) ;
19251960 asm. mov ( new_opnd, C_RET_OPND ) ;
19261961 pool. dealloc_opnd ( & Opnd :: Reg ( C_RET_REG ) ) ;
1927- vreg_opnd[ vreg_idx] = Some ( new_opnd) ;
1962+ vreg_opnd[ vreg_idx. 0 ] = Some ( new_opnd) ;
19281963 }
19291964
19301965 true
@@ -1942,8 +1977,8 @@ impl Assembler
19421977 // We're going to check if this is the last instruction that
19431978 // uses this operand. If it is, we can return the allocated
19441979 // register to the pool.
1945- if live_ranges[ idx] . end ( ) == index {
1946- if let Some ( opnd) = vreg_opnd[ idx] {
1980+ if live_ranges[ idx. 0 ] . end ( ) == index {
1981+ if let Some ( opnd) = vreg_opnd[ idx. 0 ] {
19471982 pool. dealloc_opnd ( & opnd) ;
19481983 } else {
19491984 unreachable ! ( "no register allocated for insn {:?}" , insn) ;
@@ -1986,8 +2021,8 @@ impl Assembler
19862021 _ => None ,
19872022 } ;
19882023 if let Some ( vreg_idx) = vreg_idx {
1989- if live_ranges[ vreg_idx] . end ( ) == index {
1990- debug ! ( "Allocating a register for VReg({}) at instruction index {} even though it does not live past this index" , vreg_idx, index) ;
2024+ if live_ranges[ vreg_idx. 0 ] . end ( ) == index {
2025+ debug ! ( "Allocating a register for VReg({}) at instruction index {} even though it does not live past this index" , vreg_idx. 0 , index) ;
19912026 }
19922027 // This is going to be the output operand that we will set on the
19932028 // instruction. CCall and LiveReg need to use a specific register.
@@ -2011,8 +2046,8 @@ impl Assembler
20112046 let mut opnd_iter = insn. opnd_iter ( ) ;
20122047
20132048 if let Some ( Opnd :: VReg { idx, .. } ) = opnd_iter. next ( ) {
2014- if live_ranges[ * idx] . end ( ) == index {
2015- if let Some ( Opnd :: Reg ( reg) ) = vreg_opnd[ * idx] {
2049+ if live_ranges[ idx. 0 ] . end ( ) == index {
2050+ if let Some ( Opnd :: Reg ( reg) ) = vreg_opnd[ idx. 0 ] {
20162051 out_reg = Some ( pool. take_reg ( & reg, vreg_idx) ) ;
20172052 }
20182053 }
@@ -2031,7 +2066,7 @@ impl Assembler
20312066 // extends beyond the index of the instruction.
20322067 let out = insn. out_opnd_mut ( ) . unwrap ( ) ;
20332068 let out_opnd = out_opnd. with_num_bits ( out_num_bits) ;
2034- vreg_opnd[ out. vreg_idx ( ) ] = Some ( out_opnd) ;
2069+ vreg_opnd[ out. vreg_idx ( ) . 0 ] = Some ( out_opnd) ;
20352070 * out = out_opnd;
20362071 }
20372072
@@ -2040,10 +2075,10 @@ impl Assembler
20402075 while let Some ( opnd) = opnd_iter. next ( ) {
20412076 match * opnd {
20422077 Opnd :: VReg { idx, num_bits } => {
2043- * opnd = vreg_opnd[ idx] . unwrap ( ) . with_num_bits ( num_bits) ;
2078+ * opnd = vreg_opnd[ idx. 0 ] . unwrap ( ) . with_num_bits ( num_bits) ;
20442079 } ,
20452080 Opnd :: Mem ( Mem { base : MemBase :: VReg ( idx) , disp, num_bits } ) => {
2046- * opnd = match vreg_opnd[ idx] . unwrap ( ) {
2081+ * opnd = match vreg_opnd[ idx. 0 ] . unwrap ( ) {
20472082 Opnd :: Reg ( reg) => Opnd :: Mem ( Mem { base : MemBase :: Reg ( reg. reg_no ) , disp, num_bits } ) ,
20482083 // If the base is spilled, lower it to MemBase::Stack, which scratch_split will lower to MemBase::Reg.
20492084 Opnd :: Mem ( mem) => Opnd :: Mem ( Mem { base : pool. stack_state . mem_to_stack_membase ( mem) , disp, num_bits } ) ,
@@ -2057,8 +2092,8 @@ impl Assembler
20572092 // If we have an output that dies at its definition (it is unused), free up the
20582093 // register
20592094 if let Some ( idx) = vreg_idx {
2060- if live_ranges[ idx] . end ( ) == index {
2061- if let Some ( opnd) = vreg_opnd[ idx] {
2095+ if live_ranges[ idx. 0 ] . end ( ) == index {
2096+ if let Some ( opnd) = vreg_opnd[ idx. 0 ] {
20622097 pool. dealloc_opnd ( & opnd) ;
20632098 } else {
20642099 unreachable ! ( "no register allocated for insn {:?}" , insn) ;
0 commit comments