@@ -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 ,
@@ -120,6 +121,8 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
120121 optimization_finder. visit_basic_block_data ( bb, data) ;
121122 }
122123
124+ optimization_finder. patch . visit_body_preserves_cfg ( body) ;
125+
123126 trace ! ( "ConstProp done for {:?}" , def_id) ;
124127 }
125128}
@@ -302,6 +305,7 @@ struct ConstPropagator<'mir, 'tcx> {
302305 tcx : TyCtxt < ' tcx > ,
303306 param_env : ParamEnv < ' tcx > ,
304307 local_decls : & ' mir IndexSlice < Local , LocalDecl < ' tcx > > ,
308+ patch : Patch < ' tcx > ,
305309}
306310
307311impl < ' tcx > LayoutOfHelpers < ' tcx > for ConstPropagator < ' _ , ' tcx > {
@@ -385,7 +389,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
385389 ecx. frame_mut ( ) . locals [ local] . make_live_uninit ( ) ;
386390 }
387391
388- ConstPropagator { ecx, tcx, param_env, local_decls : & dummy_body. local_decls }
392+ let patch = Patch :: new ( tcx) ;
393+ ConstPropagator { ecx, tcx, param_env, local_decls : & dummy_body. local_decls , patch }
389394 }
390395
391396 fn get_const ( & self , place : Place < ' tcx > ) -> Option < OpTy < ' tcx > > {
@@ -422,12 +427,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
422427 ecx. machine . written_only_inside_own_block_locals . remove ( & local) ;
423428 }
424429
425- fn propagate_operand ( & mut self , operand : & mut Operand < ' tcx > ) {
426- if let Some ( place) = operand. place ( ) && let Some ( op) = self . replace_with_const ( place) {
427- * operand = op;
428- }
429- }
430-
431430 fn check_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > ) -> Option < ( ) > {
432431 // Perform any special handling for specific Rvalue types.
433432 // Generally, checks here fall into one of two categories:
@@ -543,16 +542,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
543542 }
544543 }
545544
546- /// Creates a new `Operand::Constant` from a `Scalar` value
547- fn operand_from_scalar ( & self , scalar : Scalar , ty : Ty < ' tcx > ) -> Operand < ' tcx > {
548- Operand :: Constant ( Box :: new ( Constant {
549- span : DUMMY_SP ,
550- user_ty : None ,
551- literal : ConstantKind :: from_scalar ( self . tcx , scalar, ty) ,
552- } ) )
553- }
554-
555- fn replace_with_const ( & mut self , place : Place < ' tcx > ) -> Option < Operand < ' tcx > > {
545+ fn replace_with_const ( & mut self , place : Place < ' tcx > ) -> Option < ConstantKind < ' tcx > > {
556546 // This will return None if the above `const_prop` invocation only "wrote" a
557547 // type whose creation requires no write. E.g. a generator whose initial state
558548 // consists solely of uninitialized memory (so it doesn't capture any locals).
@@ -568,7 +558,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
568558 let Right ( imm) = imm else { return None } ;
569559 match * imm {
570560 Immediate :: Scalar ( scalar) if scalar. try_to_int ( ) . is_ok ( ) => {
571- Some ( self . operand_from_scalar ( scalar, value. layout . ty ) )
561+ Some ( ConstantKind :: from_scalar ( self . tcx , scalar, value. layout . ty ) )
572562 }
573563 Immediate :: ScalarPair ( l, r) if l. try_to_int ( ) . is_ok ( ) && r. try_to_int ( ) . is_ok ( ) => {
574564 let alloc = self
@@ -578,15 +568,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
578568 } )
579569 . ok ( ) ?;
580570
581- let literal = ConstantKind :: Val (
571+ Some ( ConstantKind :: Val (
582572 ConstValue :: ByRef { alloc, offset : Size :: ZERO } ,
583573 value. layout . ty ,
584- ) ;
585- Some ( Operand :: Constant ( Box :: new ( Constant {
586- span : DUMMY_SP ,
587- user_ty : None ,
588- literal,
589- } ) ) )
574+ ) )
590575 }
591576 // Scalars or scalar pairs that contain undef values are assumed to not have
592577 // successfully evaluated and are thus not propagated.
@@ -728,40 +713,29 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
728713 }
729714}
730715
731- impl < ' tcx > MutVisitor < ' tcx > for ConstPropagator < ' _ , ' tcx > {
732- fn tcx ( & self ) -> TyCtxt < ' tcx > {
733- self . tcx
734- }
735-
736- fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
716+ impl < ' tcx > Visitor < ' tcx > for ConstPropagator < ' _ , ' tcx > {
717+ fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
737718 self . super_operand ( operand, location) ;
738- self . propagate_operand ( operand)
719+ if let Some ( place) = operand. place ( ) && let Some ( value) = self . replace_with_const ( place) {
720+ self . patch . before_effect . insert ( ( location, place) , value) ;
721+ }
739722 }
740723
741- fn process_projection_elem (
724+ fn visit_projection_elem (
742725 & mut self ,
726+ _: PlaceRef < ' tcx > ,
743727 elem : PlaceElem < ' tcx > ,
744- _: Location ,
745- ) -> Option < PlaceElem < ' tcx > > {
728+ _: PlaceContext ,
729+ location : Location ,
730+ ) {
746731 if let PlaceElem :: Index ( local) = elem
747- && let Some ( value) = self . get_const ( local. into ( ) )
748- && let Some ( imm) = value. as_mplace_or_imm ( ) . right ( )
749- && let Immediate :: Scalar ( scalar) = * imm
750- && let Ok ( offset) = scalar. to_target_usize ( & self . tcx )
751- && let Some ( min_length) = offset. checked_add ( 1 )
732+ && let Some ( value) = self . replace_with_const ( local. into ( ) )
752733 {
753- Some ( PlaceElem :: ConstantIndex { offset, min_length, from_end : false } )
754- } else {
755- None
734+ self . patch . before_effect . insert ( ( location, local. into ( ) ) , value) ;
756735 }
757736 }
758737
759- fn visit_assign (
760- & mut self ,
761- place : & mut Place < ' tcx > ,
762- rvalue : & mut Rvalue < ' tcx > ,
763- location : Location ,
764- ) {
738+ fn visit_assign ( & mut self , place : & Place < ' tcx > , rvalue : & Rvalue < ' tcx > , location : Location ) {
765739 self . super_assign ( place, rvalue, location) ;
766740
767741 let Some ( ( ) ) = self . check_rvalue ( rvalue) else { return } ;
@@ -778,7 +752,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
778752 {
779753 trace ! ( "skipping replace of Rvalue::Use({:?} because it is already a const" , c) ;
780754 } else if let Some ( operand) = self . replace_with_const ( * place) {
781- * rvalue = Rvalue :: Use ( operand) ;
755+ self . patch . assignments . insert ( location , operand) ;
782756 }
783757 } else {
784758 // Const prop failed, so erase the destination, ensuring that whatever happens
@@ -802,7 +776,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
802776 }
803777 }
804778
805- fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
779+ fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
806780 trace ! ( "visit_statement: {:?}" , statement) ;
807781
808782 // We want to evaluate operands before any change to the assigned-to value,
@@ -846,7 +820,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
846820 }
847821 }
848822
849- fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
823+ fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & BasicBlockData < ' tcx > ) {
850824 self . super_basic_block_data ( block, data) ;
851825
852826 // We remove all Locals which are restricted in propagation to their containing blocks and
0 commit comments