|
4 | 4 | use either::Right; |
5 | 5 |
|
6 | 6 | use rustc_const_eval::const_eval::CheckAlignment; |
7 | | -use rustc_data_structures::fx::FxHashSet; |
8 | 7 | use rustc_hir::def::DefKind; |
9 | 8 | use rustc_index::bit_set::BitSet; |
10 | 9 | use rustc_index::vec::IndexVec; |
@@ -152,24 +151,12 @@ impl<'tcx> MirPass<'tcx> for ConstProp { |
152 | 151 | pub struct ConstPropMachine<'mir, 'tcx> { |
153 | 152 | /// The virtual call stack. |
154 | 153 | stack: Vec<Frame<'mir, 'tcx>>, |
155 | | - /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end. |
156 | | - pub written_only_inside_own_block_locals: FxHashSet<Local>, |
157 | | - /// Locals that need to be cleared after every block terminates. |
158 | | - pub only_propagate_inside_block_locals: BitSet<Local>, |
159 | 154 | pub can_const_prop: IndexVec<Local, ConstPropMode>, |
160 | 155 | } |
161 | 156 |
|
162 | 157 | impl ConstPropMachine<'_, '_> { |
163 | | - pub fn new( |
164 | | - only_propagate_inside_block_locals: BitSet<Local>, |
165 | | - can_const_prop: IndexVec<Local, ConstPropMode>, |
166 | | - ) -> Self { |
167 | | - Self { |
168 | | - stack: Vec::new(), |
169 | | - written_only_inside_own_block_locals: Default::default(), |
170 | | - only_propagate_inside_block_locals, |
171 | | - can_const_prop, |
172 | | - } |
| 158 | + pub fn new(can_const_prop: IndexVec<Local, ConstPropMode>) -> Self { |
| 159 | + Self { stack: Vec::new(), can_const_prop } |
173 | 160 | } |
174 | 161 | } |
175 | 162 |
|
@@ -255,16 +242,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> |
255 | 242 | frame: usize, |
256 | 243 | local: Local, |
257 | 244 | ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> { |
258 | | - if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { |
259 | | - throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") |
260 | | - } |
261 | | - if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) { |
262 | | - trace!( |
263 | | - "mutating local {:?} which is restricted to its block. \ |
264 | | - Will remove it from const-prop after block is finished.", |
265 | | - local |
266 | | - ); |
267 | | - ecx.machine.written_only_inside_own_block_locals.insert(local); |
| 245 | + assert_eq!(frame, 0); |
| 246 | + match ecx.machine.can_const_prop[local] { |
| 247 | + ConstPropMode::NoPropagation => { |
| 248 | + throw_machine_stop_str!( |
| 249 | + "tried to write to a local that is marked as not propagatable" |
| 250 | + ) |
| 251 | + } |
| 252 | + ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {} |
268 | 253 | } |
269 | 254 | ecx.machine.stack[frame].locals[local].access_mut() |
270 | 255 | } |
@@ -369,17 +354,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { |
369 | 354 | let param_env = tcx.param_env_reveal_all_normalized(def_id); |
370 | 355 |
|
371 | 356 | let can_const_prop = CanConstProp::check(tcx, param_env, body); |
372 | | - let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len()); |
373 | | - for (l, mode) in can_const_prop.iter_enumerated() { |
374 | | - if *mode == ConstPropMode::OnlyInsideOwnBlock { |
375 | | - only_propagate_inside_block_locals.insert(l); |
376 | | - } |
377 | | - } |
378 | 357 | let mut ecx = InterpCx::new( |
379 | 358 | tcx, |
380 | 359 | tcx.def_span(def_id), |
381 | 360 | param_env, |
382 | | - ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop), |
| 361 | + ConstPropMachine::new(can_const_prop), |
383 | 362 | ); |
384 | 363 |
|
385 | 364 | let ret_layout = ecx |
@@ -977,26 +956,33 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { |
977 | 956 | fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { |
978 | 957 | self.super_basic_block_data(block, data); |
979 | 958 |
|
| 959 | + let ensure_not_propagated = |this: &mut Self, local: Local| { |
| 960 | + if cfg!(debug_assertions) { |
| 961 | + assert!( |
| 962 | + this.get_const(local.into()).is_none() |
| 963 | + || this |
| 964 | + .layout_of(this.local_decls[local].ty) |
| 965 | + .map_or(true, |layout| layout.is_zst()), |
| 966 | + "failed to remove values for `{local:?}`, value={:?}", |
| 967 | + this.get_const(local.into()), |
| 968 | + ) |
| 969 | + } |
| 970 | + }; |
| 971 | + |
980 | 972 | // We remove all Locals which are restricted in propagation to their containing blocks and |
981 | 973 | // which were modified in the current block. |
982 | 974 | // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. |
983 | | - let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); |
984 | | - for &local in locals.iter() { |
985 | | - Self::remove_const(&mut self.ecx, local); |
986 | | - } |
987 | | - locals.clear(); |
988 | | - // Put it back so we reuse the heap of the storage |
989 | | - self.ecx.machine.written_only_inside_own_block_locals = locals; |
990 | | - if cfg!(debug_assertions) { |
991 | | - // Ensure we are correctly erasing locals with the non-debug-assert logic. |
992 | | - for local in self.ecx.machine.only_propagate_inside_block_locals.iter() { |
993 | | - assert!( |
994 | | - self.get_const(local.into()).is_none() |
995 | | - || self |
996 | | - .layout_of(self.local_decls[local].ty) |
997 | | - .map_or(true, |layout| layout.is_zst()) |
998 | | - ) |
| 975 | + let can_const_prop = std::mem::take(&mut self.ecx.machine.can_const_prop); |
| 976 | + for (local, &mode) in can_const_prop.iter_enumerated() { |
| 977 | + match mode { |
| 978 | + ConstPropMode::FullConstProp => {} |
| 979 | + ConstPropMode::NoPropagation => ensure_not_propagated(self, local), |
| 980 | + ConstPropMode::OnlyInsideOwnBlock => { |
| 981 | + Self::remove_const(&mut self.ecx, local); |
| 982 | + ensure_not_propagated(self, local); |
| 983 | + } |
999 | 984 | } |
1000 | 985 | } |
| 986 | + self.ecx.machine.can_const_prop = can_const_prop; |
1001 | 987 | } |
1002 | 988 | } |
0 commit comments