@@ -39,26 +39,26 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
39
39
attr:: contains_name ( tcx. hir_krate_attrs ( ) , sym:: rustc_preserve_ub_checks) ;
40
40
for block in body. basic_blocks . as_mut ( ) {
41
41
for statement in block. statements . iter_mut ( ) {
42
- match statement. kind {
43
- StatementKind :: Assign ( box ( _place, ref mut rvalue) ) => {
44
- if !preserve_ub_checks {
45
- ctx. simplify_ub_check ( rvalue) ;
46
- }
47
- ctx. simplify_bool_cmp ( rvalue) ;
48
- ctx. simplify_ref_deref ( rvalue) ;
49
- ctx. simplify_ptr_aggregate ( rvalue) ;
50
- ctx. simplify_cast ( rvalue) ;
51
- ctx. simplify_repeated_aggregate ( rvalue) ;
52
- ctx. simplify_repeat_once ( rvalue) ;
53
- }
54
- _ => { }
42
+ let StatementKind :: Assign ( box ( .., rvalue) ) = & mut statement. kind else {
43
+ continue ;
44
+ } ;
45
+
46
+ if !preserve_ub_checks {
47
+ ctx. simplify_ub_check ( rvalue) ;
55
48
}
49
+ ctx. simplify_bool_cmp ( rvalue) ;
50
+ ctx. simplify_ref_deref ( rvalue) ;
51
+ ctx. simplify_ptr_aggregate ( rvalue) ;
52
+ ctx. simplify_cast ( rvalue) ;
53
+ ctx. simplify_repeated_aggregate ( rvalue) ;
54
+ ctx. simplify_repeat_once ( rvalue) ;
56
55
}
57
56
58
- ctx. simplify_primitive_clone ( block. terminator . as_mut ( ) . unwrap ( ) , & mut block. statements ) ;
59
- ctx. simplify_intrinsic_assert ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
60
- ctx. simplify_nounwind_call ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
61
- simplify_duplicate_switch_targets ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
57
+ let terminator = block. terminator . as_mut ( ) . unwrap ( ) ;
58
+ ctx. simplify_primitive_clone ( terminator, & mut block. statements ) ;
59
+ ctx. simplify_intrinsic_assert ( terminator) ;
60
+ ctx. simplify_nounwind_call ( terminator) ;
61
+ simplify_duplicate_switch_targets ( terminator) ;
62
62
}
63
63
}
64
64
@@ -105,43 +105,34 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
105
105
106
106
/// Transform boolean comparisons into logical operations.
107
107
fn simplify_bool_cmp ( & self , rvalue : & mut Rvalue < ' tcx > ) {
108
- match rvalue {
109
- Rvalue :: BinaryOp ( op @ ( BinOp :: Eq | BinOp :: Ne ) , box ( a, b) ) => {
110
- let new = match ( op, self . try_eval_bool ( a) , self . try_eval_bool ( b) ) {
111
- // Transform "Eq(a, true)" ==> "a"
112
- ( BinOp :: Eq , _, Some ( true ) ) => Some ( Rvalue :: Use ( a. clone ( ) ) ) ,
108
+ let Rvalue :: BinaryOp ( op @ ( BinOp :: Eq | BinOp :: Ne ) , box ( a, b) ) = & * rvalue else { return } ;
109
+ * rvalue = match ( op, self . try_eval_bool ( a) , self . try_eval_bool ( b) ) {
110
+ // Transform "Eq(a, true)" ==> "a"
111
+ ( BinOp :: Eq , _, Some ( true ) ) => Rvalue :: Use ( a. clone ( ) ) ,
113
112
114
- // Transform "Ne(a, false)" ==> "a"
115
- ( BinOp :: Ne , _, Some ( false ) ) => Some ( Rvalue :: Use ( a. clone ( ) ) ) ,
113
+ // Transform "Ne(a, false)" ==> "a"
114
+ ( BinOp :: Ne , _, Some ( false ) ) => Rvalue :: Use ( a. clone ( ) ) ,
116
115
117
- // Transform "Eq(true, b)" ==> "b"
118
- ( BinOp :: Eq , Some ( true ) , _) => Some ( Rvalue :: Use ( b. clone ( ) ) ) ,
116
+ // Transform "Eq(true, b)" ==> "b"
117
+ ( BinOp :: Eq , Some ( true ) , _) => Rvalue :: Use ( b. clone ( ) ) ,
119
118
120
- // Transform "Ne(false, b)" ==> "b"
121
- ( BinOp :: Ne , Some ( false ) , _) => Some ( Rvalue :: Use ( b. clone ( ) ) ) ,
119
+ // Transform "Ne(false, b)" ==> "b"
120
+ ( BinOp :: Ne , Some ( false ) , _) => Rvalue :: Use ( b. clone ( ) ) ,
122
121
123
- // Transform "Eq(false, b)" ==> "Not(b)"
124
- ( BinOp :: Eq , Some ( false ) , _) => Some ( Rvalue :: UnaryOp ( UnOp :: Not , b. clone ( ) ) ) ,
122
+ // Transform "Eq(false, b)" ==> "Not(b)"
123
+ ( BinOp :: Eq , Some ( false ) , _) => Rvalue :: UnaryOp ( UnOp :: Not , b. clone ( ) ) ,
125
124
126
- // Transform "Ne(true, b)" ==> "Not(b)"
127
- ( BinOp :: Ne , Some ( true ) , _) => Some ( Rvalue :: UnaryOp ( UnOp :: Not , b. clone ( ) ) ) ,
125
+ // Transform "Ne(true, b)" ==> "Not(b)"
126
+ ( BinOp :: Ne , Some ( true ) , _) => Rvalue :: UnaryOp ( UnOp :: Not , b. clone ( ) ) ,
128
127
129
- // Transform "Eq(a, false)" ==> "Not(a)"
130
- ( BinOp :: Eq , _, Some ( false ) ) => Some ( Rvalue :: UnaryOp ( UnOp :: Not , a. clone ( ) ) ) ,
128
+ // Transform "Eq(a, false)" ==> "Not(a)"
129
+ ( BinOp :: Eq , _, Some ( false ) ) => Rvalue :: UnaryOp ( UnOp :: Not , a. clone ( ) ) ,
131
130
132
- // Transform "Ne(a, true)" ==> "Not(a)"
133
- ( BinOp :: Ne , _, Some ( true ) ) => Some ( Rvalue :: UnaryOp ( UnOp :: Not , a. clone ( ) ) ) ,
134
-
135
- _ => None ,
136
- } ;
137
-
138
- if let Some ( new) = new {
139
- * rvalue = new;
140
- }
141
- }
131
+ // Transform "Ne(a, true)" ==> "Not(a)"
132
+ ( BinOp :: Ne , _, Some ( true ) ) => Rvalue :: UnaryOp ( UnOp :: Not , a. clone ( ) ) ,
142
133
143
- _ => { }
144
- }
134
+ _ => return ,
135
+ } ;
145
136
}
146
137
147
138
fn try_eval_bool ( & self , a : & Operand < ' _ > ) -> Option < bool > {
@@ -151,64 +142,58 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
151
142
152
143
/// Transform `&(*a)` ==> `a`.
153
144
fn simplify_ref_deref ( & self , rvalue : & mut Rvalue < ' tcx > ) {
154
- if let Rvalue :: Ref ( _, _, place) | Rvalue :: RawPtr ( _, place) = rvalue {
155
- if let Some ( ( base, ProjectionElem :: Deref ) ) = place. as_ref ( ) . last_projection ( ) {
156
- if rvalue. ty ( self . local_decls , self . tcx ) != base. ty ( self . local_decls , self . tcx ) . ty {
157
- return ;
158
- }
159
-
160
- * rvalue = Rvalue :: Use ( Operand :: Copy ( Place {
161
- local : base. local ,
162
- projection : self . tcx . mk_place_elems ( base. projection ) ,
163
- } ) ) ;
164
- }
145
+ if let Rvalue :: Ref ( _, _, place) | Rvalue :: RawPtr ( _, place) = rvalue
146
+ && let Some ( ( base, ProjectionElem :: Deref ) ) = place. as_ref ( ) . last_projection ( )
147
+ && rvalue. ty ( self . local_decls , self . tcx ) == base. ty ( self . local_decls , self . tcx ) . ty
148
+ {
149
+ * rvalue = Rvalue :: Use ( Operand :: Copy ( Place {
150
+ local : base. local ,
151
+ projection : self . tcx . mk_place_elems ( base. projection ) ,
152
+ } ) ) ;
165
153
}
166
154
}
167
155
168
156
/// Transform `Aggregate(RawPtr, [p, ()])` ==> `Cast(PtrToPtr, p)`.
169
157
fn simplify_ptr_aggregate ( & self , rvalue : & mut Rvalue < ' tcx > ) {
170
158
if let Rvalue :: Aggregate ( box AggregateKind :: RawPtr ( pointee_ty, mutability) , fields) = rvalue
159
+ && let meta_ty = fields. raw [ 1 ] . ty ( self . local_decls , self . tcx )
160
+ && meta_ty. is_unit ( )
171
161
{
172
- let meta_ty = fields. raw [ 1 ] . ty ( self . local_decls , self . tcx ) ;
173
- if meta_ty. is_unit ( ) {
174
- // The mutable borrows we're holding prevent printing `rvalue` here
175
- let mut fields = std:: mem:: take ( fields) ;
176
- let _meta = fields. pop ( ) . unwrap ( ) ;
177
- let data = fields. pop ( ) . unwrap ( ) ;
178
- let ptr_ty = Ty :: new_ptr ( self . tcx , * pointee_ty, * mutability) ;
179
- * rvalue = Rvalue :: Cast ( CastKind :: PtrToPtr , data, ptr_ty) ;
180
- }
162
+ // The mutable borrows we're holding prevent printing `rvalue` here
163
+ let mut fields = std:: mem:: take ( fields) ;
164
+ let _meta = fields. pop ( ) . unwrap ( ) ;
165
+ let data = fields. pop ( ) . unwrap ( ) ;
166
+ let ptr_ty = Ty :: new_ptr ( self . tcx , * pointee_ty, * mutability) ;
167
+ * rvalue = Rvalue :: Cast ( CastKind :: PtrToPtr , data, ptr_ty) ;
181
168
}
182
169
}
183
170
184
171
fn simplify_ub_check ( & self , rvalue : & mut Rvalue < ' tcx > ) {
185
- if let Rvalue :: NullaryOp ( NullOp :: UbChecks , _) = * rvalue {
186
- let const_ = Const :: from_bool ( self . tcx , self . tcx . sess . ub_checks ( ) ) ;
187
- let constant = ConstOperand { span : DUMMY_SP , const_ , user_ty : None } ;
188
- * rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( constant ) ) ) ;
189
- }
172
+ let Rvalue :: NullaryOp ( NullOp :: UbChecks , _) = * rvalue else { return } ;
173
+
174
+ let const_ = Const :: from_bool ( self . tcx , self . tcx . sess . ub_checks ( ) ) ;
175
+ let constant = ConstOperand { span : DUMMY_SP , const_ , user_ty : None } ;
176
+ * rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( constant ) ) ) ;
190
177
}
191
178
192
179
fn simplify_cast ( & self , rvalue : & mut Rvalue < ' tcx > ) {
193
- if let Rvalue :: Cast ( kind, operand, cast_ty) = rvalue {
194
- let operand_ty = operand. ty ( self . local_decls , self . tcx ) ;
195
- if operand_ty == * cast_ty {
196
- * rvalue = Rvalue :: Use ( operand. clone ( ) ) ;
197
- } else if * kind == CastKind :: Transmute {
198
- // Transmuting an integer to another integer is just a signedness cast
199
- if let ( ty:: Int ( int) , ty:: Uint ( uint) ) | ( ty:: Uint ( uint) , ty:: Int ( int) ) =
200
- ( operand_ty. kind ( ) , cast_ty. kind ( ) )
201
- && int. bit_width ( ) == uint. bit_width ( )
202
- {
203
- // The width check isn't strictly necessary, as different widths
204
- // are UB and thus we'd be allowed to turn it into a cast anyway.
205
- // But let's keep the UB around for codegen to exploit later.
206
- // (If `CastKind::Transmute` ever becomes *not* UB for mismatched sizes,
207
- // then the width check is necessary for big-endian correctness.)
208
- * kind = CastKind :: IntToInt ;
209
- return ;
210
- }
211
- }
180
+ let Rvalue :: Cast ( kind, operand, cast_ty) = rvalue else { return } ;
181
+
182
+ let operand_ty = operand. ty ( self . local_decls , self . tcx ) ;
183
+ if operand_ty == * cast_ty {
184
+ * rvalue = Rvalue :: Use ( operand. clone ( ) ) ;
185
+ } else if * kind == CastKind :: Transmute
186
+ // Transmuting an integer to another integer is just a signedness cast
187
+ && let ( ty:: Int ( int) , ty:: Uint ( uint) ) | ( ty:: Uint ( uint) , ty:: Int ( int) ) =
188
+ ( operand_ty. kind ( ) , cast_ty. kind ( ) )
189
+ && int. bit_width ( ) == uint. bit_width ( )
190
+ {
191
+ // The width check isn't strictly necessary, as different widths
192
+ // are UB and thus we'd be allowed to turn it into a cast anyway.
193
+ // But let's keep the UB around for codegen to exploit later.
194
+ // (If `CastKind::Transmute` ever becomes *not* UB for mismatched sizes,
195
+ // then the width check is necessary for big-endian correctness.)
196
+ * kind = CastKind :: IntToInt ;
212
197
}
213
198
}
214
199
@@ -277,7 +262,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
277
262
}
278
263
279
264
fn simplify_nounwind_call ( & self , terminator : & mut Terminator < ' tcx > ) {
280
- let TerminatorKind :: Call { func, unwind, .. } = & mut terminator. kind else {
265
+ let TerminatorKind :: Call { ref func, ref mut unwind, .. } = terminator. kind else {
281
266
return ;
282
267
} ;
283
268
@@ -290,7 +275,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
290
275
ty:: FnDef ( ..) => body_ty. fn_sig ( self . tcx ) . abi ( ) ,
291
276
ty:: Closure ( ..) => ExternAbi :: RustCall ,
292
277
ty:: Coroutine ( ..) => ExternAbi :: Rust ,
293
- _ => bug ! ( "unexpected body ty: {:?}" , body_ty ) ,
278
+ _ => bug ! ( "unexpected body ty: {body_ty :?}" ) ,
294
279
} ;
295
280
296
281
if !layout:: fn_can_unwind ( self . tcx , Some ( def_id) , body_abi) {
@@ -299,23 +284,20 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
299
284
}
300
285
301
286
fn simplify_intrinsic_assert ( & self , terminator : & mut Terminator < ' tcx > ) {
302
- let TerminatorKind :: Call { func, target, .. } = & mut terminator. kind else {
303
- return ;
304
- } ;
305
- let Some ( target_block) = target else {
287
+ let TerminatorKind :: Call { ref func, target : ref mut target @ Some ( target_block) , .. } =
288
+ terminator. kind
289
+ else {
306
290
return ;
307
291
} ;
308
292
let func_ty = func. ty ( self . local_decls , self . tcx ) ;
309
293
let Some ( ( intrinsic_name, args) ) = resolve_rust_intrinsic ( self . tcx , func_ty) else {
310
294
return ;
311
295
} ;
312
296
// The intrinsics we are interested in have one generic parameter
313
- if args. is_empty ( ) {
314
- return ;
315
- }
297
+ let [ arg, ..] = args[ ..] else { return } ;
316
298
317
299
let known_is_valid =
318
- intrinsic_assert_panics ( self . tcx , self . typing_env , args [ 0 ] , intrinsic_name) ;
300
+ intrinsic_assert_panics ( self . tcx , self . typing_env , arg , intrinsic_name) ;
319
301
match known_is_valid {
320
302
// We don't know the layout or it's not validity assertion at all, don't touch it
321
303
None => { }
@@ -325,7 +307,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
325
307
}
326
308
Some ( false ) => {
327
309
// If we know the assert does not panic, turn the call into a Goto
328
- terminator. kind = TerminatorKind :: Goto { target : * target_block } ;
310
+ terminator. kind = TerminatorKind :: Goto { target : target_block } ;
329
311
}
330
312
}
331
313
}
@@ -346,9 +328,7 @@ fn resolve_rust_intrinsic<'tcx>(
346
328
tcx : TyCtxt < ' tcx > ,
347
329
func_ty : Ty < ' tcx > ,
348
330
) -> Option < ( Symbol , GenericArgsRef < ' tcx > ) > {
349
- if let ty:: FnDef ( def_id, args) = * func_ty. kind ( ) {
350
- let intrinsic = tcx. intrinsic ( def_id) ?;
351
- return Some ( ( intrinsic. name , args) ) ;
352
- }
353
- None
331
+ let ty:: FnDef ( def_id, args) = * func_ty. kind ( ) else { return None } ;
332
+ let intrinsic = tcx. intrinsic ( def_id) ?;
333
+ Some ( ( intrinsic. name , args) )
354
334
}
0 commit comments