@@ -362,7 +362,10 @@ struct VnState<'body, 'a, 'tcx> {
362362 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
363363 values : ValueSet < ' a , ' tcx > ,
364364 /// Values evaluated as constants if possible.
365- evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
365+ /// - `None` are values not computed yet;
366+ /// - `Some(None)` are values for which computation has failed;
367+ /// - `Some(Some(op))` are successful computations.
368+ evaluated : IndexVec < VnIndex , Option < Option < & ' a OpTy < ' tcx > > > > ,
366369 /// Cache the deref values.
367370 derefs : Vec < VnIndex > ,
368371 ssa : & ' body SsaLocals ,
@@ -414,8 +417,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
414417 let ( index, new) = self . values . insert ( ty, value) ;
415418 if new {
416419 // Grow `evaluated` and `rev_locals` here to amortize the allocations.
417- let evaluated = self . eval_to_const ( index) ;
418- let _index = self . evaluated . push ( evaluated) ;
420+ let _index = self . evaluated . push ( None ) ;
419421 debug_assert_eq ! ( index, _index) ;
420422 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
421423 debug_assert_eq ! ( index, _index) ;
@@ -428,7 +430,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
428430 #[ instrument( level = "trace" , skip( self ) , ret) ]
429431 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
430432 let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
431- let _index = self . evaluated . push ( None ) ;
433+ let _index = self . evaluated . push ( Some ( None ) ) ;
432434 debug_assert_eq ! ( index, _index) ;
433435 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
434436 debug_assert_eq ! ( index, _index) ;
@@ -466,8 +468,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
466468 kind,
467469 provenance,
468470 } ) ;
469- let evaluated = self . eval_to_const ( index) ;
470- let _index = self . evaluated . push ( evaluated) ;
471+ let _index = self . evaluated . push ( None ) ;
471472 debug_assert_eq ! ( index, _index) ;
472473 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
473474 debug_assert_eq ! ( index, _index) ;
@@ -491,8 +492,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
491492 ( index, true )
492493 } ;
493494 if new {
494- let evaluated = self . eval_to_const ( index) ;
495- let _index = self . evaluated . push ( evaluated) ;
495+ let _index = self . evaluated . push ( None ) ;
496496 debug_assert_eq ! ( index, _index) ;
497497 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
498498 debug_assert_eq ! ( index, _index) ;
@@ -549,7 +549,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
549549 }
550550
551551 #[ instrument( level = "trace" , skip( self ) , ret) ]
552- fn eval_to_const ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
552+ fn eval_to_const_inner ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
553553 use Value :: * ;
554554 let ty = self . ty ( value) ;
555555 // Avoid computing layouts inside a coroutine, as that can cause cycles.
@@ -569,10 +569,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
569569 self . ecx . eval_mir_constant ( value, DUMMY_SP , None ) . discard_err ( ) ?
570570 }
571571 Aggregate ( variant, ref fields) => {
572- let fields = fields
573- . iter ( )
574- . map ( |& f| self . evaluated [ f] . as_ref ( ) )
575- . collect :: < Option < Vec < _ > > > ( ) ?;
572+ let fields =
573+ fields. iter ( ) . map ( |& f| self . eval_to_const ( f) ) . collect :: < Option < Vec < _ > > > ( ) ?;
576574 let variant = if ty. ty . is_enum ( ) { Some ( variant) } else { None } ;
577575 if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
578576 {
@@ -601,8 +599,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
601599 }
602600 }
603601 RawPtr { pointer, metadata } => {
604- let pointer = self . evaluated [ pointer ] . as_ref ( ) ?;
605- let metadata = self . evaluated [ metadata ] . as_ref ( ) ?;
602+ let pointer = self . eval_to_const ( pointer ) ?;
603+ let metadata = self . eval_to_const ( metadata ) ?;
606604
607605 // Pointers don't have fields, so don't `project_field` them.
608606 let data = self . ecx . read_pointer ( pointer) . discard_err ( ) ?;
@@ -616,7 +614,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
616614 }
617615
618616 Projection ( base, elem) => {
619- let base = self . evaluated [ base ] . as_ref ( ) ?;
617+ let base = self . eval_to_const ( base ) ?;
620618 // `Index` by constants should have been replaced by `ConstantIndex` by
621619 // `simplify_place_projection`.
622620 let elem = elem. try_map ( |_| None , |( ) | ty. ty ) ?;
@@ -625,7 +623,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
625623 Address { base, projection, .. } => {
626624 debug_assert ! ( !projection. contains( & ProjectionElem :: Deref ) ) ;
627625 let pointer = match base {
628- AddressBase :: Deref ( pointer) => self . evaluated [ pointer ] . as_ref ( ) ?,
626+ AddressBase :: Deref ( pointer) => self . eval_to_const ( pointer ) ?,
629627 // We have no stack to point to.
630628 AddressBase :: Local ( _) => return None ,
631629 } ;
@@ -641,7 +639,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
641639 }
642640
643641 Discriminant ( base) => {
644- let base = self . evaluated [ base ] . as_ref ( ) ?;
642+ let base = self . eval_to_const ( base ) ?;
645643 let variant = self . ecx . read_discriminant ( base) . discard_err ( ) ?;
646644 let discr_value =
647645 self . ecx . discriminant_for_variant ( base. layout . ty , variant) . discard_err ( ) ?;
@@ -658,7 +656,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
658656 NullOp :: SizeOf => arg_layout. size . bytes ( ) ,
659657 NullOp :: AlignOf => arg_layout. align . bytes ( ) ,
660658 NullOp :: OffsetOf ( fields) => self
661- . ecx
662659 . tcx
663660 . offset_of_subfield ( self . typing_env ( ) , arg_layout, fields. iter ( ) )
664661 . bytes ( ) ,
@@ -668,34 +665,34 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
668665 ImmTy :: from_uint ( val, ty) . into ( )
669666 }
670667 UnaryOp ( un_op, operand) => {
671- let operand = self . evaluated [ operand ] . as_ref ( ) ?;
668+ let operand = self . eval_to_const ( operand ) ?;
672669 let operand = self . ecx . read_immediate ( operand) . discard_err ( ) ?;
673670 let val = self . ecx . unary_op ( un_op, & operand) . discard_err ( ) ?;
674671 val. into ( )
675672 }
676673 BinaryOp ( bin_op, lhs, rhs) => {
677- let lhs = self . evaluated [ lhs] . as_ref ( ) ?;
674+ let lhs = self . eval_to_const ( lhs) ?;
675+ let rhs = self . eval_to_const ( rhs) ?;
678676 let lhs = self . ecx . read_immediate ( lhs) . discard_err ( ) ?;
679- let rhs = self . evaluated [ rhs] . as_ref ( ) ?;
680677 let rhs = self . ecx . read_immediate ( rhs) . discard_err ( ) ?;
681678 let val = self . ecx . binary_op ( bin_op, & lhs, & rhs) . discard_err ( ) ?;
682679 val. into ( )
683680 }
684681 Cast { kind, value } => match kind {
685682 CastKind :: IntToInt | CastKind :: IntToFloat => {
686- let value = self . evaluated [ value ] . as_ref ( ) ?;
683+ let value = self . eval_to_const ( value ) ?;
687684 let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
688685 let res = self . ecx . int_to_int_or_float ( & value, ty) . discard_err ( ) ?;
689686 res. into ( )
690687 }
691688 CastKind :: FloatToFloat | CastKind :: FloatToInt => {
692- let value = self . evaluated [ value ] . as_ref ( ) ?;
689+ let value = self . eval_to_const ( value ) ?;
693690 let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
694691 let res = self . ecx . float_to_float_or_int ( & value, ty) . discard_err ( ) ?;
695692 res. into ( )
696693 }
697694 CastKind :: Transmute | CastKind :: Subtype => {
698- let value = self . evaluated [ value ] . as_ref ( ) ?;
695+ let value = self . eval_to_const ( value ) ?;
699696 // `offset` for immediates generally only supports projections that match the
700697 // type of the immediate. However, as a HACK, we exploit that it can also do
701698 // limited transmutes: it only works between types with the same layout, and
@@ -707,12 +704,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
707704 && !matches ! ( s1. primitive( ) , Primitive :: Pointer ( ..) )
708705 }
709706 ( BackendRepr :: ScalarPair ( a1, b1) , BackendRepr :: ScalarPair ( a2, b2) ) => {
710- a1. size ( & self . ecx ) == a2. size ( & self . ecx ) &&
711- b1. size ( & self . ecx ) == b2. size ( & self . ecx ) &&
712- // The alignment of the second component determines its offset, so that also needs to match.
713- b1. align ( & self . ecx ) == b2. align ( & self . ecx ) &&
714- // None of the inputs may be a pointer.
715- !matches ! ( a1. primitive( ) , Primitive :: Pointer ( ..) )
707+ a1. size ( & self . ecx ) == a2. size ( & self . ecx )
708+ && b1. size ( & self . ecx ) == b2. size ( & self . ecx )
709+ // The alignment of the second component determines its offset, so that also needs to match.
710+ && b1. align ( & self . ecx ) == b2. align ( & self . ecx )
711+ // None of the inputs may be a pointer.
712+ && !matches ! ( a1. primitive( ) , Primitive :: Pointer ( ..) )
716713 && !matches ! ( b1. primitive( ) , Primitive :: Pointer ( ..) )
717714 }
718715 _ => false ,
@@ -724,7 +721,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
724721 value. offset ( Size :: ZERO , ty, & self . ecx ) . discard_err ( ) ?
725722 }
726723 CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize , _) => {
727- let src = self . evaluated [ value ] . as_ref ( ) ?;
724+ let src = self . eval_to_const ( value ) ?;
728725 let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
729726 self . ecx . unsize_into ( src, ty, & dest) . discard_err ( ) ?;
730727 self . ecx
@@ -733,13 +730,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
733730 dest. into ( )
734731 }
735732 CastKind :: FnPtrToPtr | CastKind :: PtrToPtr => {
736- let src = self . evaluated [ value ] . as_ref ( ) ?;
733+ let src = self . eval_to_const ( value ) ?;
737734 let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
738735 let ret = self . ecx . ptr_to_ptr ( & src, ty) . discard_err ( ) ?;
739736 ret. into ( )
740737 }
741738 CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: UnsafeFnPointer , _) => {
742- let src = self . evaluated [ value ] . as_ref ( ) ?;
739+ let src = self . eval_to_const ( value ) ?;
743740 let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
744741 ImmTy :: from_immediate ( * src, ty) . into ( )
745742 }
@@ -749,6 +746,15 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
749746 Some ( op)
750747 }
751748
749+ fn eval_to_const ( & mut self , index : VnIndex ) -> Option < & ' a OpTy < ' tcx > > {
750+ if let Some ( op) = self . evaluated [ index] {
751+ return op;
752+ }
753+ let op = self . eval_to_const_inner ( index) ;
754+ self . evaluated [ index] = Some ( self . arena . alloc ( op) . as_ref ( ) ) ;
755+ self . evaluated [ index] . unwrap ( )
756+ }
757+
752758 /// Represent the *value* we obtain by dereferencing an `Address` value.
753759 #[ instrument( level = "trace" , skip( self ) , ret) ]
754760 fn dereference_address (
@@ -884,7 +890,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
884890 if let ProjectionElem :: Index ( idx_local) = elem
885891 && let Some ( idx) = self . locals [ idx_local]
886892 {
887- if let Some ( offset) = self . evaluated [ idx ] . as_ref ( )
893+ if let Some ( offset) = self . eval_to_const ( idx )
888894 && let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
889895 && let Some ( min_length) = offset. checked_add ( 1 )
890896 {
@@ -1369,8 +1375,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
13691375
13701376 let layout = self . ecx . layout_of ( lhs_ty) . ok ( ) ?;
13711377
1372- let as_bits = |value : VnIndex | {
1373- let constant = self . evaluated [ value ] . as_ref ( ) ?;
1378+ let mut as_bits = |value : VnIndex | {
1379+ let constant = self . eval_to_const ( value ) ?;
13741380 if layout. backend_repr . is_scalar ( ) {
13751381 let scalar = self . ecx . read_scalar ( constant) . discard_err ( ) ?;
13761382 scalar. to_bits ( constant. layout . size ) . discard_err ( )
@@ -1770,7 +1776,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17701776 return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
17711777 }
17721778
1773- let op = self . evaluated [ index ] . as_ref ( ) ?;
1779+ let op = self . eval_to_const ( index ) ?;
17741780 if op. layout . is_unsized ( ) {
17751781 // Do not attempt to propagate unsized locals.
17761782 return None ;
0 commit comments