|
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,31 @@ 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() { |
968 |
| - match mode { |
969 |
| - ConstPropMode::FullConstProp => {} |
970 |
| - ConstPropMode::NoPropagation => self.ensure_not_propagated(local), |
971 |
| - ConstPropMode::OnlyInsideOwnBlock => { |
972 |
| - Self::remove_const(&mut self.ecx, local); |
973 |
| - self.ensure_not_propagated(local); |
| 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 | + if cfg!(debug_assertions) { |
| 993 | + for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { |
| 994 | + match mode { |
| 995 | + ConstPropMode::FullConstProp => {} |
| 996 | + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { |
| 997 | + self.ensure_not_propagated(local); |
| 998 | + } |
974 | 999 | }
|
975 | 1000 | }
|
976 | 1001 | }
|
977 |
| - self.ecx.machine.can_const_prop = can_const_prop; |
978 | 1002 | }
|
979 | 1003 | }
|
0 commit comments