Skip to content

Commit

Permalink
Auto merge of #107270 - cjgillot:remove-zst, r=oli-obk
Browse files Browse the repository at this point in the history
Replace ZST operands and debuginfo by constants.

This is work that ConstProp will not have to do.
Split from #107267
  • Loading branch information
bors committed Mar 16, 2023
2 parents 1203e08 + e8afb08 commit e386217
Show file tree
Hide file tree
Showing 34 changed files with 325 additions and 209 deletions.
136 changes: 107 additions & 29 deletions compiler/rustc_mir_transform/src/remove_zsts.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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() {
Expand All @@ -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);
}
}
}
1 change: 0 additions & 1 deletion tests/debuginfo/type-names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@
// 0-sized structs appear to be optimized away in some cases, so only check the structs that do
// actually appear.
// cdb-command:dv /t *_struct
// cdb-check:struct type_names::GenericStruct<enum2$<type_names::mod1::Enum2>,f64> mut_generic_struct = [...]

// ENUMS
// cdb-command:dv /t *_enum_*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
}

bb1: {
StorageLive(_2); // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
_2 = begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/std/src/panic.rs:LL:COL
Expand Down
10 changes: 2 additions & 8 deletions tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@
let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
scope 3 {
debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21
let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
scope 5 {
debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
let _7: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
scope 7 {
debug _non_utf8_str => _7; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
}
}
scope 6 {
Expand Down Expand Up @@ -52,10 +50,6 @@
+ // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
StorageLive(_7); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
StorageDead(_7); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
return; // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2
Expand Down
76 changes: 76 additions & 0 deletions tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
- // MIR for `main` before RemoveZsts
+ // MIR for `main` after RemoveZsts

fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:+0:11: +0:11
let _1: char; // in scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22
let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63
let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59
let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55
let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73
let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65
scope 1 {
debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22
let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
scope 3 {
debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21
let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
scope 5 {
- debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
+ debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
scope 7 {
- debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
+ debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
}
}
scope 6 {
}
}
scope 4 {
}
}
scope 2 {
}

bb0: {
StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22
StorageLive(_2); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
_2 = InvalidChar { int: const 1114113_u32 }; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
_1 = (_2.1: char); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67
StorageDead(_2); // scope 0 at $DIR/invalid_constant.rs:+6:69: +6:70
StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
StorageLive(_4); // scope 1 at $DIR/invalid_constant.rs:+13:25: +13:59
StorageLive(_5); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
_5 = InvalidTag { int: const 4_u32 }; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
_4 = (_5.1: E); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
_3 = [move _4]; // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
- StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
- StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
+ nop; // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
+ nop; // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
_8 = NoVariants { int: const 0_u32 }; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
- _7 = (_8.1: Empty); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
- _6 = [move _7]; // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
- StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
+ nop; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
+ nop; // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
+ nop; // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75
- StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
- _0 = const (); // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
- StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
- StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
+ nop; // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+ nop; // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
+ nop; // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
+ nop; // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
return; // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2
}
}

1 change: 1 addition & 0 deletions tests/mir-opt/const_prop/invalid_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum E { A, B, C }
#[derive(Copy, Clone)]
enum Empty {}

// EMIT_MIR invalid_constant.main.RemoveZsts.diff
// EMIT_MIR invalid_constant.main.ConstProp.diff
fn main() {
// An invalid char.
Expand Down
7 changes: 1 addition & 6 deletions tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@
let mut _0: (); // return place in scope 0 at $DIR/issue_66971.rs:+0:11: +0:11
let _1: (); // in scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
let mut _2: ((), u8, u8); // in scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
let mut _3: (); // in scope 0 at $DIR/issue_66971.rs:+1:13: +1:15

bb0: {
StorageLive(_1); // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
StorageLive(_2); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
StorageLive(_3); // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
_2 = (move _3, const 0_u8, const 0_u8); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
StorageDead(_3); // scope 0 at $DIR/issue_66971.rs:+1:21: +1:22
_2 = (const (), const 0_u8, const 0_u8); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
_1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
// mir::Constant
// + span: $DIR/issue_66971.rs:17:5: 17:11
Expand All @@ -21,7 +17,6 @@

bb1: {
StorageDead(_2); // scope 0 at $DIR/issue_66971.rs:+1:22: +1:23
StorageDead(_1); // scope 0 at $DIR/issue_66971.rs:+1:23: +1:24
return; // scope 0 at $DIR/issue_66971.rs:+2:2: +2:2
}
}
Expand Down
2 changes: 0 additions & 2 deletions tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
let mut _3: (u8, u8); // in scope 0 at $DIR/issue_67019.rs:+1:11: +1:17

bb0: {
StorageLive(_1); // scope 0 at $DIR/issue_67019.rs:+1:5: +1:20
StorageLive(_2); // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
StorageLive(_3); // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
- _3 = (const 1_u8, const 2_u8); // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
Expand All @@ -23,7 +22,6 @@

bb1: {
StorageDead(_2); // scope 0 at $DIR/issue_67019.rs:+1:19: +1:20
StorageDead(_1); // scope 0 at $DIR/issue_67019.rs:+1:20: +1:21
return; // scope 0 at $DIR/issue_67019.rs:+2:2: +2:2
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

bb0: {
_1 = const 1_u32; // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14
StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
- _2 = consume(_1) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
+ _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
// mir::Constant
Expand All @@ -21,7 +20,6 @@
}

bb1: {
StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
return; // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@
bb0: {
- _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
+ _1 = const (1_u32, 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
StorageLive(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
_2 = consume(_1) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
// mir::Constant
// + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12
// + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(<ZST>) }
}

bb1: {
StorageDead(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16
return; // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2
}
}
Expand Down
Loading

0 comments on commit e386217

Please sign in to comment.