@@ -1366,110 +1366,112 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
13661366 return self . new_opaque ( ) ;
13671367 }
13681368
1369- let mut was_updated = false ;
1370-
1371- // Transmuting `*const T` <=> `*mut T` is just a pointer cast,
1372- // which we might be able to merge with other ones later.
1373- if let Transmute = kind
1374- && let ty:: RawPtr ( from_pointee, _) = from. kind ( )
1375- && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1376- && from_pointee == to_pointee
1377- {
1378- * kind = PtrToPtr ;
1379- was_updated = true ;
1380- }
1381-
1382- // If a cast just casts away the metadata again, then we can get it by
1383- // casting the original thin pointer passed to `from_raw_parts`
1384- if let PtrToPtr = kind
1385- && let Value :: Aggregate ( AggregateTy :: RawPtr { data_pointer_ty, .. } , _, fields) =
1386- self . get ( value)
1387- && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1388- && to_pointee. is_sized ( self . tcx , self . typing_env ( ) )
1389- {
1390- from = * data_pointer_ty;
1391- value = fields[ 0 ] ;
1392- was_updated = true ;
1393- if * data_pointer_ty == to {
1394- return Some ( fields[ 0 ] ) ;
1369+ let mut was_ever_updated = false ;
1370+ loop {
1371+ let mut was_updated_this_iteration = false ;
1372+
1373+ // Transmuting `*const T` <=> `*mut T` is just a pointer cast,
1374+ // which we might be able to merge with other ones later.
1375+ if let Transmute = kind
1376+ && let ty:: RawPtr ( from_pointee, _) = from. kind ( )
1377+ && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1378+ && from_pointee == to_pointee
1379+ {
1380+ * kind = PtrToPtr ;
1381+ was_updated_this_iteration = true ;
13951382 }
1396- }
13971383
1398- // PtrToPtr-then-PtrToPtr can skip the intermediate step
1399- if let PtrToPtr = kind
1400- && let Value :: Cast { kind : inner_kind, value : inner_value, from : inner_from, to : _ } =
1401- * self . get ( value)
1402- && let PtrToPtr = inner_kind
1403- {
1404- from = inner_from;
1405- value = inner_value;
1406- was_updated = true ;
1407- if inner_from == to {
1408- return Some ( inner_value) ;
1384+ // If a cast just casts away the metadata again, then we can get it by
1385+ // casting the original thin pointer passed to `from_raw_parts`
1386+ if let PtrToPtr = kind
1387+ && let Value :: Aggregate ( AggregateTy :: RawPtr { data_pointer_ty, .. } , _, fields) =
1388+ self . get ( value)
1389+ && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1390+ && to_pointee. is_sized ( self . tcx , self . typing_env ( ) )
1391+ {
1392+ from = * data_pointer_ty;
1393+ value = fields[ 0 ] ;
1394+ was_updated_this_iteration = true ;
1395+ if * data_pointer_ty == to {
1396+ return Some ( fields[ 0 ] ) ;
1397+ }
14091398 }
1410- }
14111399
1412- // Aggregate-then-Transmute can just transmute the original field value,
1413- // so long as the bytes of a value from only from a single field.
1414- if let Transmute = kind
1415- && let Value :: Aggregate (
1416- AggregateTy :: Def ( aggregate_did, aggregate_args) ,
1417- variant_idx,
1418- field_values,
1419- ) = self . get ( value)
1420- && let aggregate_ty =
1421- self . tcx . type_of ( aggregate_did) . instantiate ( self . tcx , aggregate_args)
1422- && let Some ( ( field_idx, field_ty) ) =
1423- self . value_is_all_in_one_field ( aggregate_ty, * variant_idx)
1424- {
1425- from = field_ty;
1426- value = field_values[ field_idx. as_usize ( ) ] ;
1427- was_updated = true ;
1428- if field_ty == to {
1429- return Some ( value) ;
1400+ // Aggregate-then-Transmute can just transmute the original field value,
1401+ // so long as the bytes of a value from only from a single field.
1402+ if let Transmute = kind
1403+ && let Value :: Aggregate (
1404+ AggregateTy :: Def ( aggregate_did, aggregate_args) ,
1405+ variant_idx,
1406+ field_values,
1407+ ) = self . get ( value)
1408+ && let aggregate_ty =
1409+ self . tcx . type_of ( aggregate_did) . instantiate ( self . tcx , aggregate_args)
1410+ && let Some ( ( field_idx, field_ty) ) =
1411+ self . value_is_all_in_one_field ( aggregate_ty, * variant_idx)
1412+ {
1413+ from = field_ty;
1414+ value = field_values[ field_idx. as_usize ( ) ] ;
1415+ was_updated_this_iteration = true ;
1416+ if field_ty == to {
1417+ return Some ( value) ;
1418+ }
14301419 }
1431- }
14321420
1433- // PtrToPtr-then-Transmute can just transmute the original, so long as the
1434- // PtrToPtr didn't change metadata (and thus the size of the pointer)
1435- if let Transmute = kind
1436- && let Value :: Cast {
1437- kind : PtrToPtr ,
1421+ // Various cast-then-cast cases can be simplified.
1422+ if let Value :: Cast {
1423+ kind : inner_kind,
14381424 value : inner_value,
14391425 from : inner_from,
14401426 to : inner_to,
14411427 } = * self . get ( value)
1442- && self . pointers_have_same_metadata ( inner_from, inner_to)
1443- {
1444- from = inner_from;
1445- value = inner_value;
1446- was_updated = true ;
1447- if inner_from == to {
1448- return Some ( inner_value) ;
1428+ {
1429+ let new_kind = match ( inner_kind, * kind) {
1430+ // Even if there's a narrowing cast in here that's fine, because
1431+ // things like `*mut [i32] -> *mut i32 -> *const i32` and
1432+ // `*mut [i32] -> *const [i32] -> *const i32` can skip the middle in MIR.
1433+ ( PtrToPtr , PtrToPtr ) => Some ( PtrToPtr ) ,
1434+ // PtrToPtr-then-Transmute is fine so long as the pointer cast is identity:
1435+ // `*const T -> *mut T -> NonNull<T>` is fine, but we need to check for narrowing
1436+ // to skip things like `*const [i32] -> *const i32 -> NonNull<T>`.
1437+ ( PtrToPtr , Transmute )
1438+ if self . pointers_have_same_metadata ( inner_from, inner_to) =>
1439+ {
1440+ Some ( Transmute )
1441+ }
1442+ // Similarly, for Transmute-then-PtrToPtr. Note that we need to check different
1443+ // variables for their metadata, and thus this can't merge with the previous arm.
1444+ ( Transmute , PtrToPtr ) if self . pointers_have_same_metadata ( from, to) => {
1445+ Some ( Transmute )
1446+ }
1447+ // If would be legal to always do this, but we don't want to hide information
1448+ // from the backend that it'd otherwise be able to use for optimizations.
1449+ ( Transmute , Transmute )
1450+ if !self . type_may_have_niche_of_interest_to_backend ( inner_to) =>
1451+ {
1452+ Some ( Transmute )
1453+ }
1454+ _ => None ,
1455+ } ;
1456+ if let Some ( new_kind) = new_kind {
1457+ * kind = new_kind;
1458+ from = inner_from;
1459+ value = inner_value;
1460+ was_updated_this_iteration = true ;
1461+ if inner_from == to {
1462+ return Some ( inner_value) ;
1463+ }
1464+ }
14491465 }
1450- }
14511466
1452- // Transmute-then-PtrToPtr can just transmute the original, so long as the
1453- // PtrToPtr won't change metadata (and thus the size of the pointer)
1454- if let PtrToPtr = kind
1455- && let Value :: Cast {
1456- kind : Transmute ,
1457- value : inner_value,
1458- from : inner_from,
1459- to : _inner_to,
1460- } = * self . get ( value)
1461- && self . pointers_have_same_metadata ( from, to)
1462- {
1463- * kind = Transmute ;
1464- from = inner_from;
1465- value = inner_value;
1466- was_updated = true ;
1467- if inner_from == to {
1468- return Some ( inner_value) ;
1467+ if was_updated_this_iteration {
1468+ was_ever_updated = true ;
1469+ } else {
1470+ break ;
14691471 }
14701472 }
14711473
1472- if was_updated && let Some ( op) = self . try_as_operand ( value, location) {
1474+ if was_ever_updated && let Some ( op) = self . try_as_operand ( value, location) {
14731475 * operand = op;
14741476 }
14751477
@@ -1492,6 +1494,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
14921494 }
14931495 }
14941496
1497+ /// Returns `false` if we know for sure that this type has no interesting niche,
1498+ /// and thus we can skip transmuting through it without worrying.
1499+ ///
1500+ /// The backend will emit `assume`s when transmuting between types with niches,
1501+ /// so we want to preserve `i32 -> char -> u32` so that that data is around,
1502+ /// but it's fine to skip whole-range-is-value steps like `A -> u32 -> B`.
1503+ fn type_may_have_niche_of_interest_to_backend ( & self , ty : Ty < ' tcx > ) -> bool {
1504+ let Ok ( layout) = self . ecx . layout_of ( ty) else {
1505+ // If it's too generic or something, then assume it might be interesting later.
1506+ return true ;
1507+ } ;
1508+
1509+ match layout. backend_repr {
1510+ BackendRepr :: Uninhabited => true ,
1511+ BackendRepr :: Scalar ( a) => !a. is_always_valid ( & self . ecx ) ,
1512+ BackendRepr :: ScalarPair ( a, b) => {
1513+ !a. is_always_valid ( & self . ecx ) || !b. is_always_valid ( & self . ecx )
1514+ }
1515+ BackendRepr :: Vector { .. } | BackendRepr :: Memory { .. } => false ,
1516+ }
1517+ }
1518+
14951519 fn value_is_all_in_one_field (
14961520 & self ,
14971521 ty : Ty < ' tcx > ,
0 commit comments