36
36
//! cost by `MAX_COST`.
37
37
38
38
use rustc_arena:: DroplessArena ;
39
+ use rustc_const_eval:: interpret:: { ImmTy , Immediate , InterpCx , OpTy , Projectable } ;
39
40
use rustc_data_structures:: fx:: FxHashSet ;
40
41
use rustc_index:: bit_set:: BitSet ;
41
42
use rustc_index:: IndexVec ;
43
+ use rustc_middle:: mir:: interpret:: Scalar ;
42
44
use rustc_middle:: mir:: visit:: Visitor ;
43
45
use rustc_middle:: mir:: * ;
44
- use rustc_middle:: ty:: { self , ScalarInt , Ty , TyCtxt } ;
46
+ use rustc_middle:: ty:: { self , ScalarInt , TyCtxt } ;
45
47
use rustc_mir_dataflow:: value_analysis:: { Map , PlaceIndex , State , TrackElem } ;
48
+ use rustc_span:: DUMMY_SP ;
46
49
47
50
use crate :: cost_checker:: CostChecker ;
51
+ use crate :: dataflow_const_prop:: DummyMachine ;
48
52
49
53
pub struct JumpThreading ;
50
54
@@ -70,6 +74,7 @@ impl<'tcx> MirPass<'tcx> for JumpThreading {
70
74
let mut finder = TOFinder {
71
75
tcx,
72
76
param_env,
77
+ ecx : InterpCx :: new ( tcx, DUMMY_SP , param_env, DummyMachine ) ,
73
78
body,
74
79
arena : & arena,
75
80
map : & map,
@@ -141,6 +146,7 @@ struct ThreadingOpportunity {
141
146
struct TOFinder < ' tcx , ' a > {
142
147
tcx : TyCtxt < ' tcx > ,
143
148
param_env : ty:: ParamEnv < ' tcx > ,
149
+ ecx : InterpCx < ' tcx , ' tcx , DummyMachine > ,
144
150
body : & ' a Body < ' tcx > ,
145
151
map : & ' a Map ,
146
152
loop_headers : & ' a BitSet < BasicBlock > ,
@@ -328,25 +334,75 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
328
334
}
329
335
330
336
#[ instrument( level = "trace" , skip( self ) ) ]
331
- fn process_operand (
337
+ fn process_immediate (
332
338
& mut self ,
333
339
bb : BasicBlock ,
334
340
lhs : PlaceIndex ,
335
- rhs : & Operand < ' tcx > ,
341
+ rhs : ImmTy < ' tcx > ,
336
342
state : & mut State < ConditionSet < ' a > > ,
337
343
) -> Option < !> {
338
344
let register_opportunity = |c : Condition | {
339
345
debug ! ( ?bb, ?c. target, "register" ) ;
340
346
self . opportunities . push ( ThreadingOpportunity { chain : vec ! [ bb] , target : c. target } )
341
347
} ;
342
348
349
+ let conditions = state. try_get_idx ( lhs, self . map ) ?;
350
+ if let Immediate :: Scalar ( Scalar :: Int ( int) ) = * rhs {
351
+ conditions. iter_matches ( int) . for_each ( register_opportunity) ;
352
+ }
353
+
354
+ None
355
+ }
356
+
357
+ #[ instrument( level = "trace" , skip( self ) ) ]
358
+ fn process_operand (
359
+ & mut self ,
360
+ bb : BasicBlock ,
361
+ lhs : PlaceIndex ,
362
+ rhs : & Operand < ' tcx > ,
363
+ state : & mut State < ConditionSet < ' a > > ,
364
+ ) -> Option < !> {
343
365
match rhs {
344
366
// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
345
367
Operand :: Constant ( constant) => {
346
- let conditions = state. try_get_idx ( lhs, self . map ) ?;
347
- let constant =
348
- constant. const_ . normalize ( self . tcx , self . param_env ) . try_to_scalar_int ( ) ?;
349
- conditions. iter_matches ( constant) . for_each ( register_opportunity) ;
368
+ let constant = self . ecx . eval_mir_constant ( & constant. const_ , None , None ) . ok ( ) ?;
369
+ self . map . for_each_projection_value (
370
+ lhs,
371
+ constant,
372
+ & mut |elem, op| match elem {
373
+ TrackElem :: Field ( idx) => self . ecx . project_field ( op, idx. as_usize ( ) ) . ok ( ) ,
374
+ TrackElem :: Variant ( idx) => self . ecx . project_downcast ( op, idx) . ok ( ) ,
375
+ TrackElem :: Discriminant => {
376
+ let variant = self . ecx . read_discriminant ( op) . ok ( ) ?;
377
+ let discr_value =
378
+ self . ecx . discriminant_for_variant ( op. layout . ty , variant) . ok ( ) ?;
379
+ Some ( discr_value. into ( ) )
380
+ }
381
+ TrackElem :: DerefLen => {
382
+ let op: OpTy < ' _ > = self . ecx . deref_pointer ( op) . ok ( ) ?. into ( ) ;
383
+ let len_usize = op. len ( & self . ecx ) . ok ( ) ?;
384
+ let layout = self
385
+ . tcx
386
+ . layout_of ( self . param_env . and ( self . tcx . types . usize ) )
387
+ . unwrap ( ) ;
388
+ Some ( ImmTy :: from_uint ( len_usize, layout) . into ( ) )
389
+ }
390
+ } ,
391
+ & mut |place, op| {
392
+ if let Some ( conditions) = state. try_get_idx ( place, self . map )
393
+ && let Ok ( imm) = self . ecx . read_immediate_raw ( op)
394
+ && let Some ( imm) = imm. right ( )
395
+ && let Immediate :: Scalar ( Scalar :: Int ( int) ) = * imm
396
+ {
397
+ conditions. iter_matches ( int) . for_each ( |c : Condition | {
398
+ self . opportunities . push ( ThreadingOpportunity {
399
+ chain : vec ! [ bb] ,
400
+ target : c. target ,
401
+ } )
402
+ } )
403
+ }
404
+ } ,
405
+ ) ;
350
406
}
351
407
// Transfer the conditions on the copied rhs.
352
408
Operand :: Move ( rhs) | Operand :: Copy ( rhs) => {
@@ -373,26 +429,14 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
373
429
// Below, `lhs` is the return value of `mutated_statement`,
374
430
// the place to which `conditions` apply.
375
431
376
- let discriminant_for_variant = |enum_ty : Ty < ' tcx > , variant_index| {
377
- let discr = enum_ty. discriminant_for_variant ( self . tcx , variant_index) ?;
378
- let discr_layout = self . tcx . layout_of ( self . param_env . and ( discr. ty ) ) . ok ( ) ?;
379
- let scalar = ScalarInt :: try_from_uint ( discr. val , discr_layout. size ) ?;
380
- Some ( Operand :: const_from_scalar (
381
- self . tcx ,
382
- discr. ty ,
383
- scalar. into ( ) ,
384
- rustc_span:: DUMMY_SP ,
385
- ) )
386
- } ;
387
-
388
432
match & stmt. kind {
389
433
// If we expect `discriminant(place) ?= A`,
390
434
// we have an opportunity if `variant_index ?= A`.
391
435
StatementKind :: SetDiscriminant { box place, variant_index } => {
392
436
let discr_target = self . map . find_discr ( place. as_ref ( ) ) ?;
393
437
let enum_ty = place. ty ( self . body , self . tcx ) . ty ;
394
- let discr = discriminant_for_variant ( enum_ty, * variant_index) ?;
395
- self . process_operand ( bb, discr_target, & discr, state) ?;
438
+ let discr = self . ecx . discriminant_for_variant ( enum_ty, * variant_index) . ok ( ) ?;
439
+ self . process_immediate ( bb, discr_target, discr, state) ?;
396
440
}
397
441
// If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`.
398
442
StatementKind :: Intrinsic ( box NonDivergingIntrinsic :: Assume (
@@ -422,10 +466,16 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
422
466
AggregateKind :: Adt ( _, variant_index, ..) if agg_ty. is_enum ( ) => {
423
467
if let Some ( discr_target) =
424
468
self . map . apply ( lhs, TrackElem :: Discriminant )
425
- && let Some ( discr_value) =
426
- discriminant_for_variant ( agg_ty, * variant_index)
469
+ && let Ok ( discr_value) = self
470
+ . ecx
471
+ . discriminant_for_variant ( agg_ty, * variant_index)
427
472
{
428
- self . process_operand ( bb, discr_target, & discr_value, state) ;
473
+ self . process_immediate (
474
+ bb,
475
+ discr_target,
476
+ discr_value,
477
+ state,
478
+ ) ;
429
479
}
430
480
self . map . apply ( lhs, TrackElem :: Variant ( * variant_index) ) ?
431
481
}
0 commit comments