Skip to content

Commit e386217

Browse files
committed
Auto merge of rust-lang#107270 - cjgillot:remove-zst, r=oli-obk
Replace ZST operands and debuginfo by constants. This is work that ConstProp will not have to do. Split from rust-lang#107267
2 parents 1203e08 + e8afb08 commit e386217

34 files changed

+325
-209
lines changed
+107-29
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
//! Removes assignments to ZST places.
1+
//! Removes operations on ZST places, and convert ZST operands to constants.
22
33
use crate::MirPass;
4-
use rustc_middle::mir::{Body, StatementKind};
4+
use rustc_middle::mir::interpret::ConstValue;
5+
use rustc_middle::mir::visit::*;
6+
use rustc_middle::mir::*;
57
use rustc_middle::ty::{self, Ty, TyCtxt};
68

79
pub struct RemoveZsts;
@@ -16,38 +18,24 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
1618
if tcx.type_of(body.source.def_id()).subst_identity().is_generator() {
1719
return;
1820
}
19-
let param_env = tcx.param_env(body.source.def_id());
20-
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
21+
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
2122
let local_decls = &body.local_decls;
22-
for block in basic_blocks {
23-
for statement in block.statements.iter_mut() {
24-
if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
25-
statement.kind
26-
{
27-
let place_ty = place.ty(local_decls, tcx).ty;
28-
if !maybe_zst(place_ty) {
29-
continue;
30-
}
31-
let Ok(layout) = tcx.layout_of(param_env.and(place_ty)) else {
32-
continue;
33-
};
34-
if !layout.is_zst() {
35-
continue;
36-
}
37-
if tcx.consider_optimizing(|| {
38-
format!(
39-
"RemoveZsts - Place: {:?} SourceInfo: {:?}",
40-
place, statement.source_info
41-
)
42-
}) {
43-
statement.make_nop();
44-
}
45-
}
46-
}
23+
let mut replacer = Replacer { tcx, param_env, local_decls };
24+
for var_debug_info in &mut body.var_debug_info {
25+
replacer.visit_var_debug_info(var_debug_info);
26+
}
27+
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
28+
replacer.visit_basic_block_data(bb, data);
4729
}
4830
}
4931
}
5032

33+
struct Replacer<'a, 'tcx> {
34+
tcx: TyCtxt<'tcx>,
35+
param_env: ty::ParamEnv<'tcx>,
36+
local_decls: &'a LocalDecls<'tcx>,
37+
}
38+
5139
/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
5240
fn maybe_zst(ty: Ty<'_>) -> bool {
5341
match ty.kind() {
@@ -63,3 +51,93 @@ fn maybe_zst(ty: Ty<'_>) -> bool {
6351
_ => false,
6452
}
6553
}
54+
55+
impl<'tcx> Replacer<'_, 'tcx> {
56+
fn known_to_be_zst(&self, ty: Ty<'tcx>) -> bool {
57+
if !maybe_zst(ty) {
58+
return false;
59+
}
60+
let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else {
61+
return false;
62+
};
63+
layout.is_zst()
64+
}
65+
66+
fn make_zst(&self, ty: Ty<'tcx>) -> Constant<'tcx> {
67+
debug_assert!(self.known_to_be_zst(ty));
68+
Constant {
69+
span: rustc_span::DUMMY_SP,
70+
user_ty: None,
71+
literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
72+
}
73+
}
74+
}
75+
76+
impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
77+
fn tcx(&self) -> TyCtxt<'tcx> {
78+
self.tcx
79+
}
80+
81+
fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) {
82+
match var_debug_info.value {
83+
VarDebugInfoContents::Const(_) => {}
84+
VarDebugInfoContents::Place(place) => {
85+
let place_ty = place.ty(self.local_decls, self.tcx).ty;
86+
if self.known_to_be_zst(place_ty) {
87+
var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty))
88+
}
89+
}
90+
VarDebugInfoContents::Composite { ty, fragments: _ } => {
91+
if self.known_to_be_zst(ty) {
92+
var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(ty))
93+
}
94+
}
95+
}
96+
}
97+
98+
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
99+
if let Operand::Constant(_) = operand {
100+
return;
101+
}
102+
let op_ty = operand.ty(self.local_decls, self.tcx);
103+
if self.known_to_be_zst(op_ty)
104+
&& self.tcx.consider_optimizing(|| {
105+
format!("RemoveZsts - Operand: {:?} Location: {:?}", operand, loc)
106+
})
107+
{
108+
*operand = Operand::Constant(Box::new(self.make_zst(op_ty)))
109+
}
110+
}
111+
112+
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, loc: Location) {
113+
let place_for_ty = match statement.kind {
114+
StatementKind::Assign(box (place, ref rvalue)) => {
115+
rvalue.is_safe_to_remove().then_some(place)
116+
}
117+
StatementKind::Deinit(box place)
118+
| StatementKind::SetDiscriminant { box place, variant_index: _ }
119+
| StatementKind::AscribeUserType(box (place, _), _)
120+
| StatementKind::Retag(_, box place)
121+
| StatementKind::PlaceMention(box place)
122+
| StatementKind::FakeRead(box (_, place)) => Some(place),
123+
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
124+
Some(local.into())
125+
}
126+
StatementKind::Coverage(_)
127+
| StatementKind::Intrinsic(_)
128+
| StatementKind::Nop
129+
| StatementKind::ConstEvalCounter => None,
130+
};
131+
if let Some(place_for_ty) = place_for_ty
132+
&& let ty = place_for_ty.ty(self.local_decls, self.tcx).ty
133+
&& self.known_to_be_zst(ty)
134+
&& self.tcx.consider_optimizing(|| {
135+
format!("RemoveZsts - Place: {:?} SourceInfo: {:?}", place_for_ty, statement.source_info)
136+
})
137+
{
138+
statement.make_nop();
139+
} else {
140+
self.super_statement(statement, loc);
141+
}
142+
}
143+
}

