@@ -6,7 +6,8 @@ use rustc_middle::mir::{
66 BinOp , Body , Constant , ConstantKind , LocalDecls , Operand , Place , ProjectionElem , Rvalue ,
77 SourceInfo , Statement , StatementKind , Terminator , TerminatorKind , UnOp ,
88} ;
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 } ;
1011
1112pub struct InstCombine ;
1213
@@ -16,7 +17,11 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
1617 }
1718
1819 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+ } ;
2025 for block in body. basic_blocks . as_mut ( ) {
2126 for statement in block. statements . iter_mut ( ) {
2227 match statement. kind {
@@ -33,13 +38,18 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
3338 & mut block. terminator . as_mut ( ) . unwrap ( ) ,
3439 & mut block. statements ,
3540 ) ;
41+ ctx. combine_intrinsic_assert (
42+ & mut block. terminator . as_mut ( ) . unwrap ( ) ,
43+ & mut block. statements ,
44+ ) ;
3645 }
3746 }
3847}
3948
4049struct InstCombineContext < ' tcx , ' a > {
4150 tcx : TyCtxt < ' tcx > ,
4251 local_decls : & ' a LocalDecls < ' tcx > ,
52+ param_env : ParamEnv < ' tcx > ,
4353}
4454
4555impl < ' tcx > InstCombineContext < ' tcx , ' _ > {
@@ -200,4 +210,69 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
200210 } ) ;
201211 terminator. kind = TerminatorKind :: Goto { target : destination_block } ;
202212 }
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
203278}
0 commit comments