8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- //! An analysis to determine which temporaries require allocas and
11
+ //! An analysis to determine which locals require allocas and
12
12
//! which do not.
13
13
14
14
use rustc_data_structures:: bitvec:: BitVector ;
@@ -21,16 +21,20 @@ use common::{self, Block, BlockAndBuilder};
21
21
use glue;
22
22
use super :: rvalue;
23
23
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 {
26
26
let bcx = bcx. build ( ) ;
27
- let mut analyzer = TempAnalyzer :: new ( mir, & bcx, mir . temp_decls . len ( ) ) ;
27
+ let mut analyzer = LocalAnalyzer :: new ( mir, & bcx) ;
28
28
29
29
analyzer. visit_mir ( mir) ;
30
30
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) ;
34
38
if ty. is_scalar ( ) ||
35
39
ty. is_unique ( ) ||
36
40
ty. is_region_ptr ( ) ||
@@ -50,76 +54,97 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
50
54
// (e.g. structs) into an alloca unconditionally, just so
51
55
// that we don't have to deal with having two pathways
52
56
// (gep vs extractvalue etc).
53
- analyzer. mark_as_lvalue ( index) ;
57
+ analyzer. mark_as_lvalue ( mir :: Local :: new ( index) ) ;
54
58
}
55
59
}
56
60
57
- analyzer. lvalue_temps
61
+ analyzer. lvalue_locals
58
62
}
59
63
60
- struct TempAnalyzer < ' mir , ' bcx : ' mir , ' tcx : ' bcx > {
64
+ struct LocalAnalyzer < ' mir , ' bcx : ' mir , ' tcx : ' bcx > {
61
65
mir : & ' mir mir:: Mir < ' tcx > ,
62
66
bcx : & ' mir BlockAndBuilder < ' bcx , ' tcx > ,
63
- lvalue_temps : BitVector ,
67
+ lvalue_locals : BitVector ,
64
68
seen_assigned : BitVector
65
69
}
66
70
67
- impl < ' mir , ' bcx , ' tcx > TempAnalyzer < ' mir , ' bcx , ' tcx > {
71
+ impl < ' mir , ' bcx , ' tcx > LocalAnalyzer < ' mir , ' bcx , ' tcx > {
68
72
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 {
72
77
mir : mir,
73
78
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 )
76
81
}
77
82
}
78
83
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 ( ) ) ;
82
87
}
83
88
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 ) ;
87
92
}
88
93
}
89
94
}
90
95
91
- impl < ' mir , ' bcx , ' tcx > Visitor < ' tcx > for TempAnalyzer < ' mir , ' bcx , ' tcx > {
96
+ impl < ' mir , ' bcx , ' tcx > Visitor < ' tcx > for LocalAnalyzer < ' mir , ' bcx , ' tcx > {
92
97
fn visit_assign ( & mut self ,
93
98
block : mir:: BasicBlock ,
94
99
lvalue : & mir:: Lvalue < ' tcx > ,
95
100
rvalue : & mir:: Rvalue < ' tcx > ) {
96
101
debug ! ( "visit_assign(block={:?}, lvalue={:?}, rvalue={:?})" , block, lvalue, rvalue) ;
97
102
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) ;
107
107
}
108
+ } else {
109
+ self . visit_lvalue ( lvalue, LvalueContext :: Store ) ;
108
110
}
109
111
110
112
self . visit_rvalue ( rvalue) ;
111
113
}
112
114
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
+
113
138
fn visit_lvalue ( & mut self ,
114
139
lvalue : & mir:: Lvalue < ' tcx > ,
115
140
context : LvalueContext ) {
116
141
debug ! ( "visit_lvalue(lvalue={:?}, context={:?})" , lvalue, context) ;
117
142
118
143
// Allow uses of projections of immediate pair fields.
119
144
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 ( ) ) ) ;
123
148
if common:: type_is_imm_pair ( self . bcx . ccx ( ) , ty) {
124
149
if let mir:: ProjectionElem :: Field ( ..) = proj. elem {
125
150
if let LvalueContext :: Consume = context {
@@ -130,34 +155,30 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> {
130
155
}
131
156
}
132
157
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 ( ) ) ) ;
151
175
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) ;
156
179
}
157
180
}
158
181
}
159
- _ => {
160
- }
161
182
}
162
183
163
184
// A deref projection only reads the pointer, never needs the lvalue.
0 commit comments