1
1
//! Propagates constants for early reporting of statically known
2
2
//! assertion failures
3
3
4
+ use std:: cell:: Cell ;
5
+
4
6
use rustc:: hir:: def:: DefKind ;
5
7
use rustc:: mir:: {
6
8
AggregateKind , Constant , Location , Place , PlaceBase , Body , Operand , Rvalue ,
@@ -21,7 +23,8 @@ use rustc::ty::layout::{
21
23
} ;
22
24
23
25
use crate :: interpret:: {
24
- self , InterpretCx , ScalarMaybeUndef , Immediate , OpTy , ImmTy , MemoryKind ,
26
+ self , InterpretCx , ScalarMaybeUndef , Immediate , OpTy ,
27
+ ImmTy , MemoryKind , StackPopCleanup , LocalValue , LocalState ,
25
28
} ;
26
29
use crate :: const_eval:: {
27
30
CompileTimeInterpreter , error_to_const_error, eval_promoted, mk_eval_cx,
@@ -56,21 +59,54 @@ impl MirPass for ConstProp {
56
59
57
60
trace ! ( "ConstProp starting for {:?}" , source. def_id( ) ) ;
58
61
62
+ // steal some data we need from `body`
63
+ let source_scope_local_data = std:: mem:: replace (
64
+ & mut body. source_scope_local_data ,
65
+ ClearCrossCrate :: Clear
66
+ ) ;
67
+ let promoted = std:: mem:: replace (
68
+ & mut body. promoted ,
69
+ IndexVec :: new ( )
70
+ ) ;
71
+
72
+ let dummy_body =
73
+ & Body :: new (
74
+ body. basic_blocks ( ) . clone ( ) ,
75
+ Default :: default ( ) ,
76
+ ClearCrossCrate :: Clear ,
77
+ Default :: default ( ) ,
78
+ None ,
79
+ body. local_decls . clone ( ) ,
80
+ Default :: default ( ) ,
81
+ body. arg_count ,
82
+ Default :: default ( ) ,
83
+ tcx. def_span ( source. def_id ( ) ) ,
84
+ Default :: default ( ) ,
85
+ ) ;
86
+
59
87
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
60
88
// constants, instead of just checking for const-folding succeeding.
61
89
// That would require an uniform one-def no-mutation analysis
62
90
// and RPO (or recursing when needing the value of a local).
63
- let mut optimization_finder = ConstPropagator :: new ( body, tcx, source) ;
91
+ let mut optimization_finder = ConstPropagator :: new (
92
+ body,
93
+ dummy_body,
94
+ source_scope_local_data,
95
+ promoted,
96
+ tcx,
97
+ source
98
+ ) ;
64
99
optimization_finder. visit_body ( body) ;
65
100
66
101
// put back the data we stole from `mir`
102
+ let ( source_scope_local_data, promoted) = optimization_finder. release_stolen_data ( ) ;
67
103
std:: mem:: replace (
68
104
& mut body. source_scope_local_data ,
69
- optimization_finder . source_scope_local_data
105
+ source_scope_local_data
70
106
) ;
71
107
std:: mem:: replace (
72
108
& mut body. promoted ,
73
- optimization_finder . promoted
109
+ promoted
74
110
) ;
75
111
76
112
trace ! ( "ConstProp done for {:?}" , source. def_id( ) ) ;
@@ -84,7 +120,6 @@ struct ConstPropagator<'mir, 'tcx> {
84
120
ecx : InterpretCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
85
121
tcx : TyCtxt < ' tcx > ,
86
122
source : MirSource < ' tcx > ,
87
- places : IndexVec < Local , Option < Const < ' tcx > > > ,
88
123
can_const_prop : IndexVec < Local , bool > ,
89
124
param_env : ParamEnv < ' tcx > ,
90
125
source_scope_local_data : ClearCrossCrate < IndexVec < SourceScope , SourceScopeLocalData > > ,
@@ -117,42 +152,67 @@ impl<'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> {
117
152
118
153
impl < ' mir , ' tcx > ConstPropagator < ' mir , ' tcx > {
119
154
fn new (
120
- body : & mut Body < ' tcx > ,
155
+ body : & Body < ' tcx > ,
156
+ dummy_body : & ' mir Body < ' tcx > ,
157
+ source_scope_local_data : ClearCrossCrate < IndexVec < SourceScope , SourceScopeLocalData > > ,
158
+ promoted : IndexVec < Promoted , Body < ' tcx > > ,
121
159
tcx : TyCtxt < ' tcx > ,
122
160
source : MirSource < ' tcx > ,
123
161
) -> ConstPropagator < ' mir , ' tcx > {
124
- let param_env = tcx. param_env ( source. def_id ( ) ) ;
125
- let ecx = mk_eval_cx ( tcx, tcx. def_span ( source. def_id ( ) ) , param_env) ;
162
+ let def_id = source. def_id ( ) ;
163
+ let param_env = tcx. param_env ( def_id) ;
164
+ let span = tcx. def_span ( def_id) ;
165
+ let mut ecx = mk_eval_cx ( tcx, span, param_env) ;
126
166
let can_const_prop = CanConstProp :: check ( body) ;
127
- let source_scope_local_data = std:: mem:: replace (
128
- & mut body. source_scope_local_data ,
129
- ClearCrossCrate :: Clear
130
- ) ;
131
- let promoted = std:: mem:: replace (
132
- & mut body. promoted ,
133
- IndexVec :: new ( )
134
- ) ;
167
+
168
+ ecx. push_stack_frame (
169
+ Instance :: new ( def_id, & InternalSubsts :: identity_for_item ( tcx, def_id) ) ,
170
+ span,
171
+ dummy_body,
172
+ None ,
173
+ StackPopCleanup :: None {
174
+ cleanup : false ,
175
+ } ,
176
+ ) . expect ( "failed to push initial stack frame" ) ;
135
177
136
178
ConstPropagator {
137
179
ecx,
138
180
tcx,
139
181
source,
140
182
param_env,
141
183
can_const_prop,
142
- places : IndexVec :: from_elem ( None , & body. local_decls ) ,
143
184
source_scope_local_data,
144
185
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
145
186
local_decls : body. local_decls . clone ( ) ,
146
187
promoted,
147
188
}
148
189
}
149
190
191
+ fn release_stolen_data ( self ) ->
192
+ ( ClearCrossCrate < IndexVec < SourceScope , SourceScopeLocalData > > ,
193
+ IndexVec < Promoted , Body < ' tcx > > )
194
+ {
195
+ ( self . source_scope_local_data , self . promoted )
196
+ }
197
+
150
198
fn get_const ( & self , local : Local ) -> Option < Const < ' tcx > > {
151
- self . places [ local]
199
+ let l = & self . ecx . frame ( ) . locals [ local] ;
200
+ if l. value == LocalValue :: Uninitialized || l. value == LocalValue :: Dead {
201
+ return None ;
202
+ }
203
+
204
+ self . ecx . access_local ( self . ecx . frame ( ) , local, None ) . ok ( )
152
205
}
153
206
154
207
fn set_const ( & mut self , local : Local , c : Option < Const < ' tcx > > ) {
155
- self . places [ local] = c;
208
+ self . ecx . frame_mut ( ) . locals [ local] =
209
+ match c {
210
+ Some ( op_ty) => LocalState {
211
+ value : LocalValue :: Live ( * op_ty) ,
212
+ layout : Cell :: new ( Some ( op_ty. layout ) ) ,
213
+ } ,
214
+ None => LocalState { value : LocalValue :: Uninitialized , layout : Cell :: new ( None ) } ,
215
+ } ;
156
216
}
157
217
158
218
fn use_ecx < F , T > (
0 commit comments