@@ -351,7 +351,7 @@ struct VnState<'body, 'a, 'tcx> {
351
351
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
352
352
values : ValueSet < ' a , ' tcx > ,
353
353
/// Values evaluated as constants if possible.
354
- evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
354
+ evaluated : IndexVec < VnIndex , Option < Option < & ' a OpTy < ' tcx > > > > ,
355
355
/// Cache the deref values.
356
356
derefs : Vec < VnIndex > ,
357
357
ssa : & ' body SsaLocals ,
@@ -403,8 +403,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
403
403
let ( index, new) = self . values . insert ( ty, value) ;
404
404
if new {
405
405
// 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 ) ;
408
407
debug_assert_eq ! ( index, _index) ;
409
408
let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
410
409
debug_assert_eq ! ( index, _index) ;
@@ -417,7 +416,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
417
416
#[ instrument( level = "trace" , skip( self ) , ret) ]
418
417
fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
419
418
let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
420
- let _index = self . evaluated . push ( None ) ;
419
+ let _index = self . evaluated . push ( Some ( None ) ) ;
421
420
debug_assert_eq ! ( index, _index) ;
422
421
let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
423
422
debug_assert_eq ! ( index, _index) ;
@@ -436,8 +435,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
436
435
} ;
437
436
let index =
438
437
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 ) ;
441
439
debug_assert_eq ! ( index, _index) ;
442
440
let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
443
441
debug_assert_eq ! ( index, _index) ;
@@ -460,8 +458,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
460
458
( index, true )
461
459
} ;
462
460
if new {
463
- let evaluated = self . eval_to_const ( index) ;
464
- let _index = self . evaluated . push ( evaluated) ;
461
+ let _index = self . evaluated . push ( None ) ;
465
462
debug_assert_eq ! ( index, _index) ;
466
463
let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
467
464
debug_assert_eq ! ( index, _index) ;
@@ -518,7 +515,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
518
515
}
519
516
520
517
#[ 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 > > {
522
519
use Value :: * ;
523
520
let ty = self . ty ( value) ;
524
521
// Avoid computing layouts inside a coroutine, as that can cause cycles.
@@ -538,10 +535,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
538
535
self . ecx . eval_mir_constant ( value, DUMMY_SP , None ) . discard_err ( ) ?
539
536
}
540
537
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 < _ > > > ( ) ?;
545
540
let variant = if ty. ty . is_enum ( ) { Some ( variant) } else { None } ;
546
541
if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
547
542
{
@@ -570,8 +565,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
570
565
}
571
566
}
572
567
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 ) ?;
575
570
576
571
// Pointers don't have fields, so don't `project_field` them.
577
572
let data = self . ecx . read_pointer ( pointer) . discard_err ( ) ?;
@@ -585,7 +580,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
585
580
}
586
581
587
582
Projection ( base, elem) => {
588
- let base = self . evaluated [ base ] . as_ref ( ) ?;
583
+ let base = self . eval_to_const ( base ) ?;
589
584
// `Index` by constants should have been replaced by `ConstantIndex` by
590
585
// `simplify_place_projection`.
591
586
let elem = elem. try_map ( |_| None , |( ) | ty. ty ) ?;
@@ -596,7 +591,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
596
591
return None ;
597
592
}
598
593
let local = self . locals [ place. local ] ?;
599
- let pointer = self . evaluated [ local ] . as_ref ( ) ?;
594
+ let pointer = self . eval_to_const ( local ) ?;
600
595
let mut mplace = self . ecx . deref_pointer ( pointer) . discard_err ( ) ?;
601
596
for elem in place. projection . iter ( ) . skip ( 1 ) {
602
597
// `Index` by constants should have been replaced by `ConstantIndex` by
@@ -609,7 +604,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
609
604
}
610
605
611
606
Discriminant ( base) => {
612
- let base = self . evaluated [ base ] . as_ref ( ) ?;
607
+ let base = self . eval_to_const ( base ) ?;
613
608
let variant = self . ecx . read_discriminant ( base) . discard_err ( ) ?;
614
609
let discr_value =
615
610
self . ecx . discriminant_for_variant ( base. layout . ty , variant) . discard_err ( ) ?;
@@ -626,7 +621,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
626
621
NullOp :: SizeOf => arg_layout. size . bytes ( ) ,
627
622
NullOp :: AlignOf => arg_layout. align . bytes ( ) ,
628
623
NullOp :: OffsetOf ( fields) => self
629
- . ecx
630
624
. tcx
631
625
. offset_of_subfield ( self . typing_env ( ) , arg_layout, fields. iter ( ) )
632
626
. bytes ( ) ,
@@ -636,34 +630,34 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
636
630
ImmTy :: from_uint ( val, ty) . into ( )
637
631
}
638
632
UnaryOp ( un_op, operand) => {
639
- let operand = self . evaluated [ operand ] . as_ref ( ) ?;
633
+ let operand = self . eval_to_const ( operand ) ?;
640
634
let operand = self . ecx . read_immediate ( operand) . discard_err ( ) ?;
641
635
let val = self . ecx . unary_op ( un_op, & operand) . discard_err ( ) ?;
642
636
val. into ( )
643
637
}
644
638
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) ?;
646
641
let lhs = self . ecx . read_immediate ( lhs) . discard_err ( ) ?;
647
- let rhs = self . evaluated [ rhs] . as_ref ( ) ?;
648
642
let rhs = self . ecx . read_immediate ( rhs) . discard_err ( ) ?;
649
643
let val = self . ecx . binary_op ( bin_op, & lhs, & rhs) . discard_err ( ) ?;
650
644
val. into ( )
651
645
}
652
646
Cast { kind, value } => match kind {
653
647
CastKind :: IntToInt | CastKind :: IntToFloat => {
654
- let value = self . evaluated [ value ] . as_ref ( ) ?;
648
+ let value = self . eval_to_const ( value ) ?;
655
649
let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
656
650
let res = self . ecx . int_to_int_or_float ( & value, ty) . discard_err ( ) ?;
657
651
res. into ( )
658
652
}
659
653
CastKind :: FloatToFloat | CastKind :: FloatToInt => {
660
- let value = self . evaluated [ value ] . as_ref ( ) ?;
654
+ let value = self . eval_to_const ( value ) ?;
661
655
let value = self . ecx . read_immediate ( value) . discard_err ( ) ?;
662
656
let res = self . ecx . float_to_float_or_int ( & value, ty) . discard_err ( ) ?;
663
657
res. into ( )
664
658
}
665
659
CastKind :: Transmute | CastKind :: Subtype => {
666
- let value = self . evaluated [ value ] . as_ref ( ) ?;
660
+ let value = self . eval_to_const ( value ) ?;
667
661
// `offset` for immediates generally only supports projections that match the
668
662
// type of the immediate. However, as a HACK, we exploit that it can also do
669
663
// limited transmutes: it only works between types with the same layout, and
@@ -675,12 +669,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
675
669
&& !matches ! ( s1. primitive( ) , Primitive :: Pointer ( ..) )
676
670
}
677
671
( 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 ( ..) )
684
678
&& !matches ! ( b1. primitive( ) , Primitive :: Pointer ( ..) )
685
679
}
686
680
_ => false ,
@@ -692,7 +686,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
692
686
value. offset ( Size :: ZERO , ty, & self . ecx ) . discard_err ( ) ?
693
687
}
694
688
CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize , _) => {
695
- let src = self . evaluated [ value ] . as_ref ( ) ?;
689
+ let src = self . eval_to_const ( value ) ?;
696
690
let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
697
691
self . ecx . unsize_into ( src, ty, & dest) . discard_err ( ) ?;
698
692
self . ecx
@@ -701,13 +695,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
701
695
dest. into ( )
702
696
}
703
697
CastKind :: FnPtrToPtr | CastKind :: PtrToPtr => {
704
- let src = self . evaluated [ value ] . as_ref ( ) ?;
698
+ let src = self . eval_to_const ( value ) ?;
705
699
let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
706
700
let ret = self . ecx . ptr_to_ptr ( & src, ty) . discard_err ( ) ?;
707
701
ret. into ( )
708
702
}
709
703
CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: UnsafeFnPointer , _) => {
710
- let src = self . evaluated [ value ] . as_ref ( ) ?;
704
+ let src = self . eval_to_const ( value ) ?;
711
705
let src = self . ecx . read_immediate ( src) . discard_err ( ) ?;
712
706
ImmTy :: from_immediate ( * src, ty) . into ( )
713
707
}
@@ -717,6 +711,15 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
717
711
Some ( op)
718
712
}
719
713
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
+
720
723
fn project (
721
724
& mut self ,
722
725
place_ty : PlaceTy < ' tcx > ,
@@ -822,7 +825,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
822
825
if let ProjectionElem :: Index ( idx_local) = elem
823
826
&& let Some ( idx) = self . locals [ idx_local]
824
827
{
825
- if let Some ( offset) = self . evaluated [ idx ] . as_ref ( )
828
+ if let Some ( offset) = self . eval_to_const ( idx )
826
829
&& let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
827
830
&& let Some ( min_length) = offset. checked_add ( 1 )
828
831
{
@@ -1312,8 +1315,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
1312
1315
1313
1316
let layout = self . ecx . layout_of ( lhs_ty) . ok ( ) ?;
1314
1317
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 ) ?;
1317
1320
if layout. backend_repr . is_scalar ( ) {
1318
1321
let scalar = self . ecx . read_scalar ( constant) . discard_err ( ) ?;
1319
1322
scalar. to_bits ( constant. layout . size ) . discard_err ( )
@@ -1713,7 +1716,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
1713
1716
return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
1714
1717
}
1715
1718
1716
- let op = self . evaluated [ index ] . as_ref ( ) ?;
1719
+ let op = self . eval_to_const ( index ) ?;
1717
1720
if op. layout . is_unsized ( ) {
1718
1721
// Do not attempt to propagate unsized locals.
1719
1722
return None ;
0 commit comments