11//! MIR definitions and implementation
22
3- use std:: { fmt:: Display , iter} ;
3+ use std:: { collections :: hash_map :: Entry , fmt:: Display , iter} ;
44
55use crate :: {
66 consteval:: usize_const,
@@ -37,6 +37,7 @@ pub use monomorphization::{
3737 monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query,
3838 monomorphized_mir_body_query, monomorphized_mir_body_recover,
3939} ;
40+ use rustc_hash:: FxHashMap ;
4041use smallvec:: { smallvec, SmallVec } ;
4142use stdx:: { impl_from, never} ;
4243use triomphe:: Arc ;
@@ -223,35 +224,93 @@ impl<V, T> ProjectionElem<V, T> {
223224
224225type PlaceElem = ProjectionElem < LocalId , Ty > ;
225226
227+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
228+ pub struct ProjectionId ( u32 ) ;
229+
230+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
231+ pub struct ProjectionStore {
232+ id_to_proj : FxHashMap < ProjectionId , Box < [ PlaceElem ] > > ,
233+ proj_to_id : FxHashMap < Box < [ PlaceElem ] > , ProjectionId > ,
234+ }
235+
236+ impl Default for ProjectionStore {
237+ fn default ( ) -> Self {
238+ let mut this = Self { id_to_proj : Default :: default ( ) , proj_to_id : Default :: default ( ) } ;
239+ // Ensure that [] will get the id 0 which is used in `ProjectionId::Empty`
240+ this. intern ( Box :: new ( [ ] ) ) ;
241+ this
242+ }
243+ }
244+
245+ impl ProjectionStore {
246+ fn shrink_to_fit ( & mut self ) {
247+ self . id_to_proj . shrink_to_fit ( ) ;
248+ self . proj_to_id . shrink_to_fit ( ) ;
249+ }
250+
251+ fn intern_if_exist ( & self , projection : & [ PlaceElem ] ) -> Option < ProjectionId > {
252+ self . proj_to_id . get ( projection) . copied ( )
253+ }
254+
255+ fn intern ( & mut self , projection : Box < [ PlaceElem ] > ) -> ProjectionId {
256+ let new_id = ProjectionId ( self . proj_to_id . len ( ) as u32 ) ;
257+ match self . proj_to_id . entry ( projection) {
258+ Entry :: Occupied ( id) => * id. get ( ) ,
259+ Entry :: Vacant ( e) => {
260+ let key_clone = e. key ( ) . clone ( ) ;
261+ e. insert ( new_id) ;
262+ self . id_to_proj . insert ( new_id, key_clone) ;
263+ new_id
264+ }
265+ }
266+ }
267+ }
268+
269+ impl ProjectionId {
270+ const EMPTY : ProjectionId = ProjectionId ( 0 ) ;
271+
272+ fn lookup ( self , store : & ProjectionStore ) -> & [ PlaceElem ] {
273+ store. id_to_proj . get ( & self ) . unwrap ( )
274+ }
275+
276+ fn project ( self , projection : PlaceElem , store : & mut ProjectionStore ) -> ProjectionId {
277+ let mut current = self . lookup ( store) . to_vec ( ) ;
278+ current. push ( projection) ;
279+ store. intern ( current. into ( ) )
280+ }
281+ }
282+
226283#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
227284pub struct Place {
228285 pub local : LocalId ,
229- pub projection : Box < [ PlaceElem ] > ,
286+ pub projection : ProjectionId ,
230287}
231288
232289impl Place {
233- fn is_parent ( & self , child : & Place ) -> bool {
234- self . local == child. local && child. projection . starts_with ( & self . projection )
290+ fn is_parent ( & self , child : & Place , store : & ProjectionStore ) -> bool {
291+ self . local == child. local
292+ && child. projection . lookup ( store) . starts_with ( & self . projection . lookup ( store) )
235293 }
236294
237295 /// The place itself is not included
238- fn iterate_over_parents ( & self ) -> impl Iterator < Item = Place > + ' _ {
239- ( 0 ..self . projection . len ( ) )
240- . map ( |x| & self . projection [ 0 ..x] )
241- . map ( |x| Place { local : self . local , projection : x. to_vec ( ) . into ( ) } )
296+ fn iterate_over_parents < ' a > (
297+ & ' a self ,
298+ store : & ' a ProjectionStore ,
299+ ) -> impl Iterator < Item = Place > + ' a {
300+ let projection = self . projection . lookup ( store) ;
301+ ( 0 ..projection. len ( ) ) . map ( |x| & projection[ 0 ..x] ) . filter_map ( move |x| {
302+ Some ( Place { local : self . local , projection : store. intern_if_exist ( x) ? } )
303+ } )
242304 }
243305
244- fn project ( & self , projection : PlaceElem ) -> Place {
245- Place {
246- local : self . local ,
247- projection : self . projection . iter ( ) . cloned ( ) . chain ( [ projection] ) . collect ( ) ,
248- }
306+ fn project ( & self , projection : PlaceElem , store : & mut ProjectionStore ) -> Place {
307+ Place { local : self . local , projection : self . projection . project ( projection, store) }
249308 }
250309}
251310
252311impl From < LocalId > for Place {
253312 fn from ( local : LocalId ) -> Self {
254- Self { local, projection : vec ! [ ] . into ( ) }
313+ Self { local, projection : ProjectionId :: EMPTY }
255314 }
256315}
257316
@@ -997,6 +1056,7 @@ pub struct BasicBlock {
9971056
9981057#[ derive( Debug , Clone , PartialEq , Eq ) ]
9991058pub struct MirBody {
1059+ pub projection_store : ProjectionStore ,
10001060 pub basic_blocks : Arena < BasicBlock > ,
10011061 pub locals : Arena < Local > ,
10021062 pub start_block : BasicBlockId ,
@@ -1009,11 +1069,15 @@ pub struct MirBody {
10091069}
10101070
10111071impl MirBody {
1012- fn walk_places ( & mut self , mut f : impl FnMut ( & mut Place ) ) {
1013- fn for_operand ( op : & mut Operand , f : & mut impl FnMut ( & mut Place ) ) {
1072+ fn walk_places ( & mut self , mut f : impl FnMut ( & mut Place , & mut ProjectionStore ) ) {
1073+ fn for_operand (
1074+ op : & mut Operand ,
1075+ f : & mut impl FnMut ( & mut Place , & mut ProjectionStore ) ,
1076+ store : & mut ProjectionStore ,
1077+ ) {
10141078 match op {
10151079 Operand :: Copy ( p) | Operand :: Move ( p) => {
1016- f ( p) ;
1080+ f ( p, store ) ;
10171081 }
10181082 Operand :: Constant ( _) | Operand :: Static ( _) => ( ) ,
10191083 }
@@ -1022,38 +1086,40 @@ impl MirBody {
10221086 for statement in & mut block. statements {
10231087 match & mut statement. kind {
10241088 StatementKind :: Assign ( p, r) => {
1025- f ( p) ;
1089+ f ( p, & mut self . projection_store ) ;
10261090 match r {
10271091 Rvalue :: ShallowInitBoxWithAlloc ( _) => ( ) ,
10281092 Rvalue :: ShallowInitBox ( o, _)
10291093 | Rvalue :: UnaryOp ( _, o)
10301094 | Rvalue :: Cast ( _, o, _)
10311095 | Rvalue :: Repeat ( o, _)
1032- | Rvalue :: Use ( o) => for_operand ( o, & mut f) ,
1096+ | Rvalue :: Use ( o) => for_operand ( o, & mut f, & mut self . projection_store ) ,
10331097 Rvalue :: CopyForDeref ( p)
10341098 | Rvalue :: Discriminant ( p)
10351099 | Rvalue :: Len ( p)
1036- | Rvalue :: Ref ( _, p) => f ( p) ,
1100+ | Rvalue :: Ref ( _, p) => f ( p, & mut self . projection_store ) ,
10371101 Rvalue :: CheckedBinaryOp ( _, o1, o2) => {
1038- for_operand ( o1, & mut f) ;
1039- for_operand ( o2, & mut f) ;
1102+ for_operand ( o1, & mut f, & mut self . projection_store ) ;
1103+ for_operand ( o2, & mut f, & mut self . projection_store ) ;
10401104 }
10411105 Rvalue :: Aggregate ( _, ops) => {
10421106 for op in ops. iter_mut ( ) {
1043- for_operand ( op, & mut f) ;
1107+ for_operand ( op, & mut f, & mut self . projection_store ) ;
10441108 }
10451109 }
10461110 }
10471111 }
1048- StatementKind :: Deinit ( p) => f ( p) ,
1112+ StatementKind :: Deinit ( p) => f ( p, & mut self . projection_store ) ,
10491113 StatementKind :: StorageLive ( _)
10501114 | StatementKind :: StorageDead ( _)
10511115 | StatementKind :: Nop => ( ) ,
10521116 }
10531117 }
10541118 match & mut block. terminator {
10551119 Some ( x) => match & mut x. kind {
1056- TerminatorKind :: SwitchInt { discr, .. } => for_operand ( discr, & mut f) ,
1120+ TerminatorKind :: SwitchInt { discr, .. } => {
1121+ for_operand ( discr, & mut f, & mut self . projection_store )
1122+ }
10571123 TerminatorKind :: FalseEdge { .. }
10581124 | TerminatorKind :: FalseUnwind { .. }
10591125 | TerminatorKind :: Goto { .. }
@@ -1063,23 +1129,24 @@ impl MirBody {
10631129 | TerminatorKind :: Return
10641130 | TerminatorKind :: Unreachable => ( ) ,
10651131 TerminatorKind :: Drop { place, .. } => {
1066- f ( place) ;
1132+ f ( place, & mut self . projection_store ) ;
10671133 }
10681134 TerminatorKind :: DropAndReplace { place, value, .. } => {
1069- f ( place) ;
1070- for_operand ( value, & mut f) ;
1135+ f ( place, & mut self . projection_store ) ;
1136+ for_operand ( value, & mut f, & mut self . projection_store ) ;
10711137 }
10721138 TerminatorKind :: Call { func, args, destination, .. } => {
1073- for_operand ( func, & mut f) ;
1074- args. iter_mut ( ) . for_each ( |x| for_operand ( x, & mut f) ) ;
1075- f ( destination) ;
1139+ for_operand ( func, & mut f, & mut self . projection_store ) ;
1140+ args. iter_mut ( )
1141+ . for_each ( |x| for_operand ( x, & mut f, & mut self . projection_store ) ) ;
1142+ f ( destination, & mut self . projection_store ) ;
10761143 }
10771144 TerminatorKind :: Assert { cond, .. } => {
1078- for_operand ( cond, & mut f) ;
1145+ for_operand ( cond, & mut f, & mut self . projection_store ) ;
10791146 }
10801147 TerminatorKind :: Yield { value, resume_arg, .. } => {
1081- for_operand ( value, & mut f) ;
1082- f ( resume_arg) ;
1148+ for_operand ( value, & mut f, & mut self . projection_store ) ;
1149+ f ( resume_arg, & mut self . projection_store ) ;
10831150 }
10841151 } ,
10851152 None => ( ) ,
@@ -1096,7 +1163,9 @@ impl MirBody {
10961163 binding_locals,
10971164 param_locals,
10981165 closures,
1166+ projection_store,
10991167 } = self ;
1168+ projection_store. shrink_to_fit ( ) ;
11001169 basic_blocks. shrink_to_fit ( ) ;
11011170 locals. shrink_to_fit ( ) ;
11021171 binding_locals. shrink_to_fit ( ) ;
0 commit comments