@@ -14,8 +14,7 @@ use rustc_middle::mir::visit::{
1414} ;
1515use rustc_middle:: mir:: * ;
1616use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf , LayoutOfHelpers , TyAndLayout } ;
17- use rustc_middle:: ty:: GenericArgs ;
18- use rustc_middle:: ty:: { self , ConstKind , Instance , ParamEnv , Ty , TyCtxt , TypeVisitableExt } ;
17+ use rustc_middle:: ty:: { self , GenericArgs , Instance , ParamEnv , Ty , TyCtxt , TypeVisitableExt } ;
1918use rustc_span:: { def_id:: DefId , Span , DUMMY_SP } ;
2019use rustc_target:: abi:: { self , Align , HasDataLayout , Size , TargetDataLayout } ;
2120use rustc_target:: spec:: abi:: Abi as CallAbi ;
@@ -434,24 +433,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
434433 }
435434
436435 fn propagate_operand ( & mut self , operand : & mut Operand < ' tcx > ) {
437- match * operand {
438- Operand :: Copy ( l) | Operand :: Move ( l) => {
439- if let Some ( value) = self . get_const ( l) && self . should_const_prop ( & value) {
440- // FIXME(felix91gr): this code only handles `Scalar` cases.
441- // For now, we're not handling `ScalarPair` cases because
442- // doing so here would require a lot of code duplication.
443- // We should hopefully generalize `Operand` handling into a fn,
444- // and use it to do const-prop here and everywhere else
445- // where it makes sense.
446- if let interpret:: Operand :: Immediate ( interpret:: Immediate :: Scalar (
447- scalar,
448- ) ) = * value
449- {
450- * operand = self . operand_from_scalar ( scalar, value. layout . ty ) ;
451- }
452- }
453- }
454- Operand :: Constant ( _) => ( ) ,
436+ if let Some ( place) = operand. place ( ) && let Some ( op) = self . replace_with_const ( place) {
437+ * operand = op;
455438 }
456439 }
457440
@@ -579,78 +562,63 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
579562 } ) )
580563 }
581564
582- fn replace_with_const ( & mut self , place : Place < ' tcx > , rval : & mut Rvalue < ' tcx > ) {
565+ fn replace_with_const ( & mut self , place : Place < ' tcx > ) -> Option < Operand < ' tcx > > {
583566 // This will return None if the above `const_prop` invocation only "wrote" a
584567 // type whose creation requires no write. E.g. a generator whose initial state
585568 // consists solely of uninitialized memory (so it doesn't capture any locals).
586- let Some ( ref value) = self . get_const ( place) else { return } ;
587- if !self . should_const_prop ( value) {
588- return ;
589- }
590- trace ! ( "replacing {:?}={:?} with {:?}" , place, rval, value) ;
591-
592- if let Rvalue :: Use ( Operand :: Constant ( c) ) = rval {
593- match c. literal {
594- ConstantKind :: Ty ( c) if matches ! ( c. kind( ) , ConstKind :: Unevaluated ( ..) ) => { }
595- _ => {
596- trace ! ( "skipping replace of Rvalue::Use({:?} because it is already a const" , c) ;
597- return ;
598- }
599- }
569+ let value = self . get_const ( place) ?;
570+ if !self . should_const_prop ( & value) {
571+ return None ;
600572 }
573+ trace ! ( "replacing {:?} with {:?}" , place, value) ;
601574
602- trace ! ( "attempting to replace {:?} with {:?}" , rval, value) ;
603575 // FIXME> figure out what to do when read_immediate_raw fails
604- let imm = self . ecx . read_immediate_raw ( value) . ok ( ) ;
576+ let imm = self . ecx . read_immediate_raw ( & value) . ok ( ) ? ;
605577
606- if let Some ( Right ( imm) ) = imm {
607- match * imm {
608- interpret:: Immediate :: Scalar ( scalar) => {
609- * rval = Rvalue :: Use ( self . operand_from_scalar ( scalar, value. layout . ty ) ) ;
610- }
611- Immediate :: ScalarPair ( ..) => {
612- // Found a value represented as a pair. For now only do const-prop if the type
613- // of `rvalue` is also a tuple with two scalars.
614- // FIXME: enable the general case stated above ^.
615- let ty = value. layout . ty ;
616- // Only do it for tuples
617- if let ty:: Tuple ( types) = ty. kind ( ) {
618- // Only do it if tuple is also a pair with two scalars
619- if let [ ty1, ty2] = types[ ..] {
620- let ty_is_scalar = |ty| {
621- self . ecx . layout_of ( ty) . ok ( ) . map ( |layout| layout. abi . is_scalar ( ) )
622- == Some ( true )
623- } ;
624- let alloc = if ty_is_scalar ( ty1) && ty_is_scalar ( ty2) {
625- let alloc = self
626- . ecx
627- . intern_with_temp_alloc ( value. layout , |ecx, dest| {
628- ecx. write_immediate ( * imm, dest)
629- } )
630- . unwrap ( ) ;
631- Some ( alloc)
632- } else {
633- None
634- } ;
635-
636- if let Some ( alloc) = alloc {
637- // Assign entire constant in a single statement.
638- // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
639- let const_val = ConstValue :: ByRef { alloc, offset : Size :: ZERO } ;
640- let literal = ConstantKind :: Val ( const_val, ty) ;
641- * rval = Rvalue :: Use ( Operand :: Constant ( Box :: new ( Constant {
642- span : DUMMY_SP ,
643- user_ty : None ,
644- literal,
645- } ) ) ) ;
646- }
647- }
648- }
578+ let Right ( imm) = imm else { return None } ;
579+ match * imm {
580+ interpret:: Immediate :: Scalar ( scalar) => {
581+ Some ( self . operand_from_scalar ( scalar, value. layout . ty ) )
582+ }
583+ Immediate :: ScalarPair ( ..) => {
584+ // Found a value represented as a pair. For now only do const-prop if the type
585+ // of `rvalue` is also a tuple with two scalars.
586+ // FIXME: enable the general case stated above ^.
587+ let ty = value. layout . ty ;
588+ // Only do it for tuples
589+ let ty:: Tuple ( types) = ty. kind ( ) else { return None } ;
590+ // Only do it if tuple is also a pair with two scalars
591+ if let [ ty1, ty2] = types[ ..] {
592+ let ty_is_scalar = |ty| {
593+ self . ecx . layout_of ( ty) . ok ( ) . map ( |layout| layout. abi . is_scalar ( ) )
594+ == Some ( true )
595+ } ;
596+ let alloc = if ty_is_scalar ( ty1) && ty_is_scalar ( ty2) {
597+ self . ecx
598+ . intern_with_temp_alloc ( value. layout , |ecx, dest| {
599+ ecx. write_immediate ( * imm, dest)
600+ } )
601+ . unwrap ( )
602+ } else {
603+ return None ;
604+ } ;
605+
606+ // Assign entire constant in a single statement.
607+ // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
608+ let const_val = ConstValue :: ByRef { alloc, offset : Size :: ZERO } ;
609+ let literal = ConstantKind :: Val ( const_val, ty) ;
610+ Some ( Operand :: Constant ( Box :: new ( Constant {
611+ span : DUMMY_SP ,
612+ user_ty : None ,
613+ literal,
614+ } ) ) )
615+ } else {
616+ None
649617 }
650- // Scalars or scalar pairs that contain undef values are assumed to not have
651- // successfully evaluated and are thus not propagated.
652- _ => { }
653618 }
619+ // Scalars or scalar pairs that contain undef values are assumed to not have
620+ // successfully evaluated and are thus not propagated.
621+ _ => None ,
654622 }
655623 }
656624
@@ -847,7 +815,14 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
847815 ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
848816 ConstPropMode :: OnlyInsideOwnBlock | ConstPropMode :: FullConstProp => {
849817 if let Some ( ( ) ) = self . eval_rvalue_with_identities ( rvalue, * place) {
850- self . replace_with_const ( * place, rvalue) ;
818+ // If this was already an evaluated constant, keep it.
819+ if let Rvalue :: Use ( Operand :: Constant ( c) ) = rvalue
820+ && let ConstantKind :: Val ( ..) = c. literal
821+ {
822+ trace ! ( "skipping replace of Rvalue::Use({:?} because it is already a const" , c) ;
823+ } else if let Some ( operand) = self . replace_with_const ( * place) {
824+ * rvalue = Rvalue :: Use ( operand) ;
825+ }
851826 } else {
852827 // Const prop failed, so erase the destination, ensuring that whatever happens
853828 // from here on, does not know about the previous value.
0 commit comments