|
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