@@ -5,7 +5,7 @@ use std::fmt::Debug;
5
5
6
6
use either:: Left ;
7
7
8
- use rustc_const_eval:: interpret:: Immediate ;
8
+ use rustc_const_eval:: interpret:: { ImmTy , Immediate , Projectable } ;
9
9
use rustc_const_eval:: interpret:: {
10
10
InterpCx , InterpResult , MemoryKind , OpTy , Scalar , StackPopCleanup ,
11
11
} ;
@@ -21,7 +21,7 @@ use rustc_middle::ty::{
21
21
self , ConstInt , Instance , ParamEnv , ScalarInt , Ty , TyCtxt , TypeVisitableExt ,
22
22
} ;
23
23
use rustc_span:: Span ;
24
- use rustc_target:: abi:: { HasDataLayout , Size , TargetDataLayout } ;
24
+ use rustc_target:: abi:: { self , Abi , HasDataLayout , Size , TargetDataLayout } ;
25
25
26
26
use crate :: const_prop:: CanConstProp ;
27
27
use crate :: const_prop:: ConstPropMachine ;
@@ -540,6 +540,188 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
540
540
)
541
541
}
542
542
}
543
+
544
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
545
+ fn eval_rvalue (
546
+ & mut self ,
547
+ rvalue : & Rvalue < ' tcx > ,
548
+ location : Location ,
549
+ dest : & Place < ' tcx > ,
550
+ ) -> Option < ( ) > {
551
+ if !dest. projection . is_empty ( ) {
552
+ return None ;
553
+ }
554
+ use rustc_middle:: mir:: Rvalue :: * ;
555
+ let dest = self . use_ecx ( location, |this| this. ecx . eval_place ( * dest) ) ?;
556
+ trace ! ( ?dest) ;
557
+
558
+ let val = match * rvalue {
559
+ ThreadLocalRef ( _) => return None ,
560
+
561
+ Use ( ref operand) => self . eval_operand ( operand, location, Some ( dest. layout ) ) ?,
562
+
563
+ CopyForDeref ( place) => self . eval_place ( place, location, Some ( dest. layout ) ) ?,
564
+
565
+ BinaryOp ( bin_op, box ( ref left, ref right) ) => {
566
+ let layout =
567
+ rustc_const_eval:: util:: binop_left_homogeneous ( bin_op) . then_some ( dest. layout ) ;
568
+ let left = self . eval_operand ( left, location, layout) ?;
569
+ let left = self . use_ecx ( location, |this| this. ecx . read_immediate ( & left) ) ?;
570
+
571
+ let layout =
572
+ rustc_const_eval:: util:: binop_right_homogeneous ( bin_op) . then_some ( left. layout ) ;
573
+ let right = self . eval_operand ( right, location, layout) ?;
574
+ let right = self . use_ecx ( location, |this| this. ecx . read_immediate ( & right) ) ?;
575
+
576
+ let val = self
577
+ . use_ecx ( location, |this| this. ecx . wrapping_binary_op ( bin_op, & left, & right) ) ?;
578
+ val. into ( )
579
+ }
580
+
581
+ CheckedBinaryOp ( bin_op, box ( ref left, ref right) ) => {
582
+ let left = self . eval_operand ( left, location, None ) ?;
583
+ let left = self . use_ecx ( location, |this| this. ecx . read_immediate ( & left) ) ?;
584
+
585
+ let layout =
586
+ rustc_const_eval:: util:: binop_right_homogeneous ( bin_op) . then_some ( left. layout ) ;
587
+ let right = self . eval_operand ( right, location, layout) ?;
588
+ let right = self . use_ecx ( location, |this| this. ecx . read_immediate ( & right) ) ?;
589
+
590
+ let ( val, overflowed) = self . use_ecx ( location, |this| {
591
+ this. ecx . overflowing_binary_op ( bin_op, & left, & right)
592
+ } ) ?;
593
+ let tuple = Ty :: new_tup_from_iter (
594
+ self . tcx ,
595
+ [ val. layout . ty , self . tcx . types . bool ] . into_iter ( ) ,
596
+ ) ;
597
+ let tuple = self . ecx . layout_of ( tuple) . ok ( ) ?;
598
+ let val =
599
+ ImmTy :: from_scalar_pair ( val. to_scalar ( ) , Scalar :: from_bool ( overflowed) , tuple) ;
600
+ val. into ( )
601
+ }
602
+
603
+ UnaryOp ( un_op, ref operand) => {
604
+ let operand = self . eval_operand ( operand, location, Some ( dest. layout ) ) ?;
605
+ let val = self . use_ecx ( location, |this| this. ecx . read_immediate ( & operand) ) ?;
606
+
607
+ let val = self . use_ecx ( location, |this| this. ecx . wrapping_unary_op ( un_op, & val) ) ?;
608
+ val. into ( )
609
+ }
610
+
611
+ Aggregate ( ref kind, ref fields) => {
612
+ trace ! ( ?kind) ;
613
+ trace ! ( ?dest. layout) ;
614
+ if dest. layout . is_zst ( ) {
615
+ ImmTy :: uninit ( dest. layout ) . into ( )
616
+ } else if let Abi :: Scalar ( abi:: Scalar :: Initialized { .. } ) = dest. layout . abi {
617
+ let fields = fields
618
+ . iter ( )
619
+ . map ( |field| self . eval_operand ( field, location, None ) )
620
+ . collect :: < Option < Vec < _ > > > ( ) ?;
621
+ trace ! ( ?fields) ;
622
+ let mut field =
623
+ fields. into_iter ( ) . find ( |field| field. layout . abi . is_scalar ( ) ) ?;
624
+ field. layout = dest. layout ;
625
+ field
626
+ } else if let Abi :: ScalarPair (
627
+ abi:: Scalar :: Initialized { .. } ,
628
+ abi:: Scalar :: Initialized { .. } ,
629
+ ) = dest. layout . abi
630
+ {
631
+ let fields = fields
632
+ . iter ( )
633
+ . map ( |field| self . eval_operand ( field, location, None ) )
634
+ . collect :: < Option < Vec < _ > > > ( ) ?;
635
+ trace ! ( ?fields) ;
636
+ let pair =
637
+ fields. iter ( ) . find ( |field| matches ! ( field. layout. abi, Abi :: ScalarPair ( ..) ) ) ;
638
+ if let Some ( pair) = pair {
639
+ let mut pair = pair. clone ( ) ;
640
+ pair. layout = dest. layout ;
641
+ pair
642
+ } else {
643
+ // TODO: build a pair from two scalars
644
+ return None ;
645
+ }
646
+ } else {
647
+ return None ;
648
+ }
649
+ }
650
+
651
+ Repeat ( ref op, n) => {
652
+ trace ! ( ?op, ?n) ;
653
+ return None ;
654
+ }
655
+
656
+ Len ( place) => {
657
+ let src = self . eval_place ( place, location, None ) ?;
658
+ let len = src. len ( & self . ecx ) . ok ( ) ?;
659
+ ImmTy :: from_scalar ( Scalar :: from_target_usize ( len, self ) , dest. layout ) . into ( )
660
+ }
661
+
662
+ Ref ( ..) | AddressOf ( ..) => return None ,
663
+
664
+ NullaryOp ( ref null_op, ty) => {
665
+ let layout = self . use_ecx ( location, |this| this. ecx . layout_of ( ty) ) ?;
666
+ let val = match null_op {
667
+ NullOp :: SizeOf => layout. size . bytes ( ) ,
668
+ NullOp :: AlignOf => layout. align . abi . bytes ( ) ,
669
+ NullOp :: OffsetOf ( fields) => {
670
+ layout. offset_of_subfield ( self , fields. iter ( ) ) . bytes ( )
671
+ }
672
+ } ;
673
+ ImmTy :: from_scalar ( Scalar :: from_target_usize ( val, self ) , dest. layout ) . into ( )
674
+ }
675
+
676
+ ShallowInitBox ( ..) => return None ,
677
+
678
+ Cast ( ref kind, ref value, to) => match kind {
679
+ CastKind :: IntToInt | CastKind :: IntToFloat => {
680
+ let value = self . eval_operand ( value, location, None ) ?;
681
+ let value = self . ecx . read_immediate ( & value) . ok ( ) ?;
682
+ let to = self . ecx . layout_of ( to) . ok ( ) ?;
683
+ let res = self . ecx . int_to_int_or_float ( & value, to) . ok ( ) ?;
684
+ res. into ( )
685
+ }
686
+ CastKind :: FloatToFloat | CastKind :: FloatToInt => {
687
+ let value = self . eval_operand ( value, location, None ) ?;
688
+ let value = self . ecx . read_immediate ( & value) . ok ( ) ?;
689
+ let to = self . ecx . layout_of ( to) . ok ( ) ?;
690
+ let res = self . ecx . float_to_float_or_int ( & value, to) . ok ( ) ?;
691
+ res. into ( )
692
+ }
693
+ CastKind :: Transmute => {
694
+ let value = self . eval_operand ( value, location, None ) ?;
695
+ let to = self . ecx . layout_of ( to) . ok ( ) ?;
696
+ // `offset` for immediates only supports scalar/scalar-pair ABIs,
697
+ // so bail out if the target is not one.
698
+ if value. as_mplace_or_imm ( ) . is_right ( ) {
699
+ match ( value. layout . abi , to. abi ) {
700
+ ( Abi :: Scalar ( ..) , Abi :: Scalar ( ..) ) => { }
701
+ ( Abi :: ScalarPair ( ..) , Abi :: ScalarPair ( ..) ) => { }
702
+ _ => return None ,
703
+ }
704
+ }
705
+ value. offset ( Size :: ZERO , to, & self . ecx ) . ok ( ) ?
706
+ }
707
+ _ => return None ,
708
+ } ,
709
+
710
+ Discriminant ( place) => {
711
+ let op = self . eval_place ( place, location, None ) ?;
712
+ let variant = self . use_ecx ( location, |this| this. ecx . read_discriminant ( & op) ) ?;
713
+ let imm = self . use_ecx ( location, |this| {
714
+ this. ecx . discriminant_for_variant ( op. layout . ty , variant)
715
+ } ) ?;
716
+ imm. into ( )
717
+ }
718
+ } ;
719
+ trace ! ( ?val) ;
720
+
721
+ self . use_ecx ( location, |this| this. ecx . copy_op ( & val, & dest, true ) ) ?;
722
+
723
+ Some ( ( ) )
724
+ }
543
725
}
544
726
545
727
impl < ' tcx > Visitor < ' tcx > for ConstPropagator < ' _ , ' tcx > {
@@ -574,10 +756,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
574
756
_ if place. is_indirect ( ) => { }
575
757
ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
576
758
ConstPropMode :: OnlyInsideOwnBlock | ConstPropMode :: FullConstProp => {
577
- if self
578
- . use_ecx ( location, |this| this. ecx . eval_rvalue_into_place ( rvalue, * place) )
579
- . is_none ( )
580
- {
759
+ if self . eval_rvalue ( rvalue, location, place) . is_none ( ) {
581
760
// Const prop failed, so erase the destination, ensuring that whatever happens
582
761
// from here on, does not know about the previous value.
583
762
// This is important in case we have
0 commit comments