@@ -9,7 +9,7 @@ use rustc_hir::def::DefKind;
9
9
use rustc_middle:: mir:: visit:: { MutVisitor , Visitor } ;
10
10
use rustc_middle:: mir:: * ;
11
11
use rustc_middle:: ty:: layout:: TyAndLayout ;
12
- use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
12
+ use rustc_middle:: ty:: { self , ScalarInt , Ty , TyCtxt } ;
13
13
use rustc_mir_dataflow:: value_analysis:: {
14
14
Map , State , TrackElem , ValueAnalysis , ValueAnalysisWrapper , ValueOrPlace ,
15
15
} ;
@@ -58,9 +58,13 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
58
58
. in_scope ( || analysis. wrap ( ) . into_engine ( tcx, body) . iterate_to_fixpoint ( ) ) ;
59
59
60
60
// Collect results and patch the body afterwards.
61
- let mut visitor = CollectAndPatch :: new ( tcx) ;
61
+ let mut visitor = CollectAndPatch :: new ( tcx, & body . local_decls ) ;
62
62
debug_span ! ( "collect" ) . in_scope ( || results. visit_reachable_with ( body, & mut visitor) ) ;
63
- debug_span ! ( "patch" ) . in_scope ( || visitor. visit_body ( body) ) ;
63
+ debug_span ! ( "patch" ) . in_scope ( || {
64
+ for ( block, bbdata) in body. basic_blocks . as_mut_preserves_cfg ( ) . iter_enumerated_mut ( ) {
65
+ visitor. visit_basic_block_data ( block, bbdata) ;
66
+ }
67
+ } )
64
68
}
65
69
}
66
70
@@ -73,7 +77,7 @@ struct ConstAnalysis<'a, 'tcx> {
73
77
}
74
78
75
79
impl < ' tcx > ValueAnalysis < ' tcx > for ConstAnalysis < ' _ , ' tcx > {
76
- type Value = FlatSet < ScalarTy < ' tcx > > ;
80
+ type Value = FlatSet < ScalarInt > ;
77
81
78
82
const NAME : & ' static str = "ConstAnalysis" ;
79
83
@@ -172,9 +176,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
172
176
if let Some ( overflow_target) = overflow_target {
173
177
let overflow = match overflow {
174
178
FlatSet :: Top => FlatSet :: Top ,
175
- FlatSet :: Elem ( overflow) => {
176
- self . wrap_scalar ( Scalar :: from_bool ( overflow) , self . tcx . types . bool )
177
- }
179
+ FlatSet :: Elem ( overflow) => FlatSet :: Elem ( overflow. into ( ) ) ,
178
180
FlatSet :: Bottom => FlatSet :: Bottom ,
179
181
} ;
180
182
// We have flooded `target` earlier.
@@ -209,7 +211,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
209
211
}
210
212
_ => unreachable ! ( ) ,
211
213
}
212
- . map ( |result| ValueOrPlace :: Value ( self . wrap_immediate ( result, * ty ) ) )
214
+ . map ( |result| ValueOrPlace :: Value ( self . wrap_immediate ( result) ) )
213
215
. unwrap_or ( ValueOrPlace :: TOP ) ,
214
216
_ => ValueOrPlace :: TOP ,
215
217
} ,
@@ -242,9 +244,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
242
244
constant
243
245
. literal
244
246
. eval ( self . tcx , self . param_env )
245
- . try_to_scalar ( )
246
- . map ( |value| FlatSet :: Elem ( ScalarTy ( value, constant. ty ( ) ) ) )
247
- . unwrap_or ( FlatSet :: Top )
247
+ . try_to_scalar_int ( )
248
+ . map_or ( FlatSet :: Top , FlatSet :: Elem )
248
249
}
249
250
250
251
fn handle_switch_int < ' mir > (
@@ -261,26 +262,15 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
261
262
// We are branching on uninitialized data, this is UB, treat it as unreachable.
262
263
// This allows the set of visited edges to grow monotonically with the lattice.
263
264
FlatSet :: Bottom => TerminatorEdges :: None ,
264
- FlatSet :: Elem ( ScalarTy ( scalar, _) ) => {
265
- let int = scalar. assert_int ( ) ;
266
- let choice = int. assert_bits ( int. size ( ) ) ;
265
+ FlatSet :: Elem ( scalar) => {
266
+ let choice = scalar. assert_bits ( scalar. size ( ) ) ;
267
267
TerminatorEdges :: Single ( targets. target_for_value ( choice) )
268
268
}
269
269
FlatSet :: Top => TerminatorEdges :: SwitchInt { discr, targets } ,
270
270
}
271
271
}
272
272
}
273
273
274
- #[ derive( Clone , PartialEq , Eq ) ]
275
- struct ScalarTy < ' tcx > ( Scalar , Ty < ' tcx > ) ;
276
-
277
- impl < ' tcx > std:: fmt:: Debug for ScalarTy < ' tcx > {
278
- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
279
- // This is used for dataflow visualization, so we return something more concise.
280
- std:: fmt:: Display :: fmt ( & ConstantKind :: Val ( ConstValue :: Scalar ( self . 0 ) , self . 1 ) , f)
281
- }
282
- }
283
-
284
274
impl < ' a , ' tcx > ConstAnalysis < ' a , ' tcx > {
285
275
pub fn new ( tcx : TyCtxt < ' tcx > , body : & ' a Body < ' tcx > , map : Map ) -> Self {
286
276
let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
@@ -295,17 +285,19 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
295
285
296
286
fn binary_op (
297
287
& self ,
298
- state : & mut State < FlatSet < ScalarTy < ' tcx > > > ,
288
+ state : & mut State < FlatSet < ScalarInt > > ,
299
289
op : BinOp ,
300
290
left : & Operand < ' tcx > ,
301
291
right : & Operand < ' tcx > ,
302
- ) -> ( FlatSet < ScalarTy < ' tcx > > , FlatSet < bool > ) {
292
+ ) -> ( FlatSet < ScalarInt > , FlatSet < bool > ) {
303
293
let left = self . eval_operand ( left, state) ;
304
294
let right = self . eval_operand ( right, state) ;
305
295
match ( left, right) {
306
296
( FlatSet :: Elem ( left) , FlatSet :: Elem ( right) ) => {
307
297
match self . ecx . overflowing_binary_op ( op, & left, & right) {
308
- Ok ( ( val, overflow, ty) ) => ( self . wrap_scalar ( val, ty) , FlatSet :: Elem ( overflow) ) ,
298
+ Ok ( ( Scalar :: Int ( val) , overflow, _) ) => {
299
+ ( FlatSet :: Elem ( val) , FlatSet :: Elem ( overflow) )
300
+ }
309
301
_ => ( FlatSet :: Top , FlatSet :: Top ) ,
310
302
}
311
303
}
@@ -320,84 +312,84 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
320
312
fn eval_operand (
321
313
& self ,
322
314
op : & Operand < ' tcx > ,
323
- state : & mut State < FlatSet < ScalarTy < ' tcx > > > ,
315
+ state : & mut State < FlatSet < ScalarInt > > ,
324
316
) -> FlatSet < ImmTy < ' tcx > > {
325
317
let value = match self . handle_operand ( op, state) {
326
318
ValueOrPlace :: Value ( value) => value,
327
319
ValueOrPlace :: Place ( place) => state. get_idx ( place, & self . map ) ,
328
320
} ;
329
321
match value {
330
322
FlatSet :: Top => FlatSet :: Top ,
331
- FlatSet :: Elem ( ScalarTy ( scalar, ty) ) => self
332
- . tcx
333
- . layout_of ( self . param_env . and ( ty) )
334
- . map ( |layout| FlatSet :: Elem ( ImmTy :: from_scalar ( scalar, layout) ) )
335
- . unwrap_or ( FlatSet :: Top ) ,
323
+ FlatSet :: Elem ( scalar) => {
324
+ let ty = op. ty ( self . local_decls , self . tcx ) ;
325
+ self . tcx
326
+ . layout_of ( self . param_env . and ( ty) )
327
+ . map ( |layout| FlatSet :: Elem ( ImmTy :: from_scalar ( scalar. into ( ) , layout) ) )
328
+ . unwrap_or ( FlatSet :: Top )
329
+ }
336
330
FlatSet :: Bottom => FlatSet :: Bottom ,
337
331
}
338
332
}
339
333
340
- fn eval_discriminant (
341
- & self ,
342
- enum_ty : Ty < ' tcx > ,
343
- variant_index : VariantIdx ,
344
- ) -> Option < ScalarTy < ' tcx > > {
334
+ fn eval_discriminant ( & self , enum_ty : Ty < ' tcx > , variant_index : VariantIdx ) -> Option < ScalarInt > {
345
335
if !enum_ty. is_enum ( ) {
346
336
return None ;
347
337
}
348
338
let discr = enum_ty. discriminant_for_variant ( self . tcx , variant_index) ?;
349
339
let discr_layout = self . tcx . layout_of ( self . param_env . and ( discr. ty ) ) . ok ( ) ?;
350
- let discr_value = Scalar :: try_from_uint ( discr. val , discr_layout. size ) ?;
351
- Some ( ScalarTy ( discr_value, discr. ty ) )
352
- }
353
-
354
- fn wrap_scalar ( & self , scalar : Scalar , ty : Ty < ' tcx > ) -> FlatSet < ScalarTy < ' tcx > > {
355
- FlatSet :: Elem ( ScalarTy ( scalar, ty) )
340
+ let discr_value = ScalarInt :: try_from_uint ( discr. val , discr_layout. size ) ?;
341
+ Some ( discr_value)
356
342
}
357
343
358
- fn wrap_immediate ( & self , imm : Immediate , ty : Ty < ' tcx > ) -> FlatSet < ScalarTy < ' tcx > > {
344
+ fn wrap_immediate ( & self , imm : Immediate ) -> FlatSet < ScalarInt > {
359
345
match imm {
360
- Immediate :: Scalar ( scalar) => self . wrap_scalar ( scalar, ty ) ,
346
+ Immediate :: Scalar ( Scalar :: Int ( scalar) ) => FlatSet :: Elem ( scalar) ,
361
347
_ => FlatSet :: Top ,
362
348
}
363
349
}
364
350
365
- fn wrap_immty ( & self , val : ImmTy < ' tcx > ) -> FlatSet < ScalarTy < ' tcx > > {
366
- self . wrap_immediate ( * val, val . layout . ty )
351
+ fn wrap_immty ( & self , val : ImmTy < ' tcx > ) -> FlatSet < ScalarInt > {
352
+ self . wrap_immediate ( * val)
367
353
}
368
354
}
369
355
370
- struct CollectAndPatch < ' tcx > {
356
+ struct CollectAndPatch < ' tcx , ' locals > {
371
357
tcx : TyCtxt < ' tcx > ,
358
+ local_decls : & ' locals LocalDecls < ' tcx > ,
372
359
373
360
/// For a given MIR location, this stores the values of the operands used by that location. In
374
361
/// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
375
362
/// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
376
- before_effect : FxHashMap < ( Location , Place < ' tcx > ) , ScalarTy < ' tcx > > ,
363
+ before_effect : FxHashMap < ( Location , Place < ' tcx > ) , ScalarInt > ,
377
364
378
365
/// Stores the assigned values for assignments where the Rvalue is constant.
379
- assignments : FxHashMap < Location , ScalarTy < ' tcx > > ,
366
+ assignments : FxHashMap < Location , ScalarInt > ,
380
367
}
381
368
382
- impl < ' tcx > CollectAndPatch < ' tcx > {
383
- fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
384
- Self { tcx, before_effect : FxHashMap :: default ( ) , assignments : FxHashMap :: default ( ) }
369
+ impl < ' tcx , ' locals > CollectAndPatch < ' tcx , ' locals > {
370
+ fn new ( tcx : TyCtxt < ' tcx > , local_decls : & ' locals LocalDecls < ' tcx > ) -> Self {
371
+ Self {
372
+ tcx,
373
+ local_decls,
374
+ before_effect : FxHashMap :: default ( ) ,
375
+ assignments : FxHashMap :: default ( ) ,
376
+ }
385
377
}
386
378
387
- fn make_operand ( & self , scalar : ScalarTy < ' tcx > ) -> Operand < ' tcx > {
379
+ fn make_operand ( & self , scalar : ScalarInt , ty : Ty < ' tcx > ) -> Operand < ' tcx > {
388
380
Operand :: Constant ( Box :: new ( Constant {
389
381
span : DUMMY_SP ,
390
382
user_ty : None ,
391
- literal : ConstantKind :: Val ( ConstValue :: Scalar ( scalar. 0 ) , scalar . 1 ) ,
383
+ literal : ConstantKind :: Val ( ConstValue :: Scalar ( scalar. into ( ) ) , ty ) ,
392
384
} ) )
393
385
}
394
386
}
395
387
396
388
impl < ' mir , ' tcx >
397
389
ResultsVisitor < ' mir , ' tcx , Results < ' tcx , ValueAnalysisWrapper < ConstAnalysis < ' _ , ' tcx > > > >
398
- for CollectAndPatch < ' tcx >
390
+ for CollectAndPatch < ' tcx , ' _ >
399
391
{
400
- type FlowState = State < FlatSet < ScalarTy < ' tcx > > > ;
392
+ type FlowState = State < FlatSet < ScalarInt > > ;
401
393
402
394
fn visit_statement_before_primary_effect (
403
395
& mut self ,
@@ -453,16 +445,17 @@ impl<'mir, 'tcx>
453
445
}
454
446
}
455
447
456
- impl < ' tcx > MutVisitor < ' tcx > for CollectAndPatch < ' tcx > {
457
- fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' tcx > {
448
+ impl < ' tcx > MutVisitor < ' tcx > for CollectAndPatch < ' tcx , ' _ > {
449
+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
458
450
self . tcx
459
451
}
460
452
461
453
fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
462
454
if let Some ( value) = self . assignments . get ( & location) {
463
455
match & mut statement. kind {
464
456
StatementKind :: Assign ( box ( _, rvalue) ) => {
465
- * rvalue = Rvalue :: Use ( self . make_operand ( value. clone ( ) ) ) ;
457
+ let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
458
+ * rvalue = Rvalue :: Use ( self . make_operand ( * value, ty) ) ;
466
459
}
467
460
_ => bug ! ( "found assignment info for non-assign statement" ) ,
468
461
}
@@ -475,21 +468,22 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> {
475
468
match operand {
476
469
Operand :: Copy ( place) | Operand :: Move ( place) => {
477
470
if let Some ( value) = self . before_effect . get ( & ( location, * place) ) {
478
- * operand = self . make_operand ( value. clone ( ) ) ;
471
+ let ty = place. ty ( self . local_decls , self . tcx ) . ty ;
472
+ * operand = self . make_operand ( * value, ty) ;
479
473
}
480
474
}
481
- _ => ( ) ,
475
+ Operand :: Constant ( _ ) => { }
482
476
}
483
477
}
484
478
}
485
479
486
- struct OperandCollector < ' tcx , ' map , ' a > {
487
- state : & ' a State < FlatSet < ScalarTy < ' tcx > > > ,
488
- visitor : & ' a mut CollectAndPatch < ' tcx > ,
480
+ struct OperandCollector < ' tcx , ' map , ' locals , ' a > {
481
+ state : & ' a State < FlatSet < ScalarInt > > ,
482
+ visitor : & ' a mut CollectAndPatch < ' tcx , ' locals > ,
489
483
map : & ' map Map ,
490
484
}
491
485
492
- impl < ' tcx , ' map , ' a > Visitor < ' tcx > for OperandCollector < ' tcx , ' map , ' a > {
486
+ impl < ' tcx > Visitor < ' tcx > for OperandCollector < ' tcx , ' _ , ' _ , ' _ > {
493
487
fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
494
488
match operand {
495
489
Operand :: Copy ( place) | Operand :: Move ( place) => {
@@ -572,7 +566,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
572
566
_bin_op : BinOp ,
573
567
_left : & rustc_const_eval:: interpret:: ImmTy < ' tcx , Self :: Provenance > ,
574
568
_right : & rustc_const_eval:: interpret:: ImmTy < ' tcx , Self :: Provenance > ,
575
- ) -> interpret:: InterpResult < ' tcx , ( interpret :: Scalar < Self :: Provenance > , bool , Ty < ' tcx > ) > {
569
+ ) -> interpret:: InterpResult < ' tcx , ( Scalar < Self :: Provenance > , bool , Ty < ' tcx > ) > {
576
570
throw_unsup ! ( Unsupported ( "" . into( ) ) )
577
571
}
578
572
0 commit comments