@@ -90,7 +90,9 @@ use std::hash::{Hash, Hasher};
9090use either:: Either ;
9191use hashbrown:: hash_table:: { Entry , HashTable } ;
9292use itertools:: Itertools as _;
93- use rustc_abi:: { self as abi, BackendRepr , FIRST_VARIANT , FieldIdx , Primitive , Size , VariantIdx } ;
93+ use rustc_abi:: {
94+ self as abi, BackendRepr , FIRST_VARIANT , FieldIdx , Primitive , Size , VariantIdx , WrappingRange ,
95+ } ;
9496use rustc_arena:: DroplessArena ;
9597use rustc_const_eval:: const_eval:: DummyMachine ;
9698use rustc_const_eval:: interpret:: {
@@ -380,6 +382,8 @@ struct VnState<'body, 'a, 'tcx> {
380382 dominators : Dominators < BasicBlock > ,
381383 reused_locals : DenseBitSet < Local > ,
382384 arena : & ' a DroplessArena ,
385+ /// Known ranges at each locations.
386+ ranges : IndexVec < VnIndex , Vec < ( Location , WrappingRange ) > > ,
383387}
384388
385389impl < ' body , ' a , ' tcx > VnState < ' body , ' a , ' tcx > {
@@ -413,6 +417,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
413417 dominators,
414418 reused_locals : DenseBitSet :: new_empty ( local_decls. len ( ) ) ,
415419 arena,
420+ ranges : IndexVec :: with_capacity ( num_values) ,
416421 }
417422 }
418423
@@ -429,6 +434,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
429434 debug_assert_eq ! ( index, _index) ;
430435 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
431436 debug_assert_eq ! ( index, _index) ;
437+ let _index = self . ranges . push ( Vec :: new ( ) ) ;
438+ debug_assert_eq ! ( index, _index) ;
432439 }
433440 index
434441 }
@@ -442,6 +449,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
442449 debug_assert_eq ! ( index, _index) ;
443450 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
444451 debug_assert_eq ! ( index, _index) ;
452+ let _index = self . ranges . push ( Vec :: new ( ) ) ;
453+ debug_assert_eq ! ( index, _index) ;
445454 index
446455 }
447456
@@ -480,6 +489,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
480489 debug_assert_eq ! ( index, _index) ;
481490 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
482491 debug_assert_eq ! ( index, _index) ;
492+ let _index = self . ranges . push ( Vec :: new ( ) ) ;
493+ debug_assert_eq ! ( index, _index) ;
483494
484495 Some ( index)
485496 }
@@ -504,6 +515,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
504515 debug_assert_eq ! ( index, _index) ;
505516 let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
506517 debug_assert_eq ! ( index, _index) ;
518+ let _index = self . ranges . push ( Vec :: new ( ) ) ;
519+ debug_assert_eq ! ( index, _index) ;
507520 }
508521 index
509522 }
@@ -526,6 +539,18 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
526539 self . rev_locals [ value] . push ( local) ;
527540 }
528541
542+ fn insert_range ( & mut self , value : VnIndex , location : Location , range : WrappingRange ) {
543+ self . ranges [ value] . push ( ( location, range) ) ;
544+ }
545+
546+ fn get_range ( & self , value : VnIndex , location : Location ) -> Option < WrappingRange > {
547+ // FIXME: This should use the intersection of all valid ranges.
548+ let ( _, range) = self . ranges [ value]
549+ . iter ( )
550+ . find ( |( range_loc, _) | range_loc. dominates ( location, & self . dominators ) ) ?;
551+ Some ( * range)
552+ }
553+
529554 fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
530555 // Booleans are deterministic.
531556 let value = Const :: from_bool ( self . tcx , flag) ;
@@ -1010,7 +1035,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
10101035 Operand :: Constant ( ref constant) => Some ( self . insert_constant ( constant. const_ ) ) ,
10111036 Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
10121037 let value = self . simplify_place_value ( place, location) ?;
1013- if let Some ( const_) = self . try_as_constant ( value) {
1038+ if let Some ( const_) = self . try_as_constant ( value, location ) {
10141039 * operand = Operand :: Constant ( Box :: new ( const_) ) ;
10151040 }
10161041 Some ( value)
@@ -1780,7 +1805,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17801805 /// If either [`Self::try_as_constant`] as [`Self::try_as_place`] succeeds,
17811806 /// returns that result as an [`Operand`].
17821807 fn try_as_operand ( & mut self , index : VnIndex , location : Location ) -> Option < Operand < ' tcx > > {
1783- if let Some ( const_) = self . try_as_constant ( index) {
1808+ if let Some ( const_) = self . try_as_constant ( index, location ) {
17841809 Some ( Operand :: Constant ( Box :: new ( const_) ) )
17851810 } else if let Some ( place) = self . try_as_place ( index, location, false ) {
17861811 self . reused_locals . insert ( place. local ) ;
@@ -1791,7 +1816,11 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17911816 }
17921817
17931818 /// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
1794- fn try_as_constant ( & mut self , index : VnIndex ) -> Option < ConstOperand < ' tcx > > {
1819+ fn try_as_constant (
1820+ & mut self ,
1821+ index : VnIndex ,
1822+ location : Location ,
1823+ ) -> Option < ConstOperand < ' tcx > > {
17951824 // This was already constant in MIR, do not change it. If the constant is not
17961825 // deterministic, adding an additional mention of it in MIR will not give the same value as
17971826 // the former mention.
@@ -1800,21 +1829,34 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
18001829 return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
18011830 }
18021831
1803- let op = self . eval_to_const ( index) ? ;
1804- if op. layout . is_unsized ( ) {
1805- // Do not attempt to propagate unsized locals.
1806- return None ;
1807- }
1832+ if let Some ( op ) = self . eval_to_const ( index) {
1833+ if op. layout . is_unsized ( ) {
1834+ // Do not attempt to propagate unsized locals.
1835+ return None ;
1836+ }
18081837
1809- let value = op_to_prop_const ( & mut self . ecx , op) ?;
1838+ let value = op_to_prop_const ( & mut self . ecx , op) ?;
18101839
1811- // Check that we do not leak a pointer.
1812- // Those pointers may lose part of their identity in codegen.
1813- // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
1814- assert ! ( !value. may_have_provenance( self . tcx, op. layout. size) ) ;
1840+ // Check that we do not leak a pointer.
1841+ // Those pointers may lose part of their identity in codegen.
1842+ // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
1843+ assert ! ( !value. may_have_provenance( self . tcx, op. layout. size) ) ;
1844+
1845+ let const_ = Const :: Val ( value, op. layout . ty ) ;
1846+ return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ } ) ;
1847+ }
18151848
1816- let const_ = Const :: Val ( value, op. layout . ty ) ;
1817- Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ } )
1849+ if let Some ( range) = self . get_range ( index, location)
1850+ && range. start == range. end
1851+ {
1852+ let ty = self . ty ( index) ;
1853+ let layout = self . ecx . layout_of ( ty) . ok ( ) ?;
1854+ let value = ConstValue :: Scalar ( Scalar :: from_uint ( range. start , layout. size ) ) ;
1855+ let const_ = Const :: Val ( value, self . ty ( index) ) ;
1856+ return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ } ) ;
1857+ }
1858+
1859+ None
18181860 }
18191861
18201862 /// Construct a place which holds the same value as `index` and for which all locals strictly
@@ -1891,7 +1933,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
18911933
18921934 let value = self . simplify_rvalue ( lhs, rvalue, location) ;
18931935 if let Some ( value) = value {
1894- if let Some ( const_) = self . try_as_constant ( value) {
1936+ if let Some ( const_) = self . try_as_constant ( value, location ) {
18951937 * rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( const_) ) ) ;
18961938 } else if let Some ( place) = self . try_as_place ( value, location, false )
18971939 && * rvalue != Rvalue :: Use ( Operand :: Move ( place) )
@@ -1920,14 +1962,56 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
19201962 }
19211963
19221964 fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
1923- if let Terminator { kind : TerminatorKind :: Call { destination, .. } , .. } = terminator {
1924- if let Some ( local) = destination. as_local ( )
1925- && self . ssa . is_ssa ( local)
1926- {
1927- let ty = self . local_decls [ local] . ty ;
1928- let opaque = self . new_opaque ( ty) ;
1929- self . assign ( local, opaque) ;
1965+ match & mut terminator. kind {
1966+ TerminatorKind :: Call { destination, .. } => {
1967+ if let Some ( local) = destination. as_local ( )
1968+ && self . ssa . is_ssa ( local)
1969+ {
1970+ let ty = self . local_decls [ local] . ty ;
1971+ let opaque = self . new_opaque ( ty) ;
1972+ self . assign ( local, opaque) ;
1973+ }
1974+ }
1975+ TerminatorKind :: Assert { cond, expected, target, .. } => {
1976+ if let Some ( value) = self . simplify_operand ( cond, location) {
1977+ let successor = Location { block : * target, statement_index : 0 } ;
1978+ if location. block != successor. block
1979+ && location. dominates ( successor, & self . dominators )
1980+ {
1981+ let val = * expected as u128 ;
1982+ let range = WrappingRange { start : val, end : val } ;
1983+ self . insert_range ( value, successor, range) ;
1984+ }
1985+ }
1986+ }
1987+ TerminatorKind :: SwitchInt { discr, targets } => {
1988+ if let Some ( value) = self . simplify_operand ( discr, location) {
1989+ for ( val, target) in targets. iter ( ) {
1990+ let successor = Location { block : target, statement_index : 0 } ;
1991+ if location. block != successor. block
1992+ && location. dominates ( successor, & self . dominators )
1993+ {
1994+ let range = WrappingRange { start : val, end : val } ;
1995+ self . insert_range ( value, successor, range) ;
1996+ }
1997+ }
1998+
1999+ let otherwise = Location { block : targets. otherwise ( ) , statement_index : 0 } ;
2000+ if self . ty ( value) . is_bool ( )
2001+ && let [ val] = targets. all_values ( )
2002+ && location. block != otherwise. block
2003+ && location. dominates ( otherwise, & self . dominators )
2004+ {
2005+ let range = if val. get ( ) == 0 {
2006+ WrappingRange { start : 1 , end : 1 }
2007+ } else {
2008+ WrappingRange { start : 0 , end : 0 }
2009+ } ;
2010+ self . insert_range ( value, otherwise, range) ;
2011+ }
2012+ }
19302013 }
2014+ _ => { }
19312015 }
19322016 // Terminators that can write to memory may invalidate (nested) derefs.
19332017 if terminator. kind . can_write_to_memory ( ) {
0 commit comments