summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_transform/src/remove_zsts.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:29 +0000
commit631cd5845e8de329d0e227aaa707d7ea228b8f8f (patch)
treea1b87c8f8cad01cf18f7c5f57a08f102771ed303 /compiler/rustc_mir_transform/src/remove_zsts.rs
parentAdding debian version 1.69.0+dfsg1-1. (diff)
downloadrustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.tar.xz
rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_transform/src/remove_zsts.rs')
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs136
1 files changed, 107 insertions, 29 deletions
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 1becfddb2..1f37f03cf 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -1,7 +1,9 @@
-//! Removes assignments to ZST places.
+//! Removes operations on ZST places, and convert ZST operands to constants.
use crate::MirPass;
-use rustc_middle::mir::{Body, StatementKind};
+use rustc_middle::mir::interpret::ConstValue;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};
pub struct RemoveZsts;
@@ -16,38 +18,24 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
if tcx.type_of(body.source.def_id()).subst_identity().is_generator() {
return;
}
- let param_env = tcx.param_env(body.source.def_id());
- let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let local_decls = &body.local_decls;
- for block in basic_blocks {
- for statement in block.statements.iter_mut() {
- if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
- statement.kind
- {
- let place_ty = place.ty(local_decls, tcx).ty;
- if !maybe_zst(place_ty) {
- continue;
- }
- let Ok(layout) = tcx.layout_of(param_env.and(place_ty)) else {
- continue;
- };
- if !layout.is_zst() {
- continue;
- }
- if tcx.consider_optimizing(|| {
- format!(
- "RemoveZsts - Place: {:?} SourceInfo: {:?}",
- place, statement.source_info
- )
- }) {
- statement.make_nop();
- }
- }
- }
+ let mut replacer = Replacer { tcx, param_env, local_decls };
+ for var_debug_info in &mut body.var_debug_info {
+ replacer.visit_var_debug_info(var_debug_info);
+ }
+ for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
+ replacer.visit_basic_block_data(bb, data);
}
}
}
+struct Replacer<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ local_decls: &'a LocalDecls<'tcx>,
+}
+
/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
fn maybe_zst(ty: Ty<'_>) -> bool {
match ty.kind() {
@@ -63,3 +51,93 @@ fn maybe_zst(ty: Ty<'_>) -> bool {
_ => false,
}
}
+
+impl<'tcx> Replacer<'_, 'tcx> {
+ fn known_to_be_zst(&self, ty: Ty<'tcx>) -> bool {
+ if !maybe_zst(ty) {
+ return false;
+ }
+ let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else {
+ return false;
+ };
+ layout.is_zst()
+ }
+
+ fn make_zst(&self, ty: Ty<'tcx>) -> Constant<'tcx> {
+ debug_assert!(self.known_to_be_zst(ty));
+ Constant {
+ span: rustc_span::DUMMY_SP,
+ user_ty: None,
+ literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
+ }
+ }
+}
+
+impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) {
+ match var_debug_info.value {
+ VarDebugInfoContents::Const(_) => {}
+ VarDebugInfoContents::Place(place) => {
+ let place_ty = place.ty(self.local_decls, self.tcx).ty;
+ if self.known_to_be_zst(place_ty) {
+ var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty))
+ }
+ }
+ VarDebugInfoContents::Composite { ty, fragments: _ } => {
+ if self.known_to_be_zst(ty) {
+ var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(ty))
+ }
+ }
+ }
+ }
+
+ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
+ if let Operand::Constant(_) = operand {
+ return;
+ }
+ let op_ty = operand.ty(self.local_decls, self.tcx);
+ if self.known_to_be_zst(op_ty)
+ && self.tcx.consider_optimizing(|| {
+ format!("RemoveZsts - Operand: {:?} Location: {:?}", operand, loc)
+ })
+ {
+ *operand = Operand::Constant(Box::new(self.make_zst(op_ty)))
+ }
+ }
+
+ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, loc: Location) {
+ let place_for_ty = match statement.kind {
+ StatementKind::Assign(box (place, ref rvalue)) => {
+ rvalue.is_safe_to_remove().then_some(place)
+ }
+ StatementKind::Deinit(box place)
+ | StatementKind::SetDiscriminant { box place, variant_index: _ }
+ | StatementKind::AscribeUserType(box (place, _), _)
+ | StatementKind::Retag(_, box place)
+ | StatementKind::PlaceMention(box place)
+ | StatementKind::FakeRead(box (_, place)) => Some(place),
+ StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
+ Some(local.into())
+ }
+ StatementKind::Coverage(_)
+ | StatementKind::Intrinsic(_)
+ | StatementKind::Nop
+ | StatementKind::ConstEvalCounter => None,
+ };
+ if let Some(place_for_ty) = place_for_ty
+ && let ty = place_for_ty.ty(self.local_decls, self.tcx).ty
+ && self.known_to_be_zst(ty)
+ && self.tcx.consider_optimizing(|| {
+ format!("RemoveZsts - Place: {:?} SourceInfo: {:?}", place_for_ty, statement.source_info)
+ })
+ {
+ statement.make_nop();
+ } else {
+ self.super_statement(statement, loc);
+ }
+ }
+}