1- use crate :: mir:: graph_cyclic_cache:: GraphIsCyclicCache ;
2- use crate :: mir:: predecessors:: { PredecessorCache , Predecessors } ;
3- use crate :: mir:: switch_sources:: { SwitchSourceCache , SwitchSources } ;
4- use crate :: mir:: traversal:: PostorderCache ;
5- use crate :: mir:: { BasicBlock , BasicBlockData , Successors , START_BLOCK } ;
1+ use crate :: mir:: traversal:: Postorder ;
2+ use crate :: mir:: { BasicBlock , BasicBlockData , Successors , Terminator , TerminatorKind , START_BLOCK } ;
63
4+ use rustc_data_structures:: fx:: FxHashMap ;
75use rustc_data_structures:: graph;
86use rustc_data_structures:: graph:: dominators:: { dominators, Dominators } ;
7+ use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
8+ use rustc_data_structures:: sync:: OnceCell ;
99use rustc_index:: vec:: IndexVec ;
10+ use rustc_serialize:: { Decodable , Decoder , Encodable , Encoder } ;
11+ use smallvec:: SmallVec ;
1012
1113#[ derive( Clone , TyEncodable , TyDecodable , Debug , HashStable , TypeFoldable , TypeVisitable ) ]
1214pub struct BasicBlocks < ' tcx > {
1315 basic_blocks : IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
14- predecessor_cache : PredecessorCache ,
15- switch_source_cache : SwitchSourceCache ,
16- is_cyclic : GraphIsCyclicCache ,
17- postorder_cache : PostorderCache ,
16+ cache : Cache ,
17+ }
18+
19+ // Typically 95%+ of basic blocks have 4 or fewer predecessors.
20+ pub type Predecessors = IndexVec < BasicBlock , SmallVec < [ BasicBlock ; 4 ] > > ;
21+
22+ pub type SwitchSources = FxHashMap < ( BasicBlock , BasicBlock ) , SmallVec < [ Option < u128 > ; 1 ] > > ;
23+
24+ #[ derive( Clone , Default , Debug ) ]
25+ struct Cache {
26+ predecessors : OnceCell < Predecessors > ,
27+ switch_sources : OnceCell < SwitchSources > ,
28+ is_cyclic : OnceCell < bool > ,
29+ postorder : OnceCell < Vec < BasicBlock > > ,
1830}
1931
2032impl < ' tcx > BasicBlocks < ' tcx > {
2133 #[ inline]
2234 pub fn new ( basic_blocks : IndexVec < BasicBlock , BasicBlockData < ' tcx > > ) -> Self {
23- BasicBlocks {
24- basic_blocks,
25- predecessor_cache : PredecessorCache :: new ( ) ,
26- switch_source_cache : SwitchSourceCache :: new ( ) ,
27- is_cyclic : GraphIsCyclicCache :: new ( ) ,
28- postorder_cache : PostorderCache :: new ( ) ,
29- }
35+ BasicBlocks { basic_blocks, cache : Cache :: default ( ) }
3036 }
3137
3238 /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`.
3339 #[ inline]
3440 pub fn is_cfg_cyclic ( & self ) -> bool {
35- self . is_cyclic . is_cyclic ( self )
41+ * self . cache . is_cyclic . get_or_init ( || graph :: is_cyclic ( self ) )
3642 }
3743
3844 #[ inline]
@@ -43,20 +49,46 @@ impl<'tcx> BasicBlocks<'tcx> {
4349 /// Returns predecessors for each basic block.
4450 #[ inline]
4551 pub fn predecessors ( & self ) -> & Predecessors {
46- self . predecessor_cache . compute ( & self . basic_blocks )
52+ self . cache . predecessors . get_or_init ( || {
53+ let mut preds = IndexVec :: from_elem ( SmallVec :: new ( ) , & self . basic_blocks ) ;
54+ for ( bb, data) in self . basic_blocks . iter_enumerated ( ) {
55+ if let Some ( term) = & data. terminator {
56+ for succ in term. successors ( ) {
57+ preds[ succ] . push ( bb) ;
58+ }
59+ }
60+ }
61+ preds
62+ } )
4763 }
4864
4965 /// Returns basic blocks in a postorder.
5066 #[ inline]
5167 pub fn postorder ( & self ) -> & [ BasicBlock ] {
52- self . postorder_cache . compute ( & self . basic_blocks )
68+ self . cache . postorder . get_or_init ( || {
69+ Postorder :: new ( & self . basic_blocks , START_BLOCK ) . map ( |( bb, _) | bb) . collect ( )
70+ } )
5371 }
5472
5573 /// `switch_sources()[&(target, switch)]` returns a list of switch
5674 /// values that lead to a `target` block from a `switch` block.
5775 #[ inline]
5876 pub fn switch_sources ( & self ) -> & SwitchSources {
59- self . switch_source_cache . compute ( & self . basic_blocks )
77+ self . cache . switch_sources . get_or_init ( || {
78+ let mut switch_sources: SwitchSources = FxHashMap :: default ( ) ;
79+ for ( bb, data) in self . basic_blocks . iter_enumerated ( ) {
80+ if let Some ( Terminator {
81+ kind : TerminatorKind :: SwitchInt { targets, .. } , ..
82+ } ) = & data. terminator
83+ {
84+ for ( value, target) in targets. iter ( ) {
85+ switch_sources. entry ( ( target, bb) ) . or_default ( ) . push ( Some ( value) ) ;
86+ }
87+ switch_sources. entry ( ( targets. otherwise ( ) , bb) ) . or_default ( ) . push ( None ) ;
88+ }
89+ }
90+ switch_sources
91+ } )
6092 }
6193
6294 /// Returns mutable reference to basic blocks. Invalidates CFG cache.
@@ -88,10 +120,7 @@ impl<'tcx> BasicBlocks<'tcx> {
88120 /// All other methods that allow you to mutate the basic blocks also call this method
89121 /// themselves, thereby avoiding any risk of accidentally cache invalidation.
90122 pub fn invalidate_cfg_cache ( & mut self ) {
91- self . predecessor_cache . invalidate ( ) ;
92- self . switch_source_cache . invalidate ( ) ;
93- self . is_cyclic . invalidate ( ) ;
94- self . postorder_cache . invalidate ( ) ;
123+ self . cache = Cache :: default ( ) ;
95124 }
96125}
97126
@@ -145,3 +174,24 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
145174 self . predecessors ( ) [ node] . iter ( ) . copied ( )
146175 }
147176}
177+
178+ TrivialTypeTraversalAndLiftImpls ! {
179+ Cache ,
180+ }
181+
182+ impl < S : Encoder > Encodable < S > for Cache {
183+ #[ inline]
184+ fn encode ( & self , _s : & mut S ) { }
185+ }
186+
187+ impl < D : Decoder > Decodable < D > for Cache {
188+ #[ inline]
189+ fn decode ( _: & mut D ) -> Self {
190+ Default :: default ( )
191+ }
192+ }
193+
194+ impl < CTX > HashStable < CTX > for Cache {
195+ #[ inline]
196+ fn hash_stable ( & self , _: & mut CTX , _: & mut StableHasher ) { }
197+ }
0 commit comments