33//! MIR may contain repeated and/or redundant computations. The objective of this pass is to detect
44//! such redundancies and re-use the already-computed result when possible.
55//!
6- //! In a first pass, we compute a symbolic representation of values that are assigned to SSA
7- //! locals. This symbolic representation is defined by the `Value` enum. Each produced instance of
8- //! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values.
9- //!
106//! From those assignments, we construct a mapping `VnIndex -> Vec<(Local, Location)>` of available
117//! values, the locals in which they are stored, and the assignment location.
128//!
13- //! In a second pass, we traverse all (non SSA) assignments `x = rvalue` and operands. For each
9+ //! We traverse all assignments `x = rvalue` and operands.
10+ //!
11+ //! For each SSA one, we compute a symbolic representation of values that are assigned to SSA
12+ //! locals. This symbolic representation is defined by the `Value` enum. Each produced instance of
13+ //! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values.
14+ //!
15+ //! For each non-SSA
1416//! one, we compute the `VnIndex` of the rvalue. If this `VnIndex` is associated to a constant, we
1517//! replace the rvalue/operand by that constant. Otherwise, if there is an SSA local `y`
1618//! associated to this `VnIndex`, and if its definition location strictly dominates the assignment
@@ -107,7 +109,7 @@ use rustc_span::def_id::DefId;
107109use smallvec:: SmallVec ;
108110use tracing:: { debug, instrument, trace} ;
109111
110- use crate :: ssa:: { AssignedValue , SsaLocals } ;
112+ use crate :: ssa:: SsaLocals ;
111113
112114pub ( super ) struct GVN ;
113115
@@ -126,31 +128,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
126128 let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
127129
128130 let mut state = VnState :: new ( tcx, body, param_env, & ssa, dominators, & body. local_decls ) ;
129- ssa. for_each_assignment_mut (
130- body. basic_blocks . as_mut_preserves_cfg ( ) ,
131- |local, value, location| {
132- let value = match value {
133- // We do not know anything of this assigned value.
134- AssignedValue :: Arg | AssignedValue :: Terminator => None ,
135- // Try to get some insight.
136- AssignedValue :: Rvalue ( rvalue) => {
137- let value = state. simplify_rvalue ( rvalue, location) ;
138- // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
139- // `local` as reusable if we have an exact type match.
140- if state. local_decls [ local] . ty != rvalue. ty ( state. local_decls , tcx) {
141- return ;
142- }
143- value
144- }
145- } ;
146- // `next_opaque` is `Some`, so `new_opaque` must return `Some`.
147- let value = value. or_else ( || state. new_opaque ( ) ) . unwrap ( ) ;
148- state. assign ( local, value) ;
149- } ,
150- ) ;
151131
152- // Stop creating opaques during replacement as it is useless.
153- state. next_opaque = None ;
132+ for local in body. args_iter ( ) . filter ( |& local| ssa. is_ssa ( local) ) {
133+ let opaque = state. new_opaque ( ) . unwrap ( ) ;
134+ state. assign ( local, opaque) ;
135+ }
154136
155137 let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
156138 for bb in reverse_postorder {
@@ -247,7 +229,6 @@ struct VnState<'body, 'tcx> {
247229 locals : IndexVec < Local , Option < VnIndex > > ,
248230 /// Locals that are assigned that value.
249231 // This vector does not hold all the values of `VnIndex` that we create.
250- // It stops at the largest value created in the first phase of collecting assignments.
251232 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
252233 values : FxIndexSet < Value < ' tcx > > ,
253234 /// Values evaluated as constants if possible.
@@ -339,6 +320,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
339320 /// Record that `local` is assigned `value`. `local` must be SSA.
340321 #[ instrument( level = "trace" , skip( self ) ) ]
341322 fn assign ( & mut self , local : Local , value : VnIndex ) {
323+ debug_assert ! ( self . ssa. is_ssa( local) ) ;
342324 self . locals [ local] = Some ( value) ;
343325
344326 // Only register the value if its type is `Sized`, as we will emit copies of it.
@@ -1633,15 +1615,19 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
16331615 if let StatementKind :: Assign ( box ( ref mut lhs, ref mut rvalue) ) = stmt. kind {
16341616 self . simplify_place_projection ( lhs, location) ;
16351617
1636- // Do not try to simplify a constant, it's already in canonical shape.
1637- if matches ! ( rvalue, Rvalue :: Use ( Operand :: Constant ( _) ) ) {
1638- return ;
1639- }
1640-
1641- let value = lhs
1642- . as_local ( )
1643- . and_then ( |local| self . locals [ local] )
1644- . or_else ( || self . simplify_rvalue ( rvalue, location) ) ;
1618+ let value = self . simplify_rvalue ( rvalue, location) ;
1619+ let value = if let Some ( local) = lhs. as_local ( )
1620+ && self . ssa . is_ssa ( local)
1621+ // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
1622+ // `local` as reusable if we have an exact type match.
1623+ && self . local_decls [ local] . ty == rvalue. ty ( self . local_decls , self . tcx )
1624+ {
1625+ let value = value. or_else ( || self . new_opaque ( ) ) . unwrap ( ) ;
1626+ self . assign ( local, value) ;
1627+ Some ( value)
1628+ } else {
1629+ value
1630+ } ;
16451631 let Some ( value) = value else { return } ;
16461632
16471633 if let Some ( const_) = self . try_as_constant ( value) {
@@ -1657,6 +1643,17 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
16571643 }
16581644 self . super_statement ( stmt, location) ;
16591645 }
1646+
1647+ fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
1648+ if let Terminator { kind : TerminatorKind :: Call { destination, .. } , .. } = terminator
1649+ && let Some ( local) = destination. as_local ( )
1650+ && self . ssa . is_ssa ( local)
1651+ {
1652+ let opaque = self . new_opaque ( ) . unwrap ( ) ;
1653+ self . assign ( local, opaque) ;
1654+ }
1655+ self . super_terminator ( terminator, location) ;
1656+ }
16601657}
16611658
16621659struct StorageRemover < ' tcx > {
0 commit comments