@@ -5,7 +5,7 @@ use super::FunctionCx;
55use crate :: traits:: * ;
66use rustc_data_structures:: graph:: dominators:: Dominators ;
77use rustc_index:: bit_set:: BitSet ;
8- use rustc_index:: vec:: { Idx , IndexVec } ;
8+ use rustc_index:: vec:: IndexVec ;
99use rustc_middle:: mir:: traversal;
1010use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
1111use rustc_middle:: mir:: { self , Location , TerminatorKind } ;
@@ -16,7 +16,29 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
1616 fx : & FunctionCx < ' a , ' tcx , Bx > ,
1717) -> BitSet < mir:: Local > {
1818 let mir = fx. mir ;
19- let mut analyzer = LocalAnalyzer :: new ( fx) ;
19+ let dominators = mir. dominators ( ) ;
20+ let locals = mir
21+ . local_decls
22+ . iter ( )
23+ . map ( |decl| {
24+ let ty = fx. monomorphize ( decl. ty ) ;
25+ let layout = fx. cx . spanned_layout_of ( ty, decl. source_info . span ) ;
26+ if layout. is_zst ( ) {
27+ LocalKind :: ZST
28+ } else if fx. cx . is_backend_immediate ( layout) || fx. cx . is_backend_scalar_pair ( layout) {
29+ LocalKind :: Unused
30+ } else {
31+ LocalKind :: Memory
32+ }
33+ } )
34+ . collect ( ) ;
35+
36+ let mut analyzer = LocalAnalyzer { fx, dominators, locals } ;
37+
38+ // Arguments get assigned to by means of the function being called
39+ for arg in mir. args_iter ( ) {
40+ analyzer. assign ( arg, mir:: START_BLOCK . start_location ( ) ) ;
41+ }
2042
2143 // If there exists a local definition that dominates all uses of that local,
2244 // the definition should be visited first. Traverse blocks in preorder which
@@ -25,76 +47,45 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
2547 analyzer. visit_basic_block_data ( bb, data) ;
2648 }
2749
28- for ( local, decl) in mir. local_decls . iter_enumerated ( ) {
29- let ty = fx. monomorphize ( decl. ty ) ;
30- debug ! ( "local {:?} has type `{}`" , local, ty) ;
31- let layout = fx. cx . spanned_layout_of ( ty, decl. source_info . span ) ;
32- if fx. cx . is_backend_immediate ( layout) {
33- // These sorts of types are immediates that we can store
34- // in an Value without an alloca.
35- } else if fx. cx . is_backend_scalar_pair ( layout) {
36- // We allow pairs and uses of any of their 2 fields.
37- } else {
38- // These sorts of types require an alloca. Note that
39- // is_llvm_immediate() may *still* be true, particularly
40- // for newtypes, but we currently force some types
41- // (e.g., structs) into an alloca unconditionally, just so
42- // that we don't have to deal with having two pathways
43- // (gep vs extractvalue etc).
44- analyzer. not_ssa ( local) ;
50+ let mut non_ssa_locals = BitSet :: new_empty ( analyzer. locals . len ( ) ) ;
51+ for ( local, kind) in analyzer. locals . iter_enumerated ( ) {
52+ if matches ! ( kind, LocalKind :: Memory ) {
53+ non_ssa_locals. insert ( local) ;
4554 }
4655 }
4756
48- analyzer. non_ssa_locals
57+ non_ssa_locals
58+ }
59+
60+ #[ derive( Copy , Clone , PartialEq , Eq ) ]
61+ enum LocalKind {
62+ ZST ,
63+ /// A local that requires an alloca.
64+ Memory ,
65+ /// A scalar or a scalar pair local that is neither defined nor used.
66+ Unused ,
67+ /// A scalar or a scalar pair local with a single definition that dominates all uses.
68+ SSA ( mir:: Location ) ,
4969}
5070
5171struct LocalAnalyzer < ' mir , ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > {
5272 fx : & ' mir FunctionCx < ' a , ' tcx , Bx > ,
5373 dominators : Dominators < mir:: BasicBlock > ,
54- non_ssa_locals : BitSet < mir:: Local > ,
55- // The location of the first visited direct assignment to each
56- // local, or an invalid location (out of bounds `block` index).
57- first_assignment : IndexVec < mir:: Local , Location > ,
74+ locals : IndexVec < mir:: Local , LocalKind > ,
5875}
5976
6077impl < Bx : BuilderMethods < ' a , ' tcx > > LocalAnalyzer < ' mir , ' a , ' tcx , Bx > {
61- fn new ( fx : & ' mir FunctionCx < ' a , ' tcx , Bx > ) -> Self {
62- let invalid_location = mir:: BasicBlock :: new ( fx. mir . basic_blocks ( ) . len ( ) ) . start_location ( ) ;
63- let dominators = fx. mir . dominators ( ) ;
64- let mut analyzer = LocalAnalyzer {
65- fx,
66- dominators,
67- non_ssa_locals : BitSet :: new_empty ( fx. mir . local_decls . len ( ) ) ,
68- first_assignment : IndexVec :: from_elem ( invalid_location, & fx. mir . local_decls ) ,
69- } ;
70-
71- // Arguments get assigned to by means of the function being called
72- for arg in fx. mir . args_iter ( ) {
73- analyzer. first_assignment [ arg] = mir:: START_BLOCK . start_location ( ) ;
74- }
75-
76- analyzer
77- }
78-
79- fn first_assignment ( & self , local : mir:: Local ) -> Option < Location > {
80- let location = self . first_assignment [ local] ;
81- if location. block . index ( ) < self . fx . mir . basic_blocks ( ) . len ( ) {
82- Some ( location)
83- } else {
84- None
85- }
86- }
87-
88- fn not_ssa ( & mut self , local : mir:: Local ) {
89- debug ! ( "marking {:?} as non-SSA" , local) ;
90- self . non_ssa_locals . insert ( local) ;
91- }
92-
9378 fn assign ( & mut self , local : mir:: Local , location : Location ) {
94- if self . first_assignment ( local) . is_some ( ) {
95- self . not_ssa ( local) ;
96- } else {
97- self . first_assignment [ local] = location;
79+ let kind = & mut self . locals [ local] ;
80+ match * kind {
81+ LocalKind :: ZST => { }
82+ LocalKind :: Memory => { }
83+ LocalKind :: Unused => {
84+ * kind = LocalKind :: SSA ( location) ;
85+ }
86+ LocalKind :: SSA ( _) => {
87+ * kind = LocalKind :: Memory ;
88+ }
9889 }
9990 }
10091
@@ -175,11 +166,13 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
175166 ) {
176167 debug ! ( "visit_assign(place={:?}, rvalue={:?})" , place, rvalue) ;
177168
178- if let Some ( index) = place. as_local ( ) {
179- self . assign ( index, location) ;
180- let decl_span = self . fx . mir . local_decls [ index] . source_info . span ;
181- if !self . fx . rvalue_creates_operand ( rvalue, decl_span) {
182- self . not_ssa ( index) ;
169+ if let Some ( local) = place. as_local ( ) {
170+ self . assign ( local, location) ;
171+ if self . locals [ local] != LocalKind :: Memory {
172+ let decl_span = self . fx . mir . local_decls [ local] . source_info . span ;
173+ if !self . fx . rvalue_creates_operand ( rvalue, decl_span) {
174+ self . locals [ local] = LocalKind :: Memory ;
175+ }
183176 }
184177 } else {
185178 self . visit_place ( place, PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) , location) ;
@@ -204,32 +197,18 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
204197
205198 PlaceContext :: NonMutatingUse (
206199 NonMutatingUseContext :: Copy | NonMutatingUseContext :: Move ,
207- ) => {
200+ ) => match & mut self . locals [ local] {
201+ LocalKind :: ZST => { }
202+ LocalKind :: Memory => { }
203+ LocalKind :: SSA ( def) if def. dominates ( location, & self . dominators ) => { }
208204 // Reads from uninitialized variables (e.g., in dead code, after
209205 // optimizations) require locals to be in (uninitialized) memory.
210206 // N.B., there can be uninitialized reads of a local visited after
211207 // an assignment to that local, if they happen on disjoint paths.
212- let ssa_read = match self . first_assignment ( local) {
213- Some ( assignment_location) => {
214- assignment_location. dominates ( location, & self . dominators )
215- }
216- None => {
217- debug ! ( "No first assignment found for {:?}" , local) ;
218- // We have not seen any assignment to the local yet,
219- // but before marking not_ssa, check if it is a ZST,
220- // in which case we don't need to initialize the local.
221- let ty = self . fx . mir . local_decls [ local] . ty ;
222- let ty = self . fx . monomorphize ( ty) ;
223-
224- let is_zst = self . fx . cx . layout_of ( ty) . is_zst ( ) ;
225- debug ! ( "is_zst: {}" , is_zst) ;
226- is_zst
227- }
228- } ;
229- if !ssa_read {
230- self . not_ssa ( local) ;
208+ kind @ ( LocalKind :: Unused | LocalKind :: SSA ( _) ) => {
209+ * kind = LocalKind :: Memory ;
231210 }
232- }
211+ } ,
233212
234213 PlaceContext :: MutatingUse (
235214 MutatingUseContext :: Store
@@ -246,16 +225,18 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
246225 | NonMutatingUseContext :: AddressOf
247226 | NonMutatingUseContext :: Projection ,
248227 ) => {
249- self . not_ssa ( local) ;
228+ self . locals [ local] = LocalKind :: Memory ;
250229 }
251230
252231 PlaceContext :: MutatingUse ( MutatingUseContext :: Drop ) => {
253- let ty = self . fx . mir . local_decls [ local] . ty ;
254- let ty = self . fx . monomorphize ( ty) ;
255-
256- // Only need the place if we're actually dropping it.
257- if self . fx . cx . type_needs_drop ( ty) {
258- self . not_ssa ( local) ;
232+ let kind = & mut self . locals [ local] ;
233+ if * kind != LocalKind :: Memory {
234+ let ty = self . fx . mir . local_decls [ local] . ty ;
235+ let ty = self . fx . monomorphize ( ty) ;
236+ if self . fx . cx . type_needs_drop ( ty) {
237+ // Only need the place if we're actually dropping it.
238+ * kind = LocalKind :: Memory ;
239+ }
259240 }
260241 }
261242 }
0 commit comments