@@ -21,18 +21,33 @@ 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
2730 }
2831}
2932
33+ impl From < VRegId > for usize {
34+ fn from ( val : VRegId ) -> Self {
35+ val. 0
36+ }
37+ }
38+
3039impl std:: fmt:: Display for BlockId {
3140 fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
3241 write ! ( f, "l{}" , self . 0 )
3342 }
3443}
3544
45+ impl std:: fmt:: Display for VRegId {
46+ fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
47+ write ! ( f, "v{}" , self . 0 )
48+ }
49+ }
50+
3651/// Dummy HIR block ID used when creating test or invalid LIR blocks
3752const DUMMY_HIR_BLOCK_ID : usize = usize:: MAX ;
3853/// Dummy RPO index used when creating test or invalid LIR blocks
@@ -131,7 +146,7 @@ pub enum MemBase
131146 /// Register: Every Opnd::Mem should have MemBase::Reg as of emit.
132147 Reg ( u8 ) ,
133148 /// Virtual register: Lowered to MemBase::Reg or MemBase::Stack in alloc_regs.
134- VReg ( usize ) ,
149+ VReg ( VRegId ) ,
135150 /// Stack slot: Lowered to MemBase::Reg in scratch_split.
136151 Stack { stack_idx : usize , num_bits : u8 } ,
137152}
@@ -158,7 +173,7 @@ impl fmt::Display for Mem {
158173 write ! ( f, "[" ) ?;
159174 match self . base {
160175 MemBase :: Reg ( reg_no) => write ! ( f, "{}" , mem_base_reg( reg_no) ) ?,
161- MemBase :: VReg ( idx) => write ! ( f, "v {idx}" ) ?,
176+ MemBase :: VReg ( idx) => write ! ( f, "{idx}" ) ?,
162177 MemBase :: Stack { stack_idx, num_bits } if num_bits == 64 => write ! ( f, "Stack[{stack_idx}]" ) ?,
163178 MemBase :: Stack { stack_idx, num_bits } => write ! ( f, "Stack{num_bits}[{stack_idx}]" ) ?,
164179 }
@@ -196,7 +211,7 @@ pub enum Opnd
196211 Value ( VALUE ) ,
197212
198213 /// Virtual register. Lowered to Reg or Mem in Assembler::alloc_regs().
199- VReg { idx : usize , num_bits : u8 } ,
214+ VReg { idx : VRegId , num_bits : u8 } ,
200215
201216 // Low-level operands, for lowering
202217 Imm ( i64 ) , // Raw signed immediate
@@ -212,8 +227,8 @@ impl fmt::Display for Opnd {
212227 None => write ! ( f, "None" ) ,
213228 Value ( VALUE ( value) ) if * value < 10 => write ! ( f, "Value({value:x})" ) ,
214229 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})" ) ,
230+ VReg { idx, num_bits } if * num_bits == 64 => write ! ( f, "{idx}" ) ,
231+ VReg { idx, num_bits } => write ! ( f, "VReg{num_bits}({idx})" ) ,
217232 Imm ( value) if value. abs ( ) < 10 => write ! ( f, "Imm({value:x})" ) ,
218233 Imm ( value) => write ! ( f, "Imm(0x{value:x})" ) ,
219234 UImm ( value) if * value < 10 => write ! ( f, "{value:x}" ) ,
@@ -282,7 +297,7 @@ impl Opnd
282297 }
283298
284299 /// Unwrap the index of a VReg
285- pub fn vreg_idx ( & self ) -> usize {
300+ pub fn vreg_idx ( & self ) -> VRegId {
286301 match self {
287302 Opnd :: VReg { idx, .. } => * idx,
288303 _ => unreachable ! ( "trying to unwrap {self:?} into VReg" ) ,
@@ -321,10 +336,10 @@ impl Opnd
321336 pub fn map_index ( self , indices : & [ usize ] ) -> Opnd {
322337 match self {
323338 Opnd :: VReg { idx, num_bits } => {
324- Opnd :: VReg { idx : indices[ idx] , num_bits }
339+ Opnd :: VReg { idx : VRegId ( indices[ idx. 0 ] ) , num_bits }
325340 }
326341 Opnd :: Mem ( Mem { base : MemBase :: VReg ( idx) , disp, num_bits } ) => {
327- Opnd :: Mem ( Mem { base : MemBase :: VReg ( indices[ idx] ) , disp, num_bits } )
342+ Opnd :: Mem ( Mem { base : MemBase :: VReg ( VRegId ( indices[ idx. 0 ] ) ) , disp, num_bits } )
328343 } ,
329344 _ => self
330345 }
@@ -1355,12 +1370,44 @@ impl LiveRange {
13551370 }
13561371}
13571372
1373+ /// Type-safe wrapper around Vec<LiveRange> that can be indexed by VRegId
1374+ #[ derive( Clone , Debug , Default ) ]
1375+ pub struct LiveRanges ( Vec < LiveRange > ) ;
1376+
1377+ impl std:: ops:: Index < VRegId > for LiveRanges {
1378+ type Output = LiveRange ;
1379+
1380+ fn index ( & self , idx : VRegId ) -> & Self :: Output {
1381+ & self . 0 [ idx. 0 ]
1382+ }
1383+ }
1384+
1385+ impl std:: ops:: IndexMut < VRegId > for LiveRanges {
1386+ fn index_mut ( & mut self , idx : VRegId ) -> & mut Self :: Output {
1387+ & mut self . 0 [ idx. 0 ]
1388+ }
1389+ }
1390+
1391+ impl std:: ops:: Deref for LiveRanges {
1392+ type Target = Vec < LiveRange > ;
1393+
1394+ fn deref ( & self ) -> & Self :: Target {
1395+ & self . 0
1396+ }
1397+ }
1398+
1399+ impl std:: ops:: DerefMut for LiveRanges {
1400+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
1401+ & mut self . 0
1402+ }
1403+ }
1404+
13581405/// StackState manages which stack slots are used by which VReg
13591406pub struct StackState {
13601407 /// The maximum number of spilled VRegs at a time
13611408 stack_size : usize ,
13621409 /// Map from index at the C stack for spilled VRegs to Some(vreg_idx) if allocated
1363- stack_slots : Vec < Option < usize > > ,
1410+ stack_slots : Vec < Option < VRegId > > ,
13641411 /// Copy of Assembler::stack_base_idx. Used for calculating stack slot offsets.
13651412 stack_base_idx : usize ,
13661413}
@@ -1376,7 +1423,7 @@ impl StackState {
13761423 }
13771424
13781425 /// Allocate a stack slot for a given vreg_idx
1379- fn alloc_stack ( & mut self , vreg_idx : usize ) -> Opnd {
1426+ fn alloc_stack ( & mut self , vreg_idx : VRegId ) -> Opnd {
13801427 for stack_idx in 0 ..self . stack_size {
13811428 if self . stack_slots [ stack_idx] . is_none ( ) {
13821429 self . stack_slots [ stack_idx] = Some ( vreg_idx) ;
@@ -1437,7 +1484,7 @@ struct RegisterPool {
14371484
14381485 /// Some(vreg_idx) if the register at the index in `pool` is used by the VReg.
14391486 /// None if the register is not in use.
1440- pool : Vec < Option < usize > > ,
1487+ pool : Vec < Option < VRegId > > ,
14411488
14421489 /// The number of live registers.
14431490 /// Provides a quick way to query `pool.filter(|r| r.is_some()).count()`
@@ -1461,7 +1508,7 @@ impl RegisterPool {
14611508
14621509 /// Mutate the pool to indicate that the register at the index
14631510 /// has been allocated and is live.
1464- fn alloc_opnd ( & mut self , vreg_idx : usize ) -> Opnd {
1511+ fn alloc_opnd ( & mut self , vreg_idx : VRegId ) -> Opnd {
14651512 for ( reg_idx, reg) in self . regs . iter ( ) . enumerate ( ) {
14661513 if self . pool [ reg_idx] . is_none ( ) {
14671514 self . pool [ reg_idx] = Some ( vreg_idx) ;
@@ -1473,7 +1520,7 @@ impl RegisterPool {
14731520 }
14741521
14751522 /// Allocate a specific register
1476- fn take_reg ( & mut self , reg : & Reg , vreg_idx : usize ) -> Opnd {
1523+ fn take_reg ( & mut self , reg : & Reg , vreg_idx : VRegId ) -> Opnd {
14771524 let reg_idx = self . regs . iter ( ) . position ( |elem| elem. reg_no == reg. reg_no )
14781525 . unwrap_or_else ( || panic ! ( "Unable to find register: {}" , reg. reg_no) ) ;
14791526 assert_eq ! ( self . pool[ reg_idx] , None , "register already allocated for VReg({:?})" , self . pool[ reg_idx] ) ;
@@ -1499,7 +1546,7 @@ impl RegisterPool {
14991546 }
15001547
15011548 /// Return a list of (Reg, vreg_idx) tuples for all live registers
1502- fn live_regs ( & self ) -> Vec < ( Reg , usize ) > {
1549+ fn live_regs ( & self ) -> Vec < ( Reg , VRegId ) > {
15031550 let mut live_regs = Vec :: with_capacity ( self . live_regs ) ;
15041551 for ( reg_idx, & reg) in self . regs . iter ( ) . enumerate ( ) {
15051552 if let Some ( vreg_idx) = self . pool [ reg_idx] {
@@ -1510,7 +1557,7 @@ impl RegisterPool {
15101557 }
15111558
15121559 /// Return vreg_idx if a given register is already in use
1513- fn vreg_for ( & self , reg : & Reg ) -> Option < usize > {
1560+ fn vreg_for ( & self , reg : & Reg ) -> Option < VRegId > {
15141561 let reg_idx = self . regs . iter ( ) . position ( |elem| elem. reg_no == reg. reg_no ) . unwrap ( ) ;
15151562 self . pool [ reg_idx]
15161563 }
@@ -1536,7 +1583,7 @@ pub struct Assembler {
15361583 current_block_id : BlockId ,
15371584
15381585 /// Live range for each VReg indexed by its `idx``
1539- pub ( super ) live_ranges : Vec < LiveRange > ,
1586+ pub ( super ) live_ranges : LiveRanges ,
15401587
15411588 /// Names of labels
15421589 pub ( super ) label_names : Vec < String > ,
@@ -1568,7 +1615,7 @@ impl Assembler
15681615 leaf_ccall_stack_size : None ,
15691616 basic_blocks : Vec :: default ( ) ,
15701617 current_block_id : BlockId ( 0 ) ,
1571- live_ranges : Vec :: default ( ) ,
1618+ live_ranges : LiveRanges :: default ( ) ,
15721619 idx : 0 ,
15731620 }
15741621 }
@@ -1780,7 +1827,7 @@ impl Assembler
17801827
17811828 /// Build an Opnd::VReg and initialize its LiveRange
17821829 pub ( super ) fn new_vreg ( & mut self , num_bits : u8 ) -> Opnd {
1783- let vreg = Opnd :: VReg { idx : self . live_ranges . len ( ) , num_bits } ;
1830+ let vreg = Opnd :: VReg { idx : VRegId ( self . live_ranges . len ( ) ) , num_bits } ;
17841831 self . live_ranges . push ( LiveRange { start : None , end : None } ) ;
17851832 vreg
17861833 }
@@ -1794,7 +1841,7 @@ impl Assembler
17941841
17951842 // Initialize the live range of the output VReg to insn_idx..=insn_idx
17961843 if let Some ( Opnd :: VReg { idx, .. } ) = insn. out_opnd ( ) {
1797- assert ! ( * idx < self . live_ranges. len( ) ) ;
1844+ assert ! ( idx. 0 < self . live_ranges. len( ) ) ;
17981845 assert_eq ! ( self . live_ranges[ * idx] , LiveRange { start: None , end: None } ) ;
17991846 self . live_ranges [ * idx] = LiveRange { start : Some ( insn_idx) , end : Some ( insn_idx) } ;
18001847 }
@@ -1805,7 +1852,7 @@ impl Assembler
18051852 match * opnd {
18061853 Opnd :: VReg { idx, .. } |
18071854 Opnd :: Mem ( Mem { base : MemBase :: VReg ( idx) , .. } ) => {
1808- assert ! ( idx < self . live_ranges. len( ) ) ;
1855+ assert ! ( idx. 0 < self . live_ranges. len( ) ) ;
18091856 assert_ne ! ( self . live_ranges[ idx] . end, None ) ;
18101857 self . live_ranges [ idx] . end = Some ( self . live_ranges [ idx] . end ( ) . max ( insn_idx) ) ;
18111858 }
@@ -1894,7 +1941,7 @@ impl Assembler
18941941 let mut vreg_opnd: Vec < Option < Opnd > > = vec ! [ None ; self . live_ranges. len( ) ] ;
18951942
18961943 // List of registers saved before a C call, paired with the VReg index.
1897- let mut saved_regs: Vec < ( Reg , usize ) > = vec ! [ ] ;
1944+ let mut saved_regs: Vec < ( Reg , VRegId ) > = vec ! [ ] ;
18981945
18991946 // Remember the indexes of Insn::FrameSetup to update the stack size later
19001947 let mut frame_setup_idxs: Vec < ( BlockId , usize ) > = vec ! [ ] ;
@@ -1924,7 +1971,7 @@ impl Assembler
19241971 let new_opnd = pool. alloc_opnd ( vreg_idx) ;
19251972 asm. mov ( new_opnd, C_RET_OPND ) ;
19261973 pool. dealloc_opnd ( & Opnd :: Reg ( C_RET_REG ) ) ;
1927- vreg_opnd[ vreg_idx] = Some ( new_opnd) ;
1974+ vreg_opnd[ vreg_idx. 0 ] = Some ( new_opnd) ;
19281975 }
19291976
19301977 true
@@ -1942,8 +1989,8 @@ impl Assembler
19421989 // We're going to check if this is the last instruction that
19431990 // uses this operand. If it is, we can return the allocated
19441991 // register to the pool.
1945- if live_ranges[ idx] . end ( ) == index {
1946- if let Some ( opnd) = vreg_opnd[ idx] {
1992+ if live_ranges[ idx. 0 ] . end ( ) == index {
1993+ if let Some ( opnd) = vreg_opnd[ idx. 0 ] {
19471994 pool. dealloc_opnd ( & opnd) ;
19481995 } else {
19491996 unreachable ! ( "no register allocated for insn {:?}" , insn) ;
@@ -1986,8 +2033,8 @@ impl Assembler
19862033 _ => None ,
19872034 } ;
19882035 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 ) ;
2036+ if live_ranges[ vreg_idx. 0 ] . end ( ) == index {
2037+ debug ! ( "Allocating a register for {vreg_idx} at instruction index {index } even though it does not live past this index" ) ;
19912038 }
19922039 // This is going to be the output operand that we will set on the
19932040 // instruction. CCall and LiveReg need to use a specific register.
@@ -2011,8 +2058,8 @@ impl Assembler
20112058 let mut opnd_iter = insn. opnd_iter ( ) ;
20122059
20132060 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] {
2061+ if live_ranges[ idx. 0 ] . end ( ) == index {
2062+ if let Some ( Opnd :: Reg ( reg) ) = vreg_opnd[ idx. 0 ] {
20162063 out_reg = Some ( pool. take_reg ( & reg, vreg_idx) ) ;
20172064 }
20182065 }
@@ -2031,7 +2078,7 @@ impl Assembler
20312078 // extends beyond the index of the instruction.
20322079 let out = insn. out_opnd_mut ( ) . unwrap ( ) ;
20332080 let out_opnd = out_opnd. with_num_bits ( out_num_bits) ;
2034- vreg_opnd[ out. vreg_idx ( ) ] = Some ( out_opnd) ;
2081+ vreg_opnd[ out. vreg_idx ( ) . 0 ] = Some ( out_opnd) ;
20352082 * out = out_opnd;
20362083 }
20372084
@@ -2040,10 +2087,10 @@ impl Assembler
20402087 while let Some ( opnd) = opnd_iter. next ( ) {
20412088 match * opnd {
20422089 Opnd :: VReg { idx, num_bits } => {
2043- * opnd = vreg_opnd[ idx] . unwrap ( ) . with_num_bits ( num_bits) ;
2090+ * opnd = vreg_opnd[ idx. 0 ] . unwrap ( ) . with_num_bits ( num_bits) ;
20442091 } ,
20452092 Opnd :: Mem ( Mem { base : MemBase :: VReg ( idx) , disp, num_bits } ) => {
2046- * opnd = match vreg_opnd[ idx] . unwrap ( ) {
2093+ * opnd = match vreg_opnd[ idx. 0 ] . unwrap ( ) {
20472094 Opnd :: Reg ( reg) => Opnd :: Mem ( Mem { base : MemBase :: Reg ( reg. reg_no ) , disp, num_bits } ) ,
20482095 // If the base is spilled, lower it to MemBase::Stack, which scratch_split will lower to MemBase::Reg.
20492096 Opnd :: Mem ( mem) => Opnd :: Mem ( Mem { base : pool. stack_state . mem_to_stack_membase ( mem) , disp, num_bits } ) ,
@@ -2057,8 +2104,8 @@ impl Assembler
20572104 // If we have an output that dies at its definition (it is unused), free up the
20582105 // register
20592106 if let Some ( idx) = vreg_idx {
2060- if live_ranges[ idx] . end ( ) == index {
2061- if let Some ( opnd) = vreg_opnd[ idx] {
2107+ if live_ranges[ idx. 0 ] . end ( ) == index {
2108+ if let Some ( opnd) = vreg_opnd[ idx. 0 ] {
20622109 pool. dealloc_opnd ( & opnd) ;
20632110 } else {
20642111 unreachable ! ( "no register allocated for insn {:?}" , insn) ;
0 commit comments