File tree Expand file tree Collapse file tree 6 files changed +47
-3
lines changed Expand file tree Collapse file tree 6 files changed +47
-3
lines changed Original file line number Diff line number Diff line change 1+ use rustc_index:: bit_set:: DenseBitSet ;
2+
3+ use super :: * ;
4+
5+ /// Compute the set of loop headers in the given body. A loop header is usually defined as a block
6+ /// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
7+ /// However, computing dominators is expensive, so we approximate according to the post-order
8+ /// traversal order. A loop header for us is a block which is visited after its predecessor in
9+ /// post-order. This is ok as we mostly need a heuristic.
10+ pub fn maybe_loop_headers ( body : & Body < ' _ > ) -> DenseBitSet < BasicBlock > {
11+ let mut maybe_loop_headers = DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ;
12+ let mut visited = DenseBitSet :: new_empty ( body. basic_blocks . len ( ) ) ;
13+ for ( bb, bbdata) in traversal:: postorder ( body) {
14+ // Post-order means we visit successors before the block for acyclic CFGs.
15+ // If the successor is not visited yet, consider it a loop header.
16+ for succ in bbdata. terminator ( ) . successors ( ) {
17+ if !visited. contains ( succ) {
18+ maybe_loop_headers. insert ( succ) ;
19+ }
20+ }
21+
22+ // Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
23+ // bb1: goto -> bb1;
24+ let _new = visited. insert ( bb) ;
25+ debug_assert ! ( _new) ;
26+ }
27+
28+ maybe_loop_headers
29+ }
Original file line number Diff line number Diff line change @@ -51,6 +51,8 @@ mod statement;
5151mod syntax;
5252mod terminator;
5353
54+ #[ path = "loop.rs" ]
55+ pub mod loop_;
5456pub mod traversal;
5557pub mod visit;
5658
Original file line number Diff line number Diff line change @@ -129,6 +129,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
129129 let ssa = SsaLocals :: new ( tcx, body, typing_env) ;
130130 // Clone dominators because we need them while mutating the body.
131131 let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
132+ let maybe_loop = !loop_:: maybe_loop_headers ( body) . is_empty ( ) ;
132133
133134 let arena = DroplessArena :: default ( ) ;
134135 let mut state =
@@ -141,6 +142,10 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
141142
142143 let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
143144 for bb in reverse_postorder {
145+ // N.B. With loops, reverse postorder cannot produce a valid topological order.
146+ if maybe_loop {
147+ state. invalidate_derefs ( ) ;
148+ }
144149 let data = & mut body. basic_blocks . as_mut_preserves_cfg ( ) [ bb] ;
145150 state. visit_basic_block_data ( bb, data) ;
146151 }
Original file line number Diff line number Diff line change 7171 StorageLive(_12);
7272 _12 = copy _7;
7373- _11 = Value::V0(move _12);
74- + _11 = copy (*_3 );
74+ + _11 = Value::V0( copy _7 );
7575 StorageDead(_12);
7676 StorageLive(_13);
7777 StorageLive(_14);
Original file line number Diff line number Diff line change 1- // skip-filecheck
21//@ test-mir-pass: GVN
32
43#![ crate_type = "lib" ]
@@ -9,8 +8,17 @@ pub enum Value {
98 V1 ,
109}
1110
11+ // Check that we do not use the dereferenced value of `val_alias` when returning.
12+
1213// EMIT_MIR gvn_loop.loop_deref_mut.GVN.diff
1314fn loop_deref_mut ( val : & mut Value ) -> Value {
15+ // CHECK-LABEL: fn loop_deref_mut(
16+ // CHECK: [[VAL_REF:_.*]] = get::<Value>(
17+ // CHECK: [[V:_.*]] = copy (((*[[VAL_REF]]) as V0).0: i32);
18+ // CEHCK-NOT: copy (*[[VAL_REF]]);
19+ // CHECK: [[RET:_*]] = Value::V0(copy [[V]]);
20+ // CEHCK-NOT: copy (*[[VAL_REF]]);
21+ // CHECK: _0 = move [[RET]]
1422 let val_alias: & Value = get ( val) ;
1523 let mut stop = false ;
1624 let Value :: V0 ( v) = * val_alias else { unsafe { core:: intrinsics:: unreachable ( ) } } ;
Original file line number Diff line number Diff line change 11//@ compile-flags: -O
2- //@ run-fail
2+ //@ run-pass
33
44pub enum Value {
55 V0 ( i32 ) ,
You can’t perform that action at this time.
0 commit comments