@@ -15,10 +15,11 @@ use rustc_middle::mir::visit::{
1515use rustc_middle:: mir:: * ;
1616use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf , LayoutOfHelpers , TyAndLayout } ;
1717use 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 } ;
1919use rustc_target:: abi:: { self , Align , HasDataLayout , Size , TargetDataLayout } ;
2020use rustc_target:: spec:: abi:: Abi as CallAbi ;
2121
22+ use crate :: dataflow_const_prop:: Patch ;
2223use crate :: MirPass ;
2324use rustc_const_eval:: interpret:: {
2425 self , compile_time_machine, AllocId , ConstAllocation , ConstValue , FnArg , Frame , ImmTy ,
@@ -83,43 +84,32 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
8384 return ;
8485 }
8586
86- let is_generator = tcx. type_of ( def_id. to_def_id ( ) ) . instantiate_identity ( ) . is_generator ( ) ;
8787 // FIXME(welseywiser) const prop doesn't work on generators because of query cycles
8888 // computing their layout.
89+ let is_generator = def_kind == DefKind :: Generator ;
8990 if is_generator {
9091 trace ! ( "ConstProp skipped for generator {:?}" , def_id) ;
9192 return ;
9293 }
9394
9495 trace ! ( "ConstProp starting for {:?}" , def_id) ;
9596
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-
10997 // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
11098 // constants, instead of just checking for const-folding succeeding.
11199 // That would require a uniform one-def no-mutation analysis
112100 // 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) ;
114102
115103 // Traverse the body in reverse post-order, to ensure that `FullConstProp` locals are
116104 // 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] ;
120107 optimization_finder. visit_basic_block_data ( bb, data) ;
121108 }
122109
110+ let mut patch = optimization_finder. patch ;
111+ patch. visit_body_preserves_cfg ( body) ;
112+
123113 trace ! ( "ConstProp done for {:?}" , def_id) ;
124114 }
125115}
@@ -143,8 +133,11 @@ impl ConstPropMachine<'_, '_> {
143133
144134impl < ' mir , ' tcx > interpret:: Machine < ' mir , ' tcx > for ConstPropMachine < ' mir , ' tcx > {
145135 compile_time_machine ! ( <' mir, ' tcx>) ;
136+
146137 const PANIC_ON_ALLOC_FAIL : bool = true ; // all allocations are small (see `MAX_ALLOC_LIMIT`)
147138
139+ const POST_MONO_CHECKS : bool = false ; // this MIR is still generic!
140+
148141 type MemoryKind = !;
149142
150143 #[ inline( always) ]
@@ -299,6 +292,7 @@ struct ConstPropagator<'mir, 'tcx> {
299292 tcx : TyCtxt < ' tcx > ,
300293 param_env : ParamEnv < ' tcx > ,
301294 local_decls : & ' mir IndexSlice < Local , LocalDecl < ' tcx > > ,
295+ patch : Patch < ' tcx > ,
302296}
303297
304298impl < ' tcx > LayoutOfHelpers < ' tcx > for ConstPropagator < ' _ , ' tcx > {
@@ -332,11 +326,7 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
332326}
333327
334328impl < ' 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 > {
340330 let def_id = body. source . def_id ( ) ;
341331 let args = & GenericArgs :: identity_for_item ( tcx, def_id) ;
342332 let param_env = tcx. param_env_reveal_all_normalized ( def_id) ;
@@ -367,7 +357,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
367357
368358 ecx. push_stack_frame (
369359 Instance :: new ( def_id, args) ,
370- dummy_body ,
360+ body ,
371361 & ret,
372362 StackPopCleanup :: Root { cleanup : false } ,
373363 )
@@ -382,7 +372,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
382372 ecx. frame_mut ( ) . locals [ local] . make_live_uninit ( ) ;
383373 }
384374
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 }
386377 }
387378
388379 fn get_const ( & self , place : Place < ' tcx > ) -> Option < OpTy < ' tcx > > {
@@ -419,12 +410,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
419410 ecx. machine . written_only_inside_own_block_locals . remove ( & local) ;
420411 }
421412
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-
428413 fn check_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > ) -> Option < ( ) > {
429414 // Perform any special handling for specific Rvalue types.
430415 // Generally, checks here fall into one of two categories:
@@ -540,16 +525,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
540525 }
541526 }
542527
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 > > {
553529 // This will return None if the above `const_prop` invocation only "wrote" a
554530 // type whose creation requires no write. E.g. a generator whose initial state
555531 // consists solely of uninitialized memory (so it doesn't capture any locals).
@@ -565,7 +541,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
565541 let Right ( imm) = imm else { return None } ;
566542 match * imm {
567543 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 ) )
569545 }
570546 Immediate :: ScalarPair ( l, r) if l. try_to_int ( ) . is_ok ( ) && r. try_to_int ( ) . is_ok ( ) => {
571547 let alloc = self
@@ -575,15 +551,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
575551 } )
576552 . ok ( ) ?;
577553
578- let literal = ConstantKind :: Val (
554+ Some ( ConstantKind :: Val (
579555 ConstValue :: ByRef { alloc, offset : Size :: ZERO } ,
580556 value. layout . ty ,
581- ) ;
582- Some ( Operand :: Constant ( Box :: new ( Constant {
583- span : DUMMY_SP ,
584- user_ty : None ,
585- literal,
586- } ) ) )
557+ ) )
587558 }
588559 // Scalars or scalar pairs that contain undef values are assumed to not have
589560 // successfully evaluated and are thus not propagated.
@@ -725,40 +696,29 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
725696 }
726697}
727698
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 ) {
734701 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+ }
736705 }
737706
738- fn process_projection_elem (
707+ fn visit_projection_elem (
739708 & mut self ,
709+ _: PlaceRef < ' tcx > ,
740710 elem : PlaceElem < ' tcx > ,
741- _: Location ,
742- ) -> Option < PlaceElem < ' tcx > > {
711+ _: PlaceContext ,
712+ location : Location ,
713+ ) {
743714 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 ( ) )
749716 {
750- Some ( PlaceElem :: ConstantIndex { offset, min_length, from_end : false } )
751- } else {
752- None
717+ self . patch . before_effect . insert ( ( location, local. into ( ) ) , value) ;
753718 }
754719 }
755720
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 ) {
762722 self . super_assign ( place, rvalue, location) ;
763723
764724 let Some ( ( ) ) = self . check_rvalue ( rvalue) else { return } ;
@@ -775,7 +735,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
775735 {
776736 trace ! ( "skipping replace of Rvalue::Use({:?} because it is already a const" , c) ;
777737 } else if let Some ( operand) = self . replace_with_const ( * place) {
778- * rvalue = Rvalue :: Use ( operand) ;
738+ self . patch . assignments . insert ( location , operand) ;
779739 }
780740 } else {
781741 // Const prop failed, so erase the destination, ensuring that whatever happens
@@ -799,7 +759,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
799759 }
800760 }
801761
802- fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
762+ fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
803763 trace ! ( "visit_statement: {:?}" , statement) ;
804764
805765 // We want to evaluate operands before any change to the assigned-to value,
@@ -843,7 +803,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
843803 }
844804 }
845805
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 > ) {
847807 self . super_basic_block_data ( block, data) ;
848808
849809 // We remove all Locals which are restricted in propagation to their containing blocks and
0 commit comments