88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- //! An analysis to determine which temporaries require allocas and
11+ //! An analysis to determine which locals require allocas and
1212//! which do not.
1313
1414use rustc_data_structures:: bitvec:: BitVector ;
@@ -21,16 +21,20 @@ use common::{self, Block, BlockAndBuilder};
2121use glue;
2222use super :: rvalue;
2323
24- pub fn lvalue_temps < ' bcx , ' tcx > ( bcx : Block < ' bcx , ' tcx > ,
25- mir : & mir:: Mir < ' tcx > ) -> BitVector {
24+ pub fn lvalue_locals < ' bcx , ' tcx > ( bcx : Block < ' bcx , ' tcx > ,
25+ mir : & mir:: Mir < ' tcx > ) -> BitVector {
2626 let bcx = bcx. build ( ) ;
27- let mut analyzer = TempAnalyzer :: new ( mir, & bcx, mir . temp_decls . len ( ) ) ;
27+ let mut analyzer = LocalAnalyzer :: new ( mir, & bcx) ;
2828
2929 analyzer. visit_mir ( mir) ;
3030
31- for ( index, temp_decl) in mir. temp_decls . iter ( ) . enumerate ( ) {
32- let ty = bcx. monomorphize ( & temp_decl. ty ) ;
33- debug ! ( "temp {:?} has type {:?}" , index, ty) ;
31+ let local_types = mir. arg_decls . iter ( ) . map ( |a| a. ty )
32+ . chain ( mir. var_decls . iter ( ) . map ( |v| v. ty ) )
33+ . chain ( mir. temp_decls . iter ( ) . map ( |t| t. ty ) )
34+ . chain ( mir. return_ty . maybe_converging ( ) ) ;
35+ for ( index, ty) in local_types. enumerate ( ) {
36+ let ty = bcx. monomorphize ( & ty) ;
37+ debug ! ( "local {} has type {:?}" , index, ty) ;
3438 if ty. is_scalar ( ) ||
3539 ty. is_unique ( ) ||
3640 ty. is_region_ptr ( ) ||
@@ -50,76 +54,97 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
5054 // (e.g. structs) into an alloca unconditionally, just so
5155 // that we don't have to deal with having two pathways
5256 // (gep vs extractvalue etc).
53- analyzer. mark_as_lvalue ( index) ;
57+ analyzer. mark_as_lvalue ( mir :: Local :: new ( index) ) ;
5458 }
5559 }
5660
57- analyzer. lvalue_temps
61+ analyzer. lvalue_locals
5862}
5963
60- struct TempAnalyzer < ' mir , ' bcx : ' mir , ' tcx : ' bcx > {
64+ struct LocalAnalyzer < ' mir , ' bcx : ' mir , ' tcx : ' bcx > {
6165 mir : & ' mir mir:: Mir < ' tcx > ,
6266 bcx : & ' mir BlockAndBuilder < ' bcx , ' tcx > ,
63- lvalue_temps : BitVector ,
67+ lvalue_locals : BitVector ,
6468 seen_assigned : BitVector
6569}
6670
67- impl < ' mir , ' bcx , ' tcx > TempAnalyzer < ' mir , ' bcx , ' tcx > {
71+ impl < ' mir , ' bcx , ' tcx > LocalAnalyzer < ' mir , ' bcx , ' tcx > {
6872 fn new ( mir : & ' mir mir:: Mir < ' tcx > ,
69- bcx : & ' mir BlockAndBuilder < ' bcx , ' tcx > ,
70- temp_count : usize ) -> TempAnalyzer < ' mir , ' bcx , ' tcx > {
71- TempAnalyzer {
73+ bcx : & ' mir BlockAndBuilder < ' bcx , ' tcx > )
74+ -> LocalAnalyzer < ' mir , ' bcx , ' tcx > {
75+ let local_count = mir. count_locals ( ) ;
76+ LocalAnalyzer {
7277 mir : mir,
7378 bcx : bcx,
74- lvalue_temps : BitVector :: new ( temp_count ) ,
75- seen_assigned : BitVector :: new ( temp_count )
79+ lvalue_locals : BitVector :: new ( local_count ) ,
80+ seen_assigned : BitVector :: new ( local_count )
7681 }
7782 }
7883
79- fn mark_as_lvalue ( & mut self , temp : usize ) {
80- debug ! ( "marking temp { } as lvalue" , temp ) ;
81- self . lvalue_temps . insert ( temp ) ;
84+ fn mark_as_lvalue ( & mut self , local : mir :: Local ) {
85+ debug ! ( "marking {:? } as lvalue" , local ) ;
86+ self . lvalue_locals . insert ( local . index ( ) ) ;
8287 }
8388
84- fn mark_assigned ( & mut self , temp : usize ) {
85- if !self . seen_assigned . insert ( temp ) {
86- self . mark_as_lvalue ( temp ) ;
89+ fn mark_assigned ( & mut self , local : mir :: Local ) {
90+ if !self . seen_assigned . insert ( local . index ( ) ) {
91+ self . mark_as_lvalue ( local ) ;
8792 }
8893 }
8994}
9095
91- impl < ' mir , ' bcx , ' tcx > Visitor < ' tcx > for TempAnalyzer < ' mir , ' bcx , ' tcx > {
96+ impl < ' mir , ' bcx , ' tcx > Visitor < ' tcx > for LocalAnalyzer < ' mir , ' bcx , ' tcx > {
9297 fn visit_assign ( & mut self ,
9398 block : mir:: BasicBlock ,
9499 lvalue : & mir:: Lvalue < ' tcx > ,
95100 rvalue : & mir:: Rvalue < ' tcx > ) {
96101 debug ! ( "visit_assign(block={:?}, lvalue={:?}, rvalue={:?})" , block, lvalue, rvalue) ;
97102
98- match * lvalue {
99- mir:: Lvalue :: Temp ( temp) => {
100- self . mark_assigned ( temp. index ( ) ) ;
101- if !rvalue:: rvalue_creates_operand ( self . mir , self . bcx , rvalue) {
102- self . mark_as_lvalue ( temp. index ( ) ) ;
103- }
104- }
105- _ => {
106- self . visit_lvalue ( lvalue, LvalueContext :: Store ) ;
103+ if let Some ( index) = self . mir . local_index ( lvalue) {
104+ self . mark_assigned ( index) ;
105+ if !rvalue:: rvalue_creates_operand ( self . mir , self . bcx , rvalue) {
106+ self . mark_as_lvalue ( index) ;
107107 }
108+ } else {
109+ self . visit_lvalue ( lvalue, LvalueContext :: Store ) ;
108110 }
109111
110112 self . visit_rvalue ( rvalue) ;
111113 }
112114
115+ fn visit_terminator_kind ( & mut self ,
116+ block : mir:: BasicBlock ,
117+ kind : & mir:: TerminatorKind < ' tcx > ) {
118+ match * kind {
119+ mir:: TerminatorKind :: Call {
120+ func : mir:: Operand :: Constant ( mir:: Constant {
121+ literal : mir:: Literal :: Item { def_id, .. } , ..
122+ } ) ,
123+ ref args, ..
124+ } if Some ( def_id) == self . bcx . tcx ( ) . lang_items . box_free_fn ( ) => {
125+ // box_free(x) shares with `drop x` the property that it
126+ // is not guaranteed to be statically dominated by the
127+ // definition of x, so x must always be in an alloca.
128+ if let mir:: Operand :: Consume ( ref lvalue) = args[ 0 ] {
129+ self . visit_lvalue ( lvalue, LvalueContext :: Drop ) ;
130+ }
131+ }
132+ _ => { }
133+ }
134+
135+ self . super_terminator_kind ( block, kind) ;
136+ }
137+
113138 fn visit_lvalue ( & mut self ,
114139 lvalue : & mir:: Lvalue < ' tcx > ,
115140 context : LvalueContext ) {
116141 debug ! ( "visit_lvalue(lvalue={:?}, context={:?})" , lvalue, context) ;
117142
118143 // Allow uses of projections of immediate pair fields.
119144 if let mir:: Lvalue :: Projection ( ref proj) = * lvalue {
120- if let mir:: Lvalue :: Temp ( temp ) = proj. base {
121- let ty = self . mir . temp_decls [ temp ] . ty ;
122- let ty = self . bcx . monomorphize ( & ty) ;
145+ if self . mir . local_index ( & proj. base ) . is_some ( ) {
146+ let ty = self . mir . lvalue_ty ( self . bcx . tcx ( ) , & proj . base ) ;
147+ let ty = self . bcx . monomorphize ( & ty. to_ty ( self . bcx . tcx ( ) ) ) ;
123148 if common:: type_is_imm_pair ( self . bcx . ccx ( ) , ty) {
124149 if let mir:: ProjectionElem :: Field ( ..) = proj. elem {
125150 if let LvalueContext :: Consume = context {
@@ -130,34 +155,30 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> {
130155 }
131156 }
132157
133- match * lvalue {
134- mir:: Lvalue :: Temp ( temp) => {
135- match context {
136- LvalueContext :: Call => {
137- self . mark_assigned ( temp. index ( ) ) ;
138- }
139- LvalueContext :: Consume => {
140- }
141- LvalueContext :: Store |
142- LvalueContext :: Inspect |
143- LvalueContext :: Borrow { .. } |
144- LvalueContext :: Slice { .. } |
145- LvalueContext :: Projection => {
146- self . mark_as_lvalue ( temp. index ( ) ) ;
147- }
148- LvalueContext :: Drop => {
149- let ty = self . mir . temp_decls [ index as usize ] . ty ;
150- let ty = self . bcx . monomorphize ( & ty) ;
158+ if let Some ( index) = self . mir . local_index ( lvalue) {
159+ match context {
160+ LvalueContext :: Call => {
161+ self . mark_assigned ( index) ;
162+ }
163+ LvalueContext :: Consume => {
164+ }
165+ LvalueContext :: Store |
166+ LvalueContext :: Inspect |
167+ LvalueContext :: Borrow { .. } |
168+ LvalueContext :: Slice { .. } |
169+ LvalueContext :: Projection => {
170+ self . mark_as_lvalue ( index) ;
171+ }
172+ LvalueContext :: Drop => {
173+ let ty = self . mir . lvalue_ty ( self . bcx . tcx ( ) , lvalue) ;
174+ let ty = self . bcx . monomorphize ( & ty. to_ty ( self . bcx . tcx ( ) ) ) ;
151175
152- // Only need the lvalue if we're actually dropping it.
153- if glue:: type_needs_drop ( self . bcx . tcx ( ) , ty) {
154- self . mark_as_lvalue ( index as usize ) ;
155- }
176+ // Only need the lvalue if we're actually dropping it.
177+ if glue:: type_needs_drop ( self . bcx . tcx ( ) , ty) {
178+ self . mark_as_lvalue ( index) ;
156179 }
157180 }
158181 }
159- _ => {
160- }
161182 }
162183
163184 // A deref projection only reads the pointer, never needs the lvalue.
0 commit comments