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, 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
- ) ;
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 {
@@ -247,7 +229,6 @@ struct VnState<'body, 'tcx> {
247
229
locals : IndexVec < Local , Option < VnIndex > > ,
248
230
/// Locals that are assigned that value.
249
231
// 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.
251
232
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
252
233
values : FxIndexSet < Value < ' tcx > > ,
253
234
/// Values evaluated as constants if possible.
@@ -339,6 +320,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
339
320
/// Record that `local` is assigned `value`. `local` must be SSA.
340
321
#[ instrument( level = "trace" , skip( self ) ) ]
341
322
fn assign ( & mut self , local : Local , value : VnIndex ) {
323
+ debug_assert ! ( self . ssa. is_ssa( local) ) ;
342
324
self . locals [ local] = Some ( value) ;
343
325
344
326
// 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> {
1633
1615
if let StatementKind :: Assign ( box ( ref mut lhs, ref mut rvalue) ) = stmt. kind {
1634
1616
self . simplify_place_projection ( lhs, location) ;
1635
1617
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
+ } ;
1645
1631
let Some ( value) = value else { return } ;
1646
1632
1647
1633
if let Some ( const_) = self . try_as_constant ( value) {
@@ -1657,6 +1643,17 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
1657
1643
}
1658
1644
self . super_statement ( stmt, location) ;
1659
1645
}
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
+ }
1660
1657
}
1661
1658
1662
1659
struct StorageRemover < ' tcx > {
0 commit comments