@@ -980,27 +980,17 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
980
980
}
981
981
}
982
982
983
- let tcx = self . tcx ;
984
- let mut projection = SmallVec :: < [ PlaceElem < ' tcx > ; 1 ] > :: new ( ) ;
985
- loop {
986
- if let Some ( local) = self . try_as_local ( copy_from_local_value, location) {
987
- projection. reverse ( ) ;
988
- let place = Place { local, projection : tcx. mk_place_elems ( projection. as_slice ( ) ) } ;
989
- if rvalue. ty ( self . local_decls , tcx) == place. ty ( self . local_decls , tcx) . ty {
990
- self . reused_locals . insert ( local) ;
991
- * rvalue = Rvalue :: Use ( Operand :: Copy ( place) ) ;
992
- return Some ( copy_from_value) ;
993
- }
994
- return None ;
995
- } else if let Value :: Projection ( pointer, proj) = * self . get ( copy_from_local_value)
996
- && let Some ( proj) = self . try_as_place_elem ( proj, location)
997
- {
998
- projection. push ( proj) ;
999
- copy_from_local_value = pointer;
1000
- } else {
1001
- return None ;
983
+ // Allow introducing places with non-constant offsets, as those are still better than
984
+ // reconstructing an aggregate.
985
+ if let Some ( place) = self . try_as_place ( copy_from_local_value, location, true ) {
986
+ if rvalue. ty ( self . local_decls , self . tcx ) == place. ty ( self . local_decls , self . tcx ) . ty {
987
+ self . reused_locals . insert ( place. local ) ;
988
+ * rvalue = Rvalue :: Use ( Operand :: Copy ( place) ) ;
989
+ return Some ( copy_from_local_value) ;
1002
990
}
1003
991
}
992
+
993
+ None
1004
994
}
1005
995
1006
996
fn simplify_aggregate (
@@ -1672,14 +1662,14 @@ fn op_to_prop_const<'tcx>(
1672
1662
}
1673
1663
1674
1664
impl < ' tcx > VnState < ' _ , ' tcx > {
1675
- /// If either [`Self::try_as_constant`] as [`Self::try_as_local `] succeeds,
1665
+ /// If either [`Self::try_as_constant`] as [`Self::try_as_place `] succeeds,
1676
1666
/// returns that result as an [`Operand`].
1677
1667
fn try_as_operand ( & mut self , index : VnIndex , location : Location ) -> Option < Operand < ' tcx > > {
1678
1668
if let Some ( const_) = self . try_as_constant ( index) {
1679
1669
Some ( Operand :: Constant ( Box :: new ( const_) ) )
1680
- } else if let Some ( local ) = self . try_as_local ( index, location) {
1681
- self . reused_locals . insert ( local) ;
1682
- Some ( Operand :: Copy ( local . into ( ) ) )
1670
+ } else if let Some ( place ) = self . try_as_place ( index, location, false ) {
1671
+ self . reused_locals . insert ( place . local ) ;
1672
+ Some ( Operand :: Copy ( place ) )
1683
1673
} else {
1684
1674
None
1685
1675
}
@@ -1712,6 +1702,35 @@ impl<'tcx> VnState<'_, 'tcx> {
1712
1702
Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ } )
1713
1703
}
1714
1704
1705
+ /// Construct a place which holds the same value as `index` and for which all locals strictly
1706
+ /// dominate `loc`. If you used this place, add its base local to `reused_locals` to remove
1707
+ /// storage statements.
1708
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
1709
+ fn try_as_place (
1710
+ & mut self ,
1711
+ mut index : VnIndex ,
1712
+ loc : Location ,
1713
+ allow_complex_projection : bool ,
1714
+ ) -> Option < Place < ' tcx > > {
1715
+ let mut projection = SmallVec :: < [ PlaceElem < ' tcx > ; 1 ] > :: new ( ) ;
1716
+ loop {
1717
+ if let Some ( local) = self . try_as_local ( index, loc) {
1718
+ projection. reverse ( ) ;
1719
+ let place =
1720
+ Place { local, projection : self . tcx . mk_place_elems ( projection. as_slice ( ) ) } ;
1721
+ return Some ( place) ;
1722
+ } else if let Value :: Projection ( pointer, proj) = * self . get ( index)
1723
+ && ( allow_complex_projection || proj. is_stable_offset ( ) )
1724
+ && let Some ( proj) = self . try_as_place_elem ( proj, loc)
1725
+ {
1726
+ projection. push ( proj) ;
1727
+ index = pointer;
1728
+ } else {
1729
+ return None ;
1730
+ }
1731
+ }
1732
+ }
1733
+
1715
1734
/// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
1716
1735
/// return it. If you used this local, add it to `reused_locals` to remove storage statements.
1717
1736
fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
@@ -1762,11 +1781,12 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
1762
1781
if let Some ( value) = value {
1763
1782
if let Some ( const_) = self . try_as_constant ( value) {
1764
1783
* rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( const_) ) ) ;
1765
- } else if let Some ( local) = self . try_as_local ( value, location)
1766
- && * rvalue != Rvalue :: Use ( Operand :: Move ( local. into ( ) ) )
1784
+ } else if let Some ( place) = self . try_as_place ( value, location, false )
1785
+ && * rvalue != Rvalue :: Use ( Operand :: Move ( place) )
1786
+ && * rvalue != Rvalue :: Use ( Operand :: Copy ( place) )
1767
1787
{
1768
- * rvalue = Rvalue :: Use ( Operand :: Copy ( local . into ( ) ) ) ;
1769
- self . reused_locals . insert ( local) ;
1788
+ * rvalue = Rvalue :: Use ( Operand :: Copy ( place ) ) ;
1789
+ self . reused_locals . insert ( place . local ) ;
1770
1790
}
1771
1791
}
1772
1792
}
0 commit comments