@@ -56,7 +56,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
5656
5757 let terminator = block. terminator . as_mut ( ) . unwrap ( ) ;
5858 ctx. simplify_primitive_clone ( terminator, & mut block. statements ) ;
59- ctx. simplify_align_of_slice_val ( terminator, & mut block. statements ) ;
59+ ctx. simplify_size_or_align_of_val ( terminator, & mut block. statements ) ;
6060 ctx. simplify_intrinsic_assert ( terminator) ;
6161 ctx. simplify_nounwind_call ( terminator) ;
6262 simplify_duplicate_switch_targets ( terminator) ;
@@ -246,13 +246,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
246246 terminator. kind = TerminatorKind :: Goto { target : * destination_block } ;
247247 }
248248
249- // Convert `align_of_val::<[T]>(ptr)` to `align_of::<T>()`, since the
250- // alignment of a slice doesn't actually depend on metadata at all
251- // and the element type is always `Sized`.
252- //
253- // This is here so it can run after inlining, where it's more useful.
254- // (LowerIntrinsics is done in cleanup, before the optimization passes.)
255- fn simplify_align_of_slice_val (
249+ /// Simplify `size_of_val` and `align_of_val` if we don't actually need
250+ /// to look at the value in order to calculate the result:
251+ /// - For `Sized` types we can always do this for both,
252+ /// - For `align_of_val::<[T]>` we can return `align_of::<T>()`, since it
253+ /// doesn't depend on the slice's length and the elements are sized.
254+ ///
255+ /// This is here so it can run after inlining, where it's more useful.
256+ /// (LowerIntrinsics is done in cleanup, before the optimization passes.)
257+ ///
258+ /// Note that we intentionally just produce the lang item constants so this
259+ /// works on generic types and avoids any risk of layout calculation cycles.
260+ fn simplify_size_or_align_of_val (
256261 & self ,
257262 terminator : & mut Terminator < ' tcx > ,
258263 statements : & mut Vec < Statement < ' tcx > > ,
@@ -263,19 +268,35 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
263268 } = & terminator. kind
264269 && args. len ( ) == 1
265270 && let Some ( ( fn_def_id, generics) ) = func. const_fn_def ( )
266- && self . tcx . is_intrinsic ( fn_def_id, sym:: align_of_val)
267- && let ty:: Slice ( elem_ty) = * generics. type_at ( 0 ) . kind ( )
268271 {
269- let align_def_id = self . tcx . require_lang_item ( LangItem :: AlignOf , source_info. span ) ;
270- let align_const = Operand :: unevaluated_constant (
272+ let lang_item = if self . tcx . is_intrinsic ( fn_def_id, sym:: size_of_val) {
273+ LangItem :: SizeOf
274+ } else if self . tcx . is_intrinsic ( fn_def_id, sym:: align_of_val) {
275+ LangItem :: AlignOf
276+ } else {
277+ return ;
278+ } ;
279+ let generic_ty = generics. type_at ( 0 ) ;
280+ let ty = if generic_ty. is_sized ( self . tcx , self . typing_env ) {
281+ generic_ty
282+ } else if let LangItem :: AlignOf = lang_item
283+ && let ty:: Slice ( elem_ty) = * generic_ty. kind ( )
284+ {
285+ elem_ty
286+ } else {
287+ return ;
288+ } ;
289+
290+ let const_def_id = self . tcx . require_lang_item ( lang_item, source_info. span ) ;
291+ let const_op = Operand :: unevaluated_constant (
271292 self . tcx ,
272- align_def_id ,
273- & [ elem_ty . into ( ) ] ,
293+ const_def_id ,
294+ & [ ty . into ( ) ] ,
274295 source_info. span ,
275296 ) ;
276297 statements. push ( Statement :: new (
277298 source_info,
278- StatementKind :: Assign ( Box :: new ( ( * destination, Rvalue :: Use ( align_const ) ) ) ) ,
299+ StatementKind :: Assign ( Box :: new ( ( * destination, Rvalue :: Use ( const_op ) ) ) ) ,
279300 ) ) ;
280301 terminator. kind = TerminatorKind :: Goto { target : * destination_block } ;
281302 }
0 commit comments