@@ -351,7 +351,7 @@ struct VnState<'body, 'a, 'tcx> {
351351 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
352352 values : ValueSet < ' a , ' tcx > ,
353353 /// Values evaluated as constants if possible.
354- evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
354+ evaluated : IndexVec < VnIndex , Option < Option < & ' a OpTy < ' tcx > > > > ,
355355 /// Cache the deref values.
356356 derefs : Vec < VnIndex > ,
357357 ssa : & ' body SsaLocals ,
@@ -403,8 +403,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
403403 let ( index, new) = self . values . insert ( ty, value) ;
404404 if new {
405405 // Grow `evaluated` and `rev_locals` here to amortize the allocations.
406- let evaluated = self . eval_to_const ( index) ;
407- let _index = self . evaluated . push ( evaluated) ;
406+ let _index = self . evaluated . push ( None ) ;
408407 debug_assert_eq ! ( index, _index) ;
409408 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
410409 debug_assert_eq ! ( index, _index) ;
@@ -417,7 +416,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
417416 #[ instrument( level = "trace" , skip( self ) , ret) ]
418417 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
419418 let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
420- let _index = self . evaluated . push ( None ) ;
419+ let _index = self . evaluated . push ( Some ( None ) ) ;
421420 debug_assert_eq ! ( index, _index) ;
422421 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
423422 debug_assert_eq ! ( index, _index) ;
@@ -436,8 +435,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
436435 } ;
437436 let index =
438437 self . values . insert_unique ( ty, |provenance| Value :: Address { place, kind, provenance } ) ;
439- let evaluated = self . eval_to_const ( index) ;
440- let _index = self . evaluated . push ( evaluated) ;
438+ let _index = self . evaluated . push ( None ) ;
441439 debug_assert_eq ! ( index, _index) ;
442440 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
443441 debug_assert_eq ! ( index, _index) ;
@@ -460,8 +458,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
460458 ( index, true )
461459 } ;
462460 if new {
463- let evaluated = self . eval_to_const ( index) ;
464- let _index = self . evaluated . push ( evaluated) ;
461+ let _index = self . evaluated . push ( None ) ;
465462 debug_assert_eq ! ( index, _index) ;
466463 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
467464 debug_assert_eq ! ( index, _index) ;
@@ -518,7 +515,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
518515 }
519516
520517 #[ instrument( level = "trace" , skip( self ) , ret) ]
521- fn eval_to_const ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
518+ fn eval_to_const_inner ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
522519 use Value :: * ;
523520 let ty = self . ty ( value) ;
524521 // Avoid computing layouts inside a coroutine, as that can cause cycles.
@@ -538,10 +535,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
538535 self . ecx . eval_mir_constant ( value, DUMMY_SP , None ) . discard_err ( ) ?
539536 }
540537 Aggregate ( variant, ref fields) => {
541- let fields = fields
542- . iter ( )
543- . map ( |& f| self . evaluated [ f] . as_ref ( ) )
544- . collect :: < Option < Vec < _ > > > ( ) ?;
538+ let fields =
539+ fields. iter ( ) . map ( |& f| self . eval_to_const ( f) ) . collect :: < Option < Vec < _ > > > ( ) ?;
545540 let variant = if ty. ty . is_enum ( ) { Some ( variant) } else { None } ;
546541 if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
547542 {
@@ -570,8 +565,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
570565 }
571566 }
572567 RawPtr { pointer, metadata } => {
573- let pointer = self . evaluated [ pointer ] . as_ref ( ) ?;
574- let metadata = self . evaluated [ metadata ] . as_ref ( ) ?;
568+ let pointer = self . eval_to_const ( pointer ) ?;
569+ let metadata = self . eval_to_const ( metadata ) ?;
575570
576571 // Pointers don't have fields, so don't `project_field` them.
577572 let data = self . ecx . read_pointer ( pointer) . discard_err ( ) ?;
@@ -585,7 +580,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
585580 }
586581
587582 Projection ( base, elem) => {
588- let base = self . evaluated [ base ] . as_ref ( ) ?;
583+ let base = self . eval_to_const ( base ) ?;
589584 // `Index` by constants should have been replaced by `ConstantIndex` by
590585 // `simplify_place_projection`.
591586 let elem = elem. try_map ( |_| None , |( ) | ty. ty ) ?;
@@ -596,7 +591,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
596591 return None ;
597592 }
598593 let local = self . locals [ place. local ] ?;
599- let pointer = self . evaluated [ local ] . as_ref ( ) ?;
594+ let pointer = self . eval_to_const ( local ) ?;
600595 let mut mplace = self . ecx . deref_pointer ( pointer) . discard_err ( ) ?;
601596 for elem in place. projection . iter ( ) . skip ( 1 ) {
602597 // `Index` by constants should have been replaced by `ConstantIndex` by
@@ -609,7 +604,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
609604 }
610605
611606 Discriminant ( base) => {
612- let base = self . evaluated [ base ] . as_ref ( ) ?;
607+ let base = self . eval_to_const ( base ) ?;
613608 let variant = self . ecx . read_discriminant ( base) . discard_err ( ) ?;
614609 let discr_value =
615610 self . ecx . discriminant_for_variant ( base. layout . ty , variant) . discard_err ( ) ?;
@@ -626,7 +621,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
626621 NullOp :: SizeOf => arg_layout. size . bytes ( ) ,
627622 NullOp :: AlignOf => arg_layout. align . bytes ( ) ,
628623 NullOp :: OffsetOf ( fields) => self
629- . ecx
630624 . tcx
631625 . offset_of_subfield ( self . typing_env ( ) , arg_layout, fields. iter ( ) )
632626 . bytes ( ) ,
@@ -636,34 +630,34 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
636630 ImmTy :: from_uint ( val, ty) . into ( )
637631 }
638632 UnaryOp ( un_op, operand) => {
639- let operand = self . evaluated [ operand ] . as_ref ( ) ?;
633+ let operand = self . eval_to_const ( operand ) ?;
640634 let operand = self . ecx . read_immediate ( operand) . discard_err ( ) ?;
641635 let val = self . ecx . unary_op ( un_op, & operand) . discard_err ( ) ?;
642636 val. into ( )
643637 }
644638 BinaryOp ( bin_op, lhs, rhs) => {
645- let lhs = self . evaluated [ lhs] . as_ref ( ) ?;
639+ let lhs = self . eval_to_const ( lhs) ?;
640+ let rhs = self . eval_to_const ( rhs) ?;
646641 let lhs = self . ecx . read_immediate ( lhs) . discard_err ( ) ?;
647- let rhs = self . evaluated [ rhs] . as_ref ( ) ?;
648642 let rhs = self . ecx . read_immediate ( rhs) . discard_err ( ) ?;
649643 let val = self . ecx . binary_op ( bin_op, & lhs, & rhs) . discard_err ( ) ?;
650644 val. into ( )
651645 }
652646 Cast { kind, value } => match kind {
653647 CastKind :: IntToInt | CastKind :: IntToFloat => {
654- let value = self . evaluated [ value ] . as_ref ( ) ?;
648+ let value = self . eval_to_const ( value ) ?;
655649 let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
656650 let res = self . ecx . int_to_int_or_float ( & value, ty) . discard_err ( ) ?;
657651 res. into ( )
658652 }
659653 CastKind :: FloatToFloat | CastKind :: FloatToInt => {
660- let value = self . evaluated [ value ] . as_ref ( ) ?;
654+ let value = self . eval_to_const ( value ) ?;
661655 let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
662656 let res = self . ecx . float_to_float_or_int ( & value, ty) . discard_err ( ) ?;
663657 res. into ( )
664658 }
665659 CastKind :: Transmute | CastKind :: Subtype => {
666- let value = self . evaluated [ value ] . as_ref ( ) ?;
660+ let value = self . eval_to_const ( value ) ?;
667661 // `offset` for immediates generally only supports projections that match the
668662 // type of the immediate. However, as a HACK, we exploit that it can also do
669663 // limited transmutes: it only works between types with the same layout, and
@@ -675,12 +669,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
675669 && !matches ! ( s1. primitive( ) , Primitive :: Pointer ( ..) )
676670 }
677671 ( BackendRepr :: ScalarPair ( a1, b1) , BackendRepr :: ScalarPair ( a2, b2) ) => {
678- a1. size ( & self . ecx ) == a2. size ( & self . ecx ) &&
679- b1. size ( & self . ecx ) == b2. size ( & self . ecx ) &&
680- // The alignment of the second component determines its offset, so that also needs to match.
681- b1. align ( & self . ecx ) == b2. align ( & self . ecx ) &&
682- // None of the inputs may be a pointer.
683- !matches ! ( a1. primitive( ) , Primitive :: Pointer ( ..) )
672+ a1. size ( & self . ecx ) == a2. size ( & self . ecx )
673+ && b1. size ( & self . ecx ) == b2. size ( & self . ecx )
674+ // The alignment of the second component determines its offset, so that also needs to match.
675+ && b1. align ( & self . ecx ) == b2. align ( & self . ecx )
676+ // None of the inputs may be a pointer.
677+ && !matches ! ( a1. primitive( ) , Primitive :: Pointer ( ..) )
684678 && !matches ! ( b1. primitive( ) , Primitive :: Pointer ( ..) )
685679 }
686680 _ => false ,
@@ -692,7 +686,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
692686 value. offset ( Size :: ZERO , ty, & self . ecx ) . discard_err ( ) ?
693687 }
694688 CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize , _) => {
695- let src = self . evaluated [ value ] . as_ref ( ) ?;
689+ let src = self . eval_to_const ( value ) ?;
696690 let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
697691 self . ecx . unsize_into ( src, ty, & dest) . discard_err ( ) ?;
698692 self . ecx
@@ -701,13 +695,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
701695 dest. into ( )
702696 }
703697 CastKind :: FnPtrToPtr | CastKind :: PtrToPtr => {
704- let src = self . evaluated [ value ] . as_ref ( ) ?;
698+ let src = self . eval_to_const ( value ) ?;
705699 let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
706700 let ret = self . ecx . ptr_to_ptr ( & src, ty) . discard_err ( ) ?;
707701 ret. into ( )
708702 }
709703 CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: UnsafeFnPointer , _) => {
710- let src = self . evaluated [ value ] . as_ref ( ) ?;
704+ let src = self . eval_to_const ( value ) ?;
711705 let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
712706 ImmTy :: from_immediate ( * src, ty) . into ( )
713707 }
@@ -717,6 +711,15 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
717711 Some ( op)
718712 }
719713
714+ fn eval_to_const ( & mut self , index : VnIndex ) -> Option < & ' a OpTy < ' tcx > > {
715+ if let Some ( op) = self . evaluated [ index] {
716+ return op;
717+ }
718+ let op = self . eval_to_const_inner ( index) ;
719+ self . evaluated [ index] = Some ( self . arena . alloc ( op) . as_ref ( ) ) ;
720+ self . evaluated [ index] . unwrap ( )
721+ }
722+
720723 fn project (
721724 & mut self ,
722725 place_ty : PlaceTy < ' tcx > ,
@@ -822,7 +825,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
822825 if let ProjectionElem :: Index ( idx_local) = elem
823826 && let Some ( idx) = self . locals [ idx_local]
824827 {
825- if let Some ( offset) = self . evaluated [ idx ] . as_ref ( )
828+ if let Some ( offset) = self . eval_to_const ( idx )
826829 && let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
827830 && let Some ( min_length) = offset. checked_add ( 1 )
828831 {
@@ -1312,8 +1315,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
13121315
13131316 let layout = self . ecx . layout_of ( lhs_ty) . ok ( ) ?;
13141317
1315- let as_bits = |value : VnIndex | {
1316- let constant = self . evaluated [ value ] . as_ref ( ) ?;
1318+ let mut as_bits = |value : VnIndex | {
1319+ let constant = self . eval_to_const ( value ) ?;
13171320 if layout. backend_repr . is_scalar ( ) {
13181321 let scalar = self . ecx . read_scalar ( constant) . discard_err ( ) ?;
13191322 scalar. to_bits ( constant. layout . size ) . discard_err ( )
@@ -1713,7 +1716,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17131716 return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
17141717 }
17151718
1716- let op = self . evaluated [ index ] . as_ref ( ) ?;
1719+ let op = self . eval_to_const ( index ) ?;
17171720 if op. layout . is_unsized ( ) {
17181721 // Do not attempt to propagate unsized locals.
17191722 return None ;
0 commit comments