1
- //! Removes assignments to ZST places.
1
+ //! Removes operations on ZST places, and convert ZST operands to constants .
2
2
3
3
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:: * ;
5
7
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
6
8
7
9
pub struct RemoveZsts ;
@@ -16,38 +18,24 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
16
18
if tcx. type_of ( body. source . def_id ( ) ) . is_generator ( ) {
17
19
return ;
18
20
}
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 ( ) ) ;
21
22
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) ;
47
29
}
48
30
}
49
31
}
50
32
33
+ struct Replacer < ' a , ' tcx > {
34
+ tcx : TyCtxt < ' tcx > ,
35
+ param_env : ty:: ParamEnv < ' tcx > ,
36
+ local_decls : & ' a LocalDecls < ' tcx > ,
37
+ }
38
+
51
39
/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
52
40
fn maybe_zst ( ty : Ty < ' _ > ) -> bool {
53
41
match ty. kind ( ) {
@@ -63,3 +51,89 @@ fn maybe_zst(ty: Ty<'_>) -> bool {
63
51
_ => false ,
64
52
}
65
53
}
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 :: FakeRead ( box ( _, place) ) => Some ( place) ,
122
+ StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => {
123
+ Some ( local. into ( ) )
124
+ }
125
+ StatementKind :: Coverage ( _) | StatementKind :: Intrinsic ( _) | StatementKind :: Nop => None ,
126
+ } ;
127
+ if let Some ( place_for_ty) = place_for_ty
128
+ && let ty = place_for_ty. ty ( self . local_decls , self . tcx ) . ty
129
+ && self . known_to_be_zst ( ty)
130
+ && self . tcx . consider_optimizing ( || {
131
+ format ! ( "RemoveZsts - Place: {:?} SourceInfo: {:?}" , place_for_ty, statement. source_info)
132
+ } )
133
+ {
134
+ statement. make_nop ( ) ;
135
+ } else {
136
+ self . super_statement ( statement, loc) ;
137
+ }
138
+ }
139
+ }
0 commit comments