|
4 | 4 | use either::Right; |
5 | 5 |
|
6 | 6 | use rustc_const_eval::const_eval::CheckAlignment; |
| 7 | +use rustc_data_structures::fx::FxHashSet; |
7 | 8 | use rustc_hir::def::DefKind; |
8 | 9 | use rustc_index::bit_set::BitSet; |
9 | 10 | use rustc_index::vec::IndexVec; |
@@ -151,12 +152,17 @@ impl<'tcx> MirPass<'tcx> for ConstProp { |
151 | 152 | pub struct ConstPropMachine<'mir, 'tcx> { |
152 | 153 | /// The virtual call stack. |
153 | 154 | stack: Vec<Frame<'mir, 'tcx>>, |
| 155 | + pub written_only_inside_own_block_locals: FxHashSet<Local>, |
154 | 156 | pub can_const_prop: IndexVec<Local, ConstPropMode>, |
155 | 157 | } |
156 | 158 |
|
157 | 159 | impl ConstPropMachine<'_, '_> { |
158 | 160 | pub fn new(can_const_prop: IndexVec<Local, ConstPropMode>) -> Self { |
159 | | - Self { stack: Vec::new(), can_const_prop } |
| 161 | + Self { |
| 162 | + stack: Vec::new(), |
| 163 | + written_only_inside_own_block_locals: Default::default(), |
| 164 | + can_const_prop, |
| 165 | + } |
160 | 166 | } |
161 | 167 | } |
162 | 168 |
|
@@ -249,7 +255,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> |
249 | 255 | "tried to write to a local that is marked as not propagatable" |
250 | 256 | ) |
251 | 257 | } |
252 | | - ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {} |
| 258 | + ConstPropMode::OnlyInsideOwnBlock => { |
| 259 | + ecx.machine.written_only_inside_own_block_locals.insert(local); |
| 260 | + } |
| 261 | + ConstPropMode::FullConstProp => {} |
253 | 262 | } |
254 | 263 | ecx.machine.stack[frame].locals[local].access_mut() |
255 | 264 | } |
@@ -416,6 +425,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { |
416 | 425 | fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { |
417 | 426 | ecx.frame_mut().locals[local].value = |
418 | 427 | LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)); |
| 428 | + ecx.machine.written_only_inside_own_block_locals.remove(&local); |
419 | 429 | } |
420 | 430 |
|
421 | 431 | /// Returns the value, if any, of evaluating `c`. |
@@ -693,7 +703,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { |
693 | 703 | } |
694 | 704 | } |
695 | 705 |
|
696 | | - fn ensure_not_propagated(&mut self, local: Local) { |
| 706 | + fn ensure_not_propagated(&self, local: Local) { |
697 | 707 | if cfg!(debug_assertions) { |
698 | 708 | assert!( |
699 | 709 | self.get_const(local.into()).is_none() |
@@ -963,17 +973,30 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { |
963 | 973 | // We remove all Locals which are restricted in propagation to their containing blocks and |
964 | 974 | // which were modified in the current block. |
965 | 975 | // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. |
966 | | - let can_const_prop = std::mem::take(&mut self.ecx.machine.can_const_prop); |
967 | | - for (local, &mode) in can_const_prop.iter_enumerated() { |
| 976 | + let mut written_only_inside_own_block_locals = |
| 977 | + std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); |
| 978 | + |
| 979 | + // This loop can get very hot for some bodies: it check each local in each bb. |
| 980 | + // To avoid this quadratic behaviour, we only clear the locals that were modified inside |
| 981 | + // the current block. |
| 982 | + for local in written_only_inside_own_block_locals.drain() { |
| 983 | + debug_assert_eq!( |
| 984 | + self.ecx.machine.can_const_prop[local], |
| 985 | + ConstPropMode::OnlyInsideOwnBlock |
| 986 | + ); |
| 987 | + Self::remove_const(&mut self.ecx, local); |
| 988 | + } |
| 989 | + self.ecx.machine.written_only_inside_own_block_locals = |
| 990 | + written_only_inside_own_block_locals; |
| 991 | + |
| 992 | + #[cfg(debug_assertions)] |
| 993 | + for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { |
968 | 994 | match mode { |
969 | 995 | ConstPropMode::FullConstProp => {} |
970 | | - ConstPropMode::NoPropagation => self.ensure_not_propagated(local), |
971 | | - ConstPropMode::OnlyInsideOwnBlock => { |
972 | | - Self::remove_const(&mut self.ecx, local); |
| 996 | + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { |
973 | 997 | self.ensure_not_propagated(local); |
974 | 998 | } |
975 | 999 | } |
976 | 1000 | } |
977 | | - self.ecx.machine.can_const_prop = can_const_prop; |
978 | 1001 | } |
979 | 1002 | } |
0 commit comments