@@ -15,10 +15,11 @@ use rustc_middle::mir::visit::{
15
15
use rustc_middle:: mir:: * ;
16
16
use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf , LayoutOfHelpers , TyAndLayout } ;
17
17
use rustc_middle:: ty:: { self , GenericArgs , Instance , ParamEnv , Ty , TyCtxt , TypeVisitableExt } ;
18
- use rustc_span:: { def_id:: DefId , Span , DUMMY_SP } ;
18
+ use rustc_span:: { def_id:: DefId , Span } ;
19
19
use rustc_target:: abi:: { self , Align , HasDataLayout , Size , TargetDataLayout } ;
20
20
use rustc_target:: spec:: abi:: Abi as CallAbi ;
21
21
22
+ use crate :: dataflow_const_prop:: Patch ;
22
23
use crate :: MirPass ;
23
24
use rustc_const_eval:: interpret:: {
24
25
self , compile_time_machine, AllocId , ConstAllocation , ConstValue , FnArg , Frame , ImmTy ,
@@ -83,43 +84,32 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
83
84
return ;
84
85
}
85
86
86
- let is_generator = tcx. type_of ( def_id. to_def_id ( ) ) . instantiate_identity ( ) . is_generator ( ) ;
87
87
// FIXME(welseywiser) const prop doesn't work on generators because of query cycles
88
88
// computing their layout.
89
+ let is_generator = def_kind == DefKind :: Generator ;
89
90
if is_generator {
90
91
trace ! ( "ConstProp skipped for generator {:?}" , def_id) ;
91
92
return ;
92
93
}
93
94
94
95
trace ! ( "ConstProp starting for {:?}" , def_id) ;
95
96
96
- let dummy_body = & Body :: new (
97
- body. source ,
98
- ( * body. basic_blocks ) . to_owned ( ) ,
99
- body. source_scopes . clone ( ) ,
100
- body. local_decls . clone ( ) ,
101
- Default :: default ( ) ,
102
- body. arg_count ,
103
- Default :: default ( ) ,
104
- body. span ,
105
- body. generator_kind ( ) ,
106
- body. tainted_by_errors ,
107
- ) ;
108
-
109
97
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
110
98
// constants, instead of just checking for const-folding succeeding.
111
99
// That would require a uniform one-def no-mutation analysis
112
100
// and RPO (or recursing when needing the value of a local).
113
- let mut optimization_finder = ConstPropagator :: new ( body, dummy_body , tcx) ;
101
+ let mut optimization_finder = ConstPropagator :: new ( body, tcx) ;
114
102
115
103
// Traverse the body in reverse post-order, to ensure that `FullConstProp` locals are
116
104
// assigned before being read.
117
- let rpo = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
118
- for bb in rpo {
119
- let data = & mut body. basic_blocks . as_mut_preserves_cfg ( ) [ bb] ;
105
+ for & bb in body. basic_blocks . reverse_postorder ( ) {
106
+ let data = & body. basic_blocks [ bb] ;
120
107
optimization_finder. visit_basic_block_data ( bb, data) ;
121
108
}
122
109
110
+ let mut patch = optimization_finder. patch ;
111
+ patch. visit_body_preserves_cfg ( body) ;
112
+
123
113
trace ! ( "ConstProp done for {:?}" , def_id) ;
124
114
}
125
115
}
@@ -143,8 +133,11 @@ impl ConstPropMachine<'_, '_> {
143
133
144
134
impl < ' mir , ' tcx > interpret:: Machine < ' mir , ' tcx > for ConstPropMachine < ' mir , ' tcx > {
145
135
compile_time_machine ! ( <' mir, ' tcx>) ;
136
+
146
137
const PANIC_ON_ALLOC_FAIL : bool = true ; // all allocations are small (see `MAX_ALLOC_LIMIT`)
147
138
139
+ const POST_MONO_CHECKS : bool = false ; // this MIR is still generic!
140
+
148
141
type MemoryKind = !;
149
142
150
143
#[ inline( always) ]
@@ -299,6 +292,7 @@ struct ConstPropagator<'mir, 'tcx> {
299
292
tcx : TyCtxt < ' tcx > ,
300
293
param_env : ParamEnv < ' tcx > ,
301
294
local_decls : & ' mir IndexSlice < Local , LocalDecl < ' tcx > > ,
295
+ patch : Patch < ' tcx > ,
302
296
}
303
297
304
298
impl < ' tcx > LayoutOfHelpers < ' tcx > for ConstPropagator < ' _ , ' tcx > {
@@ -332,11 +326,7 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
332
326
}
333
327
334
328
impl < ' mir , ' tcx > ConstPropagator < ' mir , ' tcx > {
335
- fn new (
336
- body : & Body < ' tcx > ,
337
- dummy_body : & ' mir Body < ' tcx > ,
338
- tcx : TyCtxt < ' tcx > ,
339
- ) -> ConstPropagator < ' mir , ' tcx > {
329
+ fn new ( body : & ' mir Body < ' tcx > , tcx : TyCtxt < ' tcx > ) -> ConstPropagator < ' mir , ' tcx > {
340
330
let def_id = body. source . def_id ( ) ;
341
331
let args = & GenericArgs :: identity_for_item ( tcx, def_id) ;
342
332
let param_env = tcx. param_env_reveal_all_normalized ( def_id) ;
@@ -367,7 +357,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
367
357
368
358
ecx. push_stack_frame (
369
359
Instance :: new ( def_id, args) ,
370
- dummy_body ,
360
+ body ,
371
361
& ret,
372
362
StackPopCleanup :: Root { cleanup : false } ,
373
363
)
@@ -382,7 +372,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
382
372
ecx. frame_mut ( ) . locals [ local] . make_live_uninit ( ) ;
383
373
}
384
374
385
- ConstPropagator { ecx, tcx, param_env, local_decls : & dummy_body. local_decls }
375
+ let patch = Patch :: new ( tcx) ;
376
+ ConstPropagator { ecx, tcx, param_env, local_decls : & body. local_decls , patch }
386
377
}
387
378
388
379
fn get_const ( & self , place : Place < ' tcx > ) -> Option < OpTy < ' tcx > > {
@@ -419,12 +410,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
419
410
ecx. machine . written_only_inside_own_block_locals . remove ( & local) ;
420
411
}
421
412
422
- fn propagate_operand ( & mut self , operand : & mut Operand < ' tcx > ) {
423
- if let Some ( place) = operand. place ( ) && let Some ( op) = self . replace_with_const ( place) {
424
- * operand = op;
425
- }
426
- }
427
-
428
413
fn check_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > ) -> Option < ( ) > {
429
414
// Perform any special handling for specific Rvalue types.
430
415
// Generally, checks here fall into one of two categories:
@@ -540,16 +525,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
540
525
}
541
526
}
542
527
543
- /// Creates a new `Operand::Constant` from a `Scalar` value
544
- fn operand_from_scalar ( & self , scalar : Scalar , ty : Ty < ' tcx > ) -> Operand < ' tcx > {
545
- Operand :: Constant ( Box :: new ( Constant {
546
- span : DUMMY_SP ,
547
- user_ty : None ,
548
- literal : ConstantKind :: from_scalar ( self . tcx , scalar, ty) ,
549
- } ) )
550
- }
551
-
552
- fn replace_with_const ( & mut self , place : Place < ' tcx > ) -> Option < Operand < ' tcx > > {
528
+ fn replace_with_const ( & mut self , place : Place < ' tcx > ) -> Option < ConstantKind < ' tcx > > {
553
529
// This will return None if the above `const_prop` invocation only "wrote" a
554
530
// type whose creation requires no write. E.g. a generator whose initial state
555
531
// consists solely of uninitialized memory (so it doesn't capture any locals).
@@ -565,7 +541,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
565
541
let Right ( imm) = imm else { return None } ;
566
542
match * imm {
567
543
Immediate :: Scalar ( scalar) if scalar. try_to_int ( ) . is_ok ( ) => {
568
- Some ( self . operand_from_scalar ( scalar, value. layout . ty ) )
544
+ Some ( ConstantKind :: from_scalar ( self . tcx , scalar, value. layout . ty ) )
569
545
}
570
546
Immediate :: ScalarPair ( l, r) if l. try_to_int ( ) . is_ok ( ) && r. try_to_int ( ) . is_ok ( ) => {
571
547
let alloc = self
@@ -575,15 +551,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
575
551
} )
576
552
. ok ( ) ?;
577
553
578
- let literal = ConstantKind :: Val (
554
+ Some ( ConstantKind :: Val (
579
555
ConstValue :: ByRef { alloc, offset : Size :: ZERO } ,
580
556
value. layout . ty ,
581
- ) ;
582
- Some ( Operand :: Constant ( Box :: new ( Constant {
583
- span : DUMMY_SP ,
584
- user_ty : None ,
585
- literal,
586
- } ) ) )
557
+ ) )
587
558
}
588
559
// Scalars or scalar pairs that contain undef values are assumed to not have
589
560
// successfully evaluated and are thus not propagated.
@@ -725,40 +696,29 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
725
696
}
726
697
}
727
698
728
- impl < ' tcx > MutVisitor < ' tcx > for ConstPropagator < ' _ , ' tcx > {
729
- fn tcx ( & self ) -> TyCtxt < ' tcx > {
730
- self . tcx
731
- }
732
-
733
- fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
699
+ impl < ' tcx > Visitor < ' tcx > for ConstPropagator < ' _ , ' tcx > {
700
+ fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
734
701
self . super_operand ( operand, location) ;
735
- self . propagate_operand ( operand)
702
+ if let Some ( place) = operand. place ( ) && let Some ( value) = self . replace_with_const ( place) {
703
+ self . patch . before_effect . insert ( ( location, place) , value) ;
704
+ }
736
705
}
737
706
738
- fn process_projection_elem (
707
+ fn visit_projection_elem (
739
708
& mut self ,
709
+ _: PlaceRef < ' tcx > ,
740
710
elem : PlaceElem < ' tcx > ,
741
- _: Location ,
742
- ) -> Option < PlaceElem < ' tcx > > {
711
+ _: PlaceContext ,
712
+ location : Location ,
713
+ ) {
743
714
if let PlaceElem :: Index ( local) = elem
744
- && let Some ( value) = self . get_const ( local. into ( ) )
745
- && let Some ( imm) = value. as_mplace_or_imm ( ) . right ( )
746
- && let Immediate :: Scalar ( scalar) = * imm
747
- && let Ok ( offset) = scalar. to_target_usize ( & self . tcx )
748
- && let Some ( min_length) = offset. checked_add ( 1 )
715
+ && let Some ( value) = self . replace_with_const ( local. into ( ) )
749
716
{
750
- Some ( PlaceElem :: ConstantIndex { offset, min_length, from_end : false } )
751
- } else {
752
- None
717
+ self . patch . before_effect . insert ( ( location, local. into ( ) ) , value) ;
753
718
}
754
719
}
755
720
756
- fn visit_assign (
757
- & mut self ,
758
- place : & mut Place < ' tcx > ,
759
- rvalue : & mut Rvalue < ' tcx > ,
760
- location : Location ,
761
- ) {
721
+ fn visit_assign ( & mut self , place : & Place < ' tcx > , rvalue : & Rvalue < ' tcx > , location : Location ) {
762
722
self . super_assign ( place, rvalue, location) ;
763
723
764
724
let Some ( ( ) ) = self . check_rvalue ( rvalue) else { return } ;
@@ -775,7 +735,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
775
735
{
776
736
trace ! ( "skipping replace of Rvalue::Use({:?} because it is already a const" , c) ;
777
737
} else if let Some ( operand) = self . replace_with_const ( * place) {
778
- * rvalue = Rvalue :: Use ( operand) ;
738
+ self . patch . assignments . insert ( location , operand) ;
779
739
}
780
740
} else {
781
741
// Const prop failed, so erase the destination, ensuring that whatever happens
@@ -799,7 +759,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
799
759
}
800
760
}
801
761
802
- fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
762
+ fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
803
763
trace ! ( "visit_statement: {:?}" , statement) ;
804
764
805
765
// We want to evaluate operands before any change to the assigned-to value,
@@ -843,7 +803,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
843
803
}
844
804
}
845
805
846
- fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
806
+ fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & BasicBlockData < ' tcx > ) {
847
807
self . super_basic_block_data ( block, data) ;
848
808
849
809
// We remove all Locals which are restricted in propagation to their containing blocks and
0 commit comments