11//! Performs various peephole optimizations.
22
3- use rustc_abi:: ExternAbi ;
3+ use rustc_abi:: { ExternAbi , Integer } ;
44use rustc_hir:: { LangItem , find_attr} ;
5+ use rustc_index:: IndexVec ;
56use rustc_middle:: bug;
67use rustc_middle:: mir:: visit:: MutVisitor ;
78use rustc_middle:: mir:: * ;
8- use rustc_middle:: ty:: layout:: ValidityRequirement ;
9+ use rustc_middle:: ty:: layout:: { IntegerExt , ValidityRequirement } ;
910use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , layout} ;
1011use rustc_span:: { Symbol , sym} ;
1112
@@ -33,10 +34,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
3334 if !preserve_ub_checks {
3435 SimplifyUbCheck { tcx } . visit_body ( body) ;
3536 }
36- let ctx = InstSimplifyContext {
37+ let mut ctx = InstSimplifyContext {
3738 tcx,
38- local_decls : & body. local_decls ,
3939 typing_env : body. typing_env ( tcx) ,
40+ local_decls : & mut body. local_decls ,
4041 } ;
4142 for block in body. basic_blocks . as_mut ( ) {
4243 for statement in block. statements . iter_mut ( ) {
@@ -55,6 +56,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
5556 let terminator = block. terminator . as_mut ( ) . unwrap ( ) ;
5657 ctx. simplify_primitive_clone ( terminator, & mut block. statements ) ;
5758 ctx. simplify_size_or_align_of_val ( terminator, & mut block. statements ) ;
59+ ctx. simplify_raw_eq ( terminator, & mut block. statements ) ;
5860 ctx. simplify_intrinsic_assert ( terminator) ;
5961 ctx. simplify_nounwind_call ( terminator) ;
6062 simplify_duplicate_switch_targets ( terminator) ;
@@ -68,7 +70,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
6870
6971struct InstSimplifyContext < ' a , ' tcx > {
7072 tcx : TyCtxt < ' tcx > ,
71- local_decls : & ' a LocalDecls < ' tcx > ,
73+ local_decls : & ' a mut IndexVec < Local , LocalDecl < ' tcx > > ,
7274 typing_env : ty:: TypingEnv < ' tcx > ,
7375}
7476
@@ -318,6 +320,63 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
318320 }
319321 }
320322
323+ /// Simplify `raw_eq` intrinsic calls to `Eq` when the type has the size of a primitive.
324+ ///
325+ /// For example, replace `raw_eq::<[u8; 4]>(a, b)` with `Eq(Transmute(a), Transmute(b))`.
326+ fn simplify_raw_eq (
327+ & mut self ,
328+ terminator : & mut Terminator < ' tcx > ,
329+ statements : & mut Vec < Statement < ' tcx > > ,
330+ ) {
331+ let tcx = self . tcx ;
332+ let source_info = terminator. source_info ;
333+ let span = source_info. span ;
334+ if let TerminatorKind :: Call {
335+ func, args, destination, target : Some ( destination_block) , ..
336+ } = & terminator. kind
337+ && args. len ( ) == 2
338+ && let Some ( ( fn_def_id, generics) ) = func. const_fn_def ( )
339+ && tcx. is_intrinsic ( fn_def_id, sym:: raw_eq)
340+ && let generic_ty = generics. type_at ( 0 )
341+ && let Ok ( layout) = tcx. layout_of ( self . typing_env . as_query_input ( generic_ty) )
342+ && let Ok ( integer) = Integer :: from_size ( layout. size )
343+ {
344+ let ref_ty = Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , generic_ty) ;
345+ let uint_ty = integer. to_ty ( tcx, false ) ;
346+
347+ let mut transmute_operand = |op : & Operand < ' tcx > | -> Operand < ' tcx > {
348+ let ref_local = self . local_decls . push ( LocalDecl :: new ( ref_ty, span) ) ;
349+ statements. push ( Statement :: new (
350+ source_info,
351+ StatementKind :: Assign ( Box :: new ( (
352+ Place :: from ( ref_local) ,
353+ Rvalue :: Use ( op. clone ( ) , WithRetag :: Yes ) ,
354+ ) ) ) ,
355+ ) ) ;
356+ let place = Place :: from ( ref_local) . project_deeper ( & [ ProjectionElem :: Deref ] , tcx) ;
357+ let int_local = self . local_decls . push ( LocalDecl :: new ( uint_ty, span) ) ;
358+ statements. push ( Statement :: new (
359+ source_info,
360+ StatementKind :: Assign ( Box :: new ( (
361+ Place :: from ( int_local) ,
362+ Rvalue :: Cast ( CastKind :: Transmute , Operand :: Copy ( place) , uint_ty) ,
363+ ) ) ) ,
364+ ) ) ;
365+ Operand :: Move ( Place :: from ( int_local) )
366+ } ;
367+ let lhs_op = transmute_operand ( & args[ 0 ] . node ) ;
368+ let rhs_op = transmute_operand ( & args[ 1 ] . node ) ;
369+ statements. push ( Statement :: new (
370+ source_info,
371+ StatementKind :: Assign ( Box :: new ( (
372+ * destination,
373+ Rvalue :: BinaryOp ( BinOp :: Eq , Box :: new ( ( lhs_op, rhs_op) ) ) ,
374+ ) ) ) ,
375+ ) ) ;
376+ terminator. kind = TerminatorKind :: Goto { target : * destination_block } ;
377+ }
378+ }
379+
321380 fn simplify_nounwind_call ( & self , terminator : & mut Terminator < ' tcx > ) {
322381 let TerminatorKind :: Call { ref func, ref mut unwind, .. } = terminator. kind else {
323382 return ;
0 commit comments