@@ -364,7 +364,10 @@ struct VnState<'body, 'a, 'tcx> {
364
364
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
365
365
values : ValueSet < ' a , ' tcx > ,
366
366
/// 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 > > > > ,
368
371
/// Cache the deref values.
369
372
derefs : Vec < VnIndex > ,
370
373
ssa : & ' body SsaLocals ,
@@ -416,8 +419,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
416
419
let ( index, new) = self . values . insert ( ty, value) ;
417
420
if new {
418
421
// 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 ) ;
421
423
debug_assert_eq ! ( index, _index) ;
422
424
let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
423
425
debug_assert_eq ! ( index, _index) ;
@@ -430,7 +432,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
430
432
#[ instrument( level = "trace" , skip( self ) , ret) ]
431
433
fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
432
434
let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
433
- let _index = self . evaluated . push ( None ) ;
435
+ let _index = self . evaluated . push ( Some ( None ) ) ;
434
436
debug_assert_eq ! ( index, _index) ;
435
437
let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
436
438
debug_assert_eq ! ( index, _index) ;
@@ -468,8 +470,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
468
470
kind,
469
471
provenance,
470
472
} ) ;
471
- let evaluated = self . eval_to_const ( index) ;
472
- let _index = self . evaluated . push ( evaluated) ;
473
+ let _index = self . evaluated . push ( None ) ;
473
474
debug_assert_eq ! ( index, _index) ;
474
475
let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
475
476
debug_assert_eq ! ( index, _index) ;
@@ -493,8 +494,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
493
494
( index, true )
494
495
} ;
495
496
if new {
496
- let evaluated = self . eval_to_const ( index) ;
497
- let _index = self . evaluated . push ( evaluated) ;
497
+ let _index = self . evaluated . push ( None ) ;
498
498
debug_assert_eq ! ( index, _index) ;
499
499
let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
500
500
debug_assert_eq ! ( index, _index) ;
@@ -551,7 +551,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
551
551
}
552
552
553
553
#[ 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 > > {
555
555
use Value :: * ;
556
556
let ty = self . ty ( value) ;
557
557
// Avoid computing layouts inside a coroutine, as that can cause cycles.
@@ -571,10 +571,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
571
571
self . ecx . eval_mir_constant ( value, DUMMY_SP , None ) . discard_err ( ) ?
572
572
}
573
573
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 < _ > > > ( ) ?;
578
576
let variant = if ty. ty . is_enum ( ) { Some ( variant) } else { None } ;
579
577
if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
580
578
{
@@ -603,7 +601,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
603
601
}
604
602
}
605
603
Union ( active_field, field) => {
606
- let field = self . evaluated [ field ] . as_ref ( ) ?;
604
+ let field = self . eval_to_const ( field ) ?;
607
605
if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
608
606
{
609
607
let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
@@ -618,8 +616,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
618
616
}
619
617
}
620
618
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 ) ?;
623
621
624
622
// Pointers don't have fields, so don't `project_field` them.
625
623
let data = self . ecx . read_pointer ( pointer) . discard_err ( ) ?;
@@ -633,7 +631,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
633
631
}
634
632
635
633
Projection ( base, elem) => {
636
- let base = self . evaluated [ base ] . as_ref ( ) ?;
634
+ let base = self . eval_to_const ( base ) ?;
637
635
// `Index` by constants should have been replaced by `ConstantIndex` by
638
636
// `simplify_place_projection`.
639
637
let elem = elem. try_map ( |_| None , |( ) | ty. ty ) ?;
@@ -642,7 +640,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
642
640
Address { base, projection, .. } => {
643
641
debug_assert ! ( !projection. contains( & ProjectionElem :: Deref ) ) ;
644
642
let pointer = match base {
645
- AddressBase :: Deref ( pointer) => self . evaluated [ pointer ] . as_ref ( ) ?,
643
+ AddressBase :: Deref ( pointer) => self . eval_to_const ( pointer ) ?,
646
644
// We have no stack to point to.
647
645
AddressBase :: Local ( _) => return None ,
648
646
} ;
@@ -658,7 +656,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
658
656
}
659
657
660
658
Discriminant ( base) => {
661
- let base = self . evaluated [ base ] . as_ref ( ) ?;
659
+ let base = self . eval_to_const ( base ) ?;
662
660
let variant = self . ecx . read_discriminant ( base) . discard_err ( ) ?;
663
661
let discr_value =
664
662
self . ecx . discriminant_for_variant ( base. layout . ty , variant) . discard_err ( ) ?;
@@ -675,7 +673,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
675
673
NullOp :: SizeOf => arg_layout. size . bytes ( ) ,
676
674
NullOp :: AlignOf => arg_layout. align . bytes ( ) ,
677
675
NullOp :: OffsetOf ( fields) => self
678
- . ecx
679
676
. tcx
680
677
. offset_of_subfield ( self . typing_env ( ) , arg_layout, fields. iter ( ) )
681
678
. bytes ( ) ,
@@ -685,34 +682,34 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
685
682
ImmTy :: from_uint ( val, ty) . into ( )
686
683
}
687
684
UnaryOp ( un_op, operand) => {
688
- let operand = self . evaluated [ operand ] . as_ref ( ) ?;
685
+ let operand = self . eval_to_const ( operand ) ?;
689
686
let operand = self . ecx . read_immediate ( operand) . discard_err ( ) ?;
690
687
let val = self . ecx . unary_op ( un_op, & operand) . discard_err ( ) ?;
691
688
val. into ( )
692
689
}
693
690
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) ?;
695
693
let lhs = self . ecx . read_immediate ( lhs) . discard_err ( ) ?;
696
- let rhs = self . evaluated [ rhs] . as_ref ( ) ?;
697
694
let rhs = self . ecx . read_immediate ( rhs) . discard_err ( ) ?;
698
695
let val = self . ecx . binary_op ( bin_op, & lhs, & rhs) . discard_err ( ) ?;
699
696
val. into ( )
700
697
}
701
698
Cast { kind, value } => match kind {
702
699
CastKind :: IntToInt | CastKind :: IntToFloat => {
703
- let value = self . evaluated [ value ] . as_ref ( ) ?;
700
+ let value = self . eval_to_const ( value ) ?;
704
701
let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
705
702
let res = self . ecx . int_to_int_or_float ( & value, ty) . discard_err ( ) ?;
706
703
res. into ( )
707
704
}
708
705
CastKind :: FloatToFloat | CastKind :: FloatToInt => {
709
- let value = self . evaluated [ value ] . as_ref ( ) ?;
706
+ let value = self . eval_to_const ( value ) ?;
710
707
let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
711
708
let res = self . ecx . float_to_float_or_int ( & value, ty) . discard_err ( ) ?;
712
709
res. into ( )
713
710
}
714
711
CastKind :: Transmute | CastKind :: Subtype => {
715
- let value = self . evaluated [ value ] . as_ref ( ) ?;
712
+ let value = self . eval_to_const ( value ) ?;
716
713
// `offset` for immediates generally only supports projections that match the
717
714
// type of the immediate. However, as a HACK, we exploit that it can also do
718
715
// limited transmutes: it only works between types with the same layout, and
@@ -724,12 +721,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
724
721
&& !matches ! ( s1. primitive( ) , Primitive :: Pointer ( ..) )
725
722
}
726
723
( 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 ( ..) )
733
730
&& !matches ! ( b1. primitive( ) , Primitive :: Pointer ( ..) )
734
731
}
735
732
_ => false ,
@@ -741,7 +738,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
741
738
value. offset ( Size :: ZERO , ty, & self . ecx ) . discard_err ( ) ?
742
739
}
743
740
CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize , _) => {
744
- let src = self . evaluated [ value ] . as_ref ( ) ?;
741
+ let src = self . eval_to_const ( value ) ?;
745
742
let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
746
743
self . ecx . unsize_into ( src, ty, & dest) . discard_err ( ) ?;
747
744
self . ecx
@@ -750,13 +747,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
750
747
dest. into ( )
751
748
}
752
749
CastKind :: FnPtrToPtr | CastKind :: PtrToPtr => {
753
- let src = self . evaluated [ value ] . as_ref ( ) ?;
750
+ let src = self . eval_to_const ( value ) ?;
754
751
let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
755
752
let ret = self . ecx . ptr_to_ptr ( & src, ty) . discard_err ( ) ?;
756
753
ret. into ( )
757
754
}
758
755
CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: UnsafeFnPointer , _) => {
759
- let src = self . evaluated [ value ] . as_ref ( ) ?;
756
+ let src = self . eval_to_const ( value ) ?;
760
757
let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
761
758
ImmTy :: from_immediate ( * src, ty) . into ( )
762
759
}
@@ -766,6 +763,15 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
766
763
Some ( op)
767
764
}
768
765
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
+
769
775
/// Represent the *value* we obtain by dereferencing an `Address` value.
770
776
#[ instrument( level = "trace" , skip( self ) , ret) ]
771
777
fn dereference_address (
@@ -901,7 +907,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
901
907
if let ProjectionElem :: Index ( idx_local) = elem
902
908
&& let Some ( idx) = self . locals [ idx_local]
903
909
{
904
- if let Some ( offset) = self . evaluated [ idx ] . as_ref ( )
910
+ if let Some ( offset) = self . eval_to_const ( idx )
905
911
&& let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
906
912
&& let Some ( min_length) = offset. checked_add ( 1 )
907
913
{
@@ -1389,8 +1395,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
1389
1395
1390
1396
let layout = self . ecx . layout_of ( lhs_ty) . ok ( ) ?;
1391
1397
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 ) ?;
1394
1400
if layout. backend_repr . is_scalar ( ) {
1395
1401
let scalar = self . ecx . read_scalar ( constant) . discard_err ( ) ?;
1396
1402
scalar. to_bits ( constant. layout . size ) . discard_err ( )
@@ -1790,7 +1796,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
1790
1796
return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
1791
1797
}
1792
1798
1793
- let op = self . evaluated [ index ] . as_ref ( ) ?;
1799
+ let op = self . eval_to_const ( index ) ?;
1794
1800
if op. layout . is_unsized ( ) {
1795
1801
// Do not attempt to propagate unsized locals.
1796
1802
return None ;
0 commit comments