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, typing_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 {
@@ -246,7 +228,6 @@ struct VnState<'body, 'tcx> {
246228 locals : IndexVec < Local , Option < VnIndex > > ,
247229 /// Locals that are assigned that value.
248230 // This vector does not hold all the values of `VnIndex` that we create.
249- // It stops at the largest value created in the first phase of collecting assignments.
250231 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
251232 values : FxIndexSet < Value < ' tcx > > ,
252233 /// Values evaluated as constants if possible.
@@ -341,6 +322,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
341322 /// Record that `local` is assigned `value`. `local` must be SSA.
342323 #[ instrument( level = "trace" , skip( self ) ) ]
343324 fn assign ( & mut self , local : Local , value : VnIndex ) {
325+ debug_assert ! ( self . ssa. is_ssa( local) ) ;
344326 self . locals [ local] = Some ( value) ;
345327
346328 // Only register the value if its type is `Sized`, as we will emit copies of it.
@@ -1638,15 +1620,19 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
16381620 if let StatementKind :: Assign ( box ( ref mut lhs, ref mut rvalue) ) = stmt. kind {
16391621 self . simplify_place_projection ( lhs, location) ;
16401622
1641- // Do not try to simplify a constant, it's already in canonical shape.
1642- if matches ! ( rvalue, Rvalue :: Use ( Operand :: Constant ( _) ) ) {
1643- return ;
1644- }
1645-
1646- let value = lhs
1647- . as_local ( )
1648- . and_then ( |local| self . locals [ local] )
1649- . or_else ( || self . simplify_rvalue ( rvalue, location) ) ;
1623+ let value = self . simplify_rvalue ( rvalue, location) ;
1624+ let value = if let Some ( local) = lhs. as_local ( )
1625+ && self . ssa . is_ssa ( local)
1626+ // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
1627+ // `local` as reusable if we have an exact type match.
1628+ && self . local_decls [ local] . ty == rvalue. ty ( self . local_decls , self . tcx )
1629+ {
1630+ let value = value. or_else ( || self . new_opaque ( ) ) . unwrap ( ) ;
1631+ self . assign ( local, value) ;
1632+ Some ( value)
1633+ } else {
1634+ value
1635+ } ;
16501636 let Some ( value) = value else { return } ;
16511637
16521638 if let Some ( const_) = self . try_as_constant ( value) {
@@ -1662,6 +1648,17 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
16621648 }
16631649 self . super_statement ( stmt, location) ;
16641650 }
1651+
1652+ fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
1653+ if let Terminator { kind : TerminatorKind :: Call { destination, .. } , .. } = terminator
1654+ && let Some ( local) = destination. as_local ( )
1655+ && self . ssa . is_ssa ( local)
1656+ {
1657+ let opaque = self . new_opaque ( ) . unwrap ( ) ;
1658+ self . assign ( local, opaque) ;
1659+ }
1660+ self . super_terminator ( terminator, location) ;
1661+ }
16651662}
16661663
16671664struct StorageRemover < ' tcx > {
0 commit comments