tests/debuginfo/type-names.rs

-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@
175175
// 0-sized structs appear to be optimized away in some cases, so only check the structs that do
176176
// actually appear.
177177
// cdb-command:dv /t *_struct
178-
// cdb-check:struct type_names::GenericStruct<enum2$<type_names::mod1::Enum2>,f64> mut_generic_struct = [...]
179178

180179
// ENUMS
181180
// cdb-command:dv /t *_enum_*

tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
}
1515

1616
bb1: {
17-
StorageLive(_2); // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
1817
_2 = begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
1918
// mir::Constant
2019
// + span: $SRC_DIR/std/src/panic.rs:LL:COL

tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff

+2-8
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@
1212
let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
1313
scope 3 {
1414
debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21
15-
let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
1615
scope 5 {
17-
debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
18-
let _7: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
16+
debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
1917
scope 7 {
20-
debug _non_utf8_str => _7; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
18+
debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
2119
}
2220
}
2321
scope 6 {
@@ -52,10 +50,6 @@
5250
+ // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
5351
StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
5452
StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
55-
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
56-
StorageLive(_7); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
57-
StorageDead(_7); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
58-
StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
5953
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
6054
StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
6155
return; // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
- // MIR for `main` before RemoveZsts
2+
+ // MIR for `main` after RemoveZsts
3+
4+
fn main() -> () {
5+
let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:+0:11: +0:11
6+
let _1: char; // in scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22
7+
let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63
8+
let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59
9+
let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55
10+
let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73
11+
let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65
12+
scope 1 {
13+
debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22
14+
let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
15+
scope 3 {
16+
debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21
17+
let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
18+
scope 5 {
19+
- debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
20+
+ debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
21+
let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
22+
scope 7 {
23+
- debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
24+
+ debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
25+
}
26+
}
27+
scope 6 {
28+
}
29+
}
30+
scope 4 {
31+
}
32+
}
33+
scope 2 {
34+
}
35+
36+
bb0: {
37+
StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22
38+
StorageLive(_2); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
39+
_2 = InvalidChar { int: const 1114113_u32 }; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
40+
_1 = (_2.1: char); // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67
41+
StorageDead(_2); // scope 0 at $DIR/invalid_constant.rs:+6:69: +6:70
42+
StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
43+
StorageLive(_4); // scope 1 at $DIR/invalid_constant.rs:+13:25: +13:59
44+
StorageLive(_5); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
45+
_5 = InvalidTag { int: const 4_u32 }; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
46+
_4 = (_5.1: E); // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
47+
_3 = [move _4]; // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
48+
StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
49+
StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
50+
- StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
51+
- StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
52+
+ nop; // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
53+
+ nop; // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
54+
StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
55+
_8 = NoVariants { int: const 0_u32 }; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
56+
- _7 = (_8.1: Empty); // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
57+
- _6 = [move _7]; // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
58+
- StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
59+
+ nop; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
60+
+ nop; // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
61+
+ nop; // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
62+
StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75
63+
- StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
64+
- _0 = const (); // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
65+
- StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
66+
- StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
67+
+ nop; // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
68+
+ nop; // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
69+
+ nop; // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
70+
+ nop; // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
71+
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
72+
StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
73+
return; // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2
74+
}
75+
}
76+

tests/mir-opt/const_prop/invalid_constant.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ enum E { A, B, C }
1111
#[derive(Copy, Clone)]
1212
enum Empty {}
1313

14+
// EMIT_MIR invalid_constant.main.RemoveZsts.diff
1415
// EMIT_MIR invalid_constant.main.ConstProp.diff
1516
fn main() {
1617
// An invalid char.

tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff

+1-6
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@
55
let mut _0: (); // return place in scope 0 at $DIR/issue_66971.rs:+0:11: +0:11
66
let _1: (); // in scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
77
let mut _2: ((), u8, u8); // in scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
8-
let mut _3: (); // in scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
98

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

2218
bb1: {
2319
StorageDead(_2); // scope 0 at $DIR/issue_66971.rs:+1:22: +1:23
24-
StorageDead(_1); // scope 0 at $DIR/issue_66971.rs:+1:23: +1:24
2520
return; // scope 0 at $DIR/issue_66971.rs:+2:2: +2:2
2621
}
2722
}

tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff

-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
let mut _3: (u8, u8); // in scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
99

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

2423
bb1: {
2524
StorageDead(_2); // scope 0 at $DIR/issue_67019.rs:+1:19: +1:20
26-
StorageDead(_1); // scope 0 at $DIR/issue_67019.rs:+1:20: +1:21
2725
return; // scope 0 at $DIR/issue_67019.rs:+2:2: +2:2
2826
}
2927
}

tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff

-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

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

2322
bb1: {
24-
StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
2523
return; // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
2624
}
2725
}

tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff

-2
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@
1313
bb0: {
1414
- _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
1515
+ _1 = const (1_u32, 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
16-
StorageLive(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
1716
_2 = consume(_1) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
1817
// mir::Constant
1918
// + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12
2019
// + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(<ZST>) }
2120
}
2221

2322
bb1: {
24-
StorageDead(_2); // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16
2523
return; // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2
2624
}
2725
}

0 commit comments

Comments
 (0)