@@ -6,7 +6,8 @@ use rustc_middle::mir::{
6
6
BinOp , Body , Constant , ConstantKind , LocalDecls , Operand , Place , ProjectionElem , Rvalue ,
7
7
SourceInfo , Statement , StatementKind , Terminator , TerminatorKind , UnOp ,
8
8
} ;
9
- use rustc_middle:: ty:: { self , TyCtxt } ;
9
+ use rustc_middle:: ty:: { self , layout:: TyAndLayout , ParamEnv , SubstsRef , Ty , TyCtxt } ;
10
+ use rustc_span:: symbol:: { sym, Symbol } ;
10
11
11
12
pub struct InstCombine ;
12
13
@@ -16,7 +17,11 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
16
17
}
17
18
18
19
fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
19
- let ctx = InstCombineContext { tcx, local_decls : & body. local_decls } ;
20
+ let ctx = InstCombineContext {
21
+ tcx,
22
+ local_decls : & body. local_decls ,
23
+ param_env : tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ,
24
+ } ;
20
25
for block in body. basic_blocks . as_mut ( ) {
21
26
for statement in block. statements . iter_mut ( ) {
22
27
match statement. kind {
@@ -33,13 +38,18 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
33
38
& mut block. terminator . as_mut ( ) . unwrap ( ) ,
34
39
& mut block. statements ,
35
40
) ;
41
+ ctx. combine_intrinsic_assert (
42
+ & mut block. terminator . as_mut ( ) . unwrap ( ) ,
43
+ & mut block. statements ,
44
+ ) ;
36
45
}
37
46
}
38
47
}
39
48
40
49
struct InstCombineContext < ' tcx , ' a > {
41
50
tcx : TyCtxt < ' tcx > ,
42
51
local_decls : & ' a LocalDecls < ' tcx > ,
52
+ param_env : ParamEnv < ' tcx > ,
43
53
}
44
54
45
55
impl < ' tcx > InstCombineContext < ' tcx , ' _ > {
@@ -200,4 +210,69 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
200
210
} ) ;
201
211
terminator. kind = TerminatorKind :: Goto { target : destination_block } ;
202
212
}
213
+
214
+ fn combine_intrinsic_assert (
215
+ & self ,
216
+ terminator : & mut Terminator < ' tcx > ,
217
+ _statements : & mut Vec < Statement < ' tcx > > ,
218
+ ) {
219
+ let TerminatorKind :: Call { func, target, .. } = & mut terminator. kind else { return ; } ;
220
+ let Some ( target_block) = target else { return ; } ;
221
+ let func_ty = func. ty ( self . local_decls , self . tcx ) ;
222
+ let Some ( ( intrinsic_name, substs) ) = resolve_rust_intrinsic ( self . tcx , func_ty) else {
223
+ return ;
224
+ } ;
225
+ // The intrinsics we are interested in have one generic parameter
226
+ if substs. is_empty ( ) {
227
+ return ;
228
+ }
229
+ let ty = substs. type_at ( 0 ) ;
230
+
231
+ // Check this is a foldable intrinsic before we query the layout of our generic parameter
232
+ let Some ( assert_panics) = intrinsic_assert_panics ( intrinsic_name) else { return ; } ;
233
+ let Ok ( layout) = self . tcx . layout_of ( self . param_env . and ( ty) ) else { return ; } ;
234
+ if assert_panics ( self . tcx , layout) {
235
+ // If we know the assert panics, indicate to later opts that the call diverges
236
+ * target = None ;
237
+ } else {
238
+ // If we know the assert does not panic, turn the call into a Goto
239
+ terminator. kind = TerminatorKind :: Goto { target : * target_block } ;
240
+ }
241
+ }
242
+ }
243
+
244
+ fn intrinsic_assert_panics < ' tcx > (
245
+ intrinsic_name : Symbol ,
246
+ ) -> Option < fn ( TyCtxt < ' tcx > , TyAndLayout < ' tcx > ) -> bool > {
247
+ fn inhabited_predicate < ' tcx > ( _tcx : TyCtxt < ' tcx > , layout : TyAndLayout < ' tcx > ) -> bool {
248
+ layout. abi . is_uninhabited ( )
249
+ }
250
+ fn zero_valid_predicate < ' tcx > ( tcx : TyCtxt < ' tcx > , layout : TyAndLayout < ' tcx > ) -> bool {
251
+ !tcx. permits_zero_init ( layout)
252
+ }
253
+ fn mem_uninitialized_valid_predicate < ' tcx > (
254
+ tcx : TyCtxt < ' tcx > ,
255
+ layout : TyAndLayout < ' tcx > ,
256
+ ) -> bool {
257
+ !tcx. permits_uninit_init ( layout)
258
+ }
259
+
260
+ match intrinsic_name {
261
+ sym:: assert_inhabited => Some ( inhabited_predicate) ,
262
+ sym:: assert_zero_valid => Some ( zero_valid_predicate) ,
263
+ sym:: assert_mem_uninitialized_valid => Some ( mem_uninitialized_valid_predicate) ,
264
+ _ => None ,
265
+ }
266
+ }
267
+
268
+ fn resolve_rust_intrinsic < ' tcx > (
269
+ tcx : TyCtxt < ' tcx > ,
270
+ func_ty : Ty < ' tcx > ,
271
+ ) -> Option < ( Symbol , SubstsRef < ' tcx > ) > {
272
+ if let ty:: FnDef ( def_id, substs) = * func_ty. kind ( ) {
273
+ if tcx. is_intrinsic ( def_id) {
274
+ return Some ( ( tcx. item_name ( def_id) , substs) ) ;
275
+ }
276
+ }
277
+ None
203
278
}
0 commit comments