3
3
//! MIR may contain repeated and/or redundant computations. The objective of this pass is to detect
4
4
//! such redundancies and re-use the already-computed result when possible.
5
5
//!
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
- //!
10
6
//! From those assignments, we construct a mapping `VnIndex -> Vec<(Local, Location)>` of available
11
7
//! values, the locals in which they are stored, and the assignment location.
12
8
//!
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
14
16
//! one, we compute the `VnIndex` of the rvalue. If this `VnIndex` is associated to a constant, we
15
17
//! replace the rvalue/operand by that constant. Otherwise, if there is an SSA local `y`
16
18
//! associated to this `VnIndex`, and if its definition location strictly dominates the assignment
@@ -107,7 +109,7 @@ use rustc_span::def_id::DefId;
107
109
use smallvec:: SmallVec ;
108
110
use tracing:: { debug, instrument, trace} ;
109
111
110
- use crate :: ssa:: { AssignedValue , SsaLocals } ;
112
+ use crate :: ssa:: SsaLocals ;
111
113
112
114
pub ( super ) struct GVN ;
113
115
@@ -126,31 +128,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
126
128
let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
127
129
128
130
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
- ) ;
151
131
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
+ }
154
136
155
137
let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
156
138
for bb in reverse_postorder {
@@ -246,7 +228,6 @@ struct VnState<'body, 'tcx> {
246
228
locals : IndexVec < Local , Option < VnIndex > > ,
247
229
/// Locals that are assigned that value.
248
230
// 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.
250
231
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
251
232
values : FxIndexSet < Value < ' tcx > > ,
252
233
/// Values evaluated as constants if possible.
@@ -341,6 +322,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
341
322
/// Record that `local` is assigned `value`. `local` must be SSA.
342
323
#[ instrument( level = "trace" , skip( self ) ) ]
343
324
fn assign ( & mut self , local : Local , value : VnIndex ) {
325
+ debug_assert ! ( self . ssa. is_ssa( local) ) ;
344
326
self . locals [ local] = Some ( value) ;
345
327
346
328
// 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> {
1638
1620
if let StatementKind :: Assign ( box ( ref mut lhs, ref mut rvalue) ) = stmt. kind {
1639
1621
self . simplify_place_projection ( lhs, location) ;
1640
1622
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
+ } ;
1650
1636
let Some ( value) = value else { return } ;
1651
1637
1652
1638
if let Some ( const_) = self . try_as_constant ( value) {
@@ -1662,6 +1648,17 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
1662
1648
}
1663
1649
self . super_statement ( stmt, location) ;
1664
1650
}
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
+ }
1665
1662
}
1666
1663
1667
1664
struct StorageRemover < ' tcx > {
0 commit comments