@@ -364,7 +364,10 @@ struct VnState<'body, 'a, 'tcx> {
364364 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
365365 values : ValueSet < ' a , ' tcx > ,
366366 /// Values evaluated as constants if possible.
367- evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
367+ /// - `None` are values not computed yet;
368+ /// - `Some(None)` are values for which computation has failed;
369+ /// - `Some(Some(op))` are successful computations.
370+ evaluated : IndexVec < VnIndex , Option < Option < & ' a OpTy < ' tcx > > > > ,
368371 /// Cache the deref values.
369372 derefs : Vec < VnIndex > ,
370373 ssa : & ' body SsaLocals ,
@@ -416,8 +419,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
416419 let ( index, new) = self . values . insert ( ty, value) ;
417420 if new {
418421 // Grow `evaluated` and `rev_locals` here to amortize the allocations.
419- let evaluated = self . eval_to_const ( index) ;
420- let _index = self . evaluated . push ( evaluated) ;
422+ let _index = self . evaluated . push ( None ) ;
421423 debug_assert_eq ! ( index, _index) ;
422424 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
423425 debug_assert_eq ! ( index, _index) ;
@@ -430,7 +432,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
430432 #[ instrument( level = "trace" , skip( self ) , ret) ]
431433 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
432434 let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
433- let _index = self . evaluated . push ( None ) ;
435+ let _index = self . evaluated . push ( Some ( None ) ) ;
434436 debug_assert_eq ! ( index, _index) ;
435437 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
436438 debug_assert_eq ! ( index, _index) ;
@@ -468,8 +470,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
468470 kind,
469471 provenance,
470472 } ) ;
471- let evaluated = self . eval_to_const ( index) ;
472- let _index = self . evaluated . push ( evaluated) ;
473+ let _index = self . evaluated . push ( None ) ;
473474 debug_assert_eq ! ( index, _index) ;
474475 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
475476 debug_assert_eq ! ( index, _index) ;
@@ -493,8 +494,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
493494 ( index, true )
494495 } ;
495496 if new {
496- let evaluated = self . eval_to_const ( index) ;
497- let _index = self . evaluated . push ( evaluated) ;
497+ let _index = self . evaluated . push ( None ) ;
498498 debug_assert_eq ! ( index, _index) ;
499499 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
500500 debug_assert_eq ! ( index, _index) ;
@@ -551,7 +551,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
551551 }
552552
553553 #[ instrument( level = "trace" , skip( self ) , ret) ]
554- fn eval_to_const ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
554+ fn eval_to_const_inner ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
555555 use Value :: * ;
556556 let ty = self . ty ( value) ;
557557 // Avoid computing layouts inside a coroutine, as that can cause cycles.
@@ -571,10 +571,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
571571 self . ecx . eval_mir_constant ( value, DUMMY_SP , None ) . discard_err ( ) ?
572572 }
573573 Aggregate ( variant, ref fields) => {
574- let fields = fields
575- . iter ( )
576- . map ( |& f| self . evaluated [ f] . as_ref ( ) )
577- . collect :: < Option < Vec < _ > > > ( ) ?;
574+ let fields =
575+ fields. iter ( ) . map ( |& f| self . eval_to_const ( f) ) . collect :: < Option < Vec < _ > > > ( ) ?;
578576 let variant = if ty. ty . is_enum ( ) { Some ( variant) } else { None } ;
579577 if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
580578 {
@@ -603,7 +601,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
603601 }
604602 }
605603 Union ( active_field, field) => {
606- let field = self . evaluated [ field ] . as_ref ( ) ?;
604+ let field = self . eval_to_const ( field ) ?;
607605 if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
608606 {
609607 let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
@@ -618,8 +616,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
618616 }
619617 }
620618 RawPtr { pointer, metadata } => {
621- let pointer = self . evaluated [ pointer ] . as_ref ( ) ?;
622- let metadata = self . evaluated [ metadata ] . as_ref ( ) ?;
619+ let pointer = self . eval_to_const ( pointer ) ?;
620+ let metadata = self . eval_to_const ( metadata ) ?;
623621
624622 // Pointers don't have fields, so don't `project_field` them.
625623 let data = self . ecx . read_pointer ( pointer) . discard_err ( ) ?;
@@ -633,7 +631,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
633631 }
634632
635633 Projection ( base, elem) => {
636- let base = self . evaluated [ base ] . as_ref ( ) ?;
634+ let base = self . eval_to_const ( base ) ?;
637635 // `Index` by constants should have been replaced by `ConstantIndex` by
638636 // `simplify_place_projection`.
639637 let elem = elem. try_map ( |_| None , |( ) | ty. ty ) ?;
@@ -642,7 +640,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
642640 Address { base, projection, .. } => {
643641 debug_assert ! ( !projection. contains( & ProjectionElem :: Deref ) ) ;
644642 let pointer = match base {
645- AddressBase :: Deref ( pointer) => self . evaluated [ pointer ] . as_ref ( ) ?,
643+ AddressBase :: Deref ( pointer) => self . eval_to_const ( pointer ) ?,
646644 // We have no stack to point to.
647645 AddressBase :: Local ( _) => return None ,
648646 } ;
@@ -658,7 +656,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
658656 }
659657
660658 Discriminant ( base) => {
661- let base = self . evaluated [ base ] . as_ref ( ) ?;
659+ let base = self . eval_to_const ( base ) ?;
662660 let variant = self . ecx . read_discriminant ( base) . discard_err ( ) ?;
663661 let discr_value =
664662 self . ecx . discriminant_for_variant ( base. layout . ty , variant) . discard_err ( ) ?;
@@ -675,7 +673,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
675673 NullOp :: SizeOf => arg_layout. size . bytes ( ) ,
676674 NullOp :: AlignOf => arg_layout. align . bytes ( ) ,
677675 NullOp :: OffsetOf ( fields) => self
678- . ecx
679676 . tcx
680677 . offset_of_subfield ( self . typing_env ( ) , arg_layout, fields. iter ( ) )
681678 . bytes ( ) ,
@@ -685,34 +682,34 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
685682 ImmTy :: from_uint ( val, ty) . into ( )
686683 }
687684 UnaryOp ( un_op, operand) => {
688- let operand = self . evaluated [ operand ] . as_ref ( ) ?;
685+ let operand = self . eval_to_const ( operand ) ?;
689686 let operand = self . ecx . read_immediate ( operand) . discard_err ( ) ?;
690687 let val = self . ecx . unary_op ( un_op, & operand) . discard_err ( ) ?;
691688 val. into ( )
692689 }
693690 BinaryOp ( bin_op, lhs, rhs) => {
694- let lhs = self . evaluated [ lhs] . as_ref ( ) ?;
691+ let lhs = self . eval_to_const ( lhs) ?;
692+ let rhs = self . eval_to_const ( rhs) ?;
695693 let lhs = self . ecx . read_immediate ( lhs) . discard_err ( ) ?;
696- let rhs = self . evaluated [ rhs] . as_ref ( ) ?;
697694 let rhs = self . ecx . read_immediate ( rhs) . discard_err ( ) ?;
698695 let val = self . ecx . binary_op ( bin_op, & lhs, & rhs) . discard_err ( ) ?;
699696 val. into ( )
700697 }
701698 Cast { kind, value } => match kind {
702699 CastKind :: IntToInt | CastKind :: IntToFloat => {
703- let value = self . evaluated [ value ] . as_ref ( ) ?;
700+ let value = self . eval_to_const ( value ) ?;
704701 let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
705702 let res = self . ecx . int_to_int_or_float ( & value, ty) . discard_err ( ) ?;
706703 res. into ( )
707704 }
708705 CastKind :: FloatToFloat | CastKind :: FloatToInt => {
709- let value = self . evaluated [ value ] . as_ref ( ) ?;
706+ let value = self . eval_to_const ( value ) ?;
710707 let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
711708 let res = self . ecx . float_to_float_or_int ( & value, ty) . discard_err ( ) ?;
712709 res. into ( )
713710 }
714711 CastKind :: Transmute | CastKind :: Subtype => {
715- let value = self . evaluated [ value ] . as_ref ( ) ?;
712+ let value = self . eval_to_const ( value ) ?;
716713 // `offset` for immediates generally only supports projections that match the
717714 // type of the immediate. However, as a HACK, we exploit that it can also do
718715 // limited transmutes: it only works between types with the same layout, and
@@ -724,12 +721,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
724721 && !matches ! ( s1. primitive( ) , Primitive :: Pointer ( ..) )
725722 }
726723 ( BackendRepr :: ScalarPair ( a1, b1) , BackendRepr :: ScalarPair ( a2, b2) ) => {
727- a1. size ( & self . ecx ) == a2. size ( & self . ecx ) &&
728- b1. size ( & self . ecx ) == b2. size ( & self . ecx ) &&
729- // The alignment of the second component determines its offset, so that also needs to match.
730- b1. align ( & self . ecx ) == b2. align ( & self . ecx ) &&
731- // None of the inputs may be a pointer.
732- !matches ! ( a1. primitive( ) , Primitive :: Pointer ( ..) )
724+ a1. size ( & self . ecx ) == a2. size ( & self . ecx )
725+ && b1. size ( & self . ecx ) == b2. size ( & self . ecx )
726+ // The alignment of the second component determines its offset, so that also needs to match.
727+ && b1. align ( & self . ecx ) == b2. align ( & self . ecx )
728+ // None of the inputs may be a pointer.
729+ && !matches ! ( a1. primitive( ) , Primitive :: Pointer ( ..) )
733730 && !matches ! ( b1. primitive( ) , Primitive :: Pointer ( ..) )
734731 }
735732 _ => false ,
@@ -741,7 +738,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
741738 value. offset ( Size :: ZERO , ty, & self . ecx ) . discard_err ( ) ?
742739 }
743740 CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize , _) => {
744- let src = self . evaluated [ value ] . as_ref ( ) ?;
741+ let src = self . eval_to_const ( value ) ?;
745742 let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
746743 self . ecx . unsize_into ( src, ty, & dest) . discard_err ( ) ?;
747744 self . ecx
@@ -750,13 +747,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
750747 dest. into ( )
751748 }
752749 CastKind :: FnPtrToPtr | CastKind :: PtrToPtr => {
753- let src = self . evaluated [ value ] . as_ref ( ) ?;
750+ let src = self . eval_to_const ( value ) ?;
754751 let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
755752 let ret = self . ecx . ptr_to_ptr ( & src, ty) . discard_err ( ) ?;
756753 ret. into ( )
757754 }
758755 CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: UnsafeFnPointer , _) => {
759- let src = self . evaluated [ value ] . as_ref ( ) ?;
756+ let src = self . eval_to_const ( value ) ?;
760757 let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
761758 ImmTy :: from_immediate ( * src, ty) . into ( )
762759 }
@@ -766,6 +763,15 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
766763 Some ( op)
767764 }
768765
766+ fn eval_to_const ( & mut self , index : VnIndex ) -> Option < & ' a OpTy < ' tcx > > {
767+ if let Some ( op) = self . evaluated [ index] {
768+ return op;
769+ }
770+ let op = self . eval_to_const_inner ( index) ;
771+ self . evaluated [ index] = Some ( self . arena . alloc ( op) . as_ref ( ) ) ;
772+ self . evaluated [ index] . unwrap ( )
773+ }
774+
769775 /// Represent the *value* we obtain by dereferencing an `Address` value.
770776 #[ instrument( level = "trace" , skip( self ) , ret) ]
771777 fn dereference_address (
@@ -901,7 +907,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
901907 if let ProjectionElem :: Index ( idx_local) = elem
902908 && let Some ( idx) = self . locals [ idx_local]
903909 {
904- if let Some ( offset) = self . evaluated [ idx ] . as_ref ( )
910+ if let Some ( offset) = self . eval_to_const ( idx )
905911 && let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
906912 && let Some ( min_length) = offset. checked_add ( 1 )
907913 {
@@ -1389,8 +1395,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
13891395
13901396 let layout = self . ecx . layout_of ( lhs_ty) . ok ( ) ?;
13911397
1392- let as_bits = |value : VnIndex | {
1393- let constant = self . evaluated [ value ] . as_ref ( ) ?;
1398+ let mut as_bits = |value : VnIndex | {
1399+ let constant = self . eval_to_const ( value ) ?;
13941400 if layout. backend_repr . is_scalar ( ) {
13951401 let scalar = self . ecx . read_scalar ( constant) . discard_err ( ) ?;
13961402 scalar. to_bits ( constant. layout . size ) . discard_err ( )
@@ -1790,7 +1796,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17901796 return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
17911797 }
17921798
1793- let op = self . evaluated [ index ] . as_ref ( ) ?;
1799+ let op = self . eval_to_const ( index ) ?;
17941800 if op. layout . is_unsized ( ) {
17951801 // Do not attempt to propagate unsized locals.
17961802 return None ;
0 commit comments