Allow more MIR SROA

This commit is contained in:
Scott McMurray 2025-07-27 13:21:06 -07:00
parent edc3841c5d
commit 47bfa846f3
3 changed files with 40 additions and 68 deletions

View file

@ -1,4 +1,4 @@
use rustc_abi::{FIRST_VARIANT, FieldIdx};
use rustc_abi::FieldIdx;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_hir::LangItem;
use rustc_index::IndexVec;
@ -32,7 +32,7 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
let typing_env = body.typing_env(tcx);
loop {
debug!(?excluded);
let escaping = escaping_locals(tcx, typing_env, &excluded, body);
let escaping = escaping_locals(tcx, &excluded, body);
debug!(?escaping);
let replacements = compute_flattening(tcx, typing_env, body, escaping);
debug!(?replacements);
@ -64,7 +64,6 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
/// client code.
fn escaping_locals<'tcx>(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
excluded: &DenseBitSet<Local>,
body: &Body<'tcx>,
) -> DenseBitSet<Local> {
@ -72,31 +71,12 @@ fn escaping_locals<'tcx>(
if ty.is_union() || ty.is_enum() {
return true;
}
if let ty::Adt(def, _args) = ty.kind() {
if def.repr().simd() {
// Exclude #[repr(simd)] types so that they are not de-optimized into an array
return true;
}
if tcx.is_lang_item(def.did(), LangItem::DynMetadata) {
// codegen wants to see the `DynMetadata<T>`,
// not the inner reference-to-opaque-type.
return true;
}
// We already excluded unions and enums, so this ADT must have one variant
let variant = def.variant(FIRST_VARIANT);
if variant.fields.len() > 1 {
// If this has more than one field, it cannot be a wrapper that only provides a
// niche, so we do not want to automatically exclude it.
return false;
}
let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else {
// We can't get the layout
return true;
};
if layout.layout.largest_niche().is_some() {
// This type has a niche
return true;
}
if let ty::Adt(def, _args) = ty.kind()
&& tcx.is_lang_item(def.did(), LangItem::DynMetadata)
{
// codegen wants to see the `DynMetadata<T>`,
// not the inner reference-to-opaque-type.
return true;
}
// Default for non-ADTs
false

View file

@ -64,9 +64,8 @@
+ let mut _45: &mut std::future::Ready<()>;
+ let mut _46: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
+ let mut _47: std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
+ let mut _48: &mut &mut std::future::Ready<()>;
+ let mut _47: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ }
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
@ -76,15 +75,15 @@
+ }
+ }
+ scope 19 (inlined Option::<()>::take) {
+ let mut _49: std::option::Option<()>;
+ let mut _48: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _50: isize;
+ let mut _51: !;
+ let mut _49: isize;
+ let mut _50: !;
+ scope 23 {
+ }
+ }
@ -229,28 +228,25 @@
+ StorageDead(_24);
+ StorageLive(_45);
+ StorageLive(_46);
+ StorageLive(_51);
+ StorageLive(_50);
+ StorageLive(_42);
+ StorageLive(_43);
+ StorageLive(_44);
+ _46 = &mut _19;
+ StorageLive(_47);
+ StorageLive(_48);
+ _48 = &mut (_19.0: &mut std::future::Ready<()>);
+ _47 = &mut (_19.0: &mut std::future::Ready<()>);
+ _45 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_48);
+ _47 = Pin::<&mut std::future::Ready<()>> { pointer: copy _45 };
+ StorageDead(_47);
+ _44 = &mut ((*_45).0: std::option::Option<()>);
+ StorageLive(_49);
+ _49 = Option::<()>::None;
+ StorageLive(_48);
+ _48 = Option::<()>::None;
+ _43 = copy ((*_45).0: std::option::Option<()>);
+ ((*_45).0: std::option::Option<()>) = copy _49;
+ StorageDead(_49);
+ ((*_45).0: std::option::Option<()>) = copy _48;
+ StorageDead(_48);
+ StorageDead(_44);
+ StorageLive(_50);
+ _50 = discriminant(_43);
+ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5];
+ StorageLive(_49);
+ _49 = discriminant(_43);
+ switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5];
}
+
+ bb5: {
@ -313,16 +309,16 @@
+ }
+
+ bb11: {
+ _51 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ _50 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ }
+
+ bb12: {
+ _42 = move ((_43 as Some).0: ());
+ StorageDead(_50);
+ StorageDead(_49);
+ StorageDead(_43);
+ _18 = Poll::<()>::Ready(move _42);
+ StorageDead(_42);
+ StorageDead(_51);
+ StorageDead(_50);
+ StorageDead(_46);
+ StorageDead(_45);
+ StorageDead(_22);

View file

@ -66,9 +66,8 @@
+ let mut _47: &mut std::future::Ready<()>;
+ let mut _48: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
+ let mut _49: std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
+ let mut _50: &mut &mut std::future::Ready<()>;
+ let mut _49: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ }
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
@ -78,15 +77,15 @@
+ }
+ }
+ scope 19 (inlined Option::<()>::take) {
+ let mut _51: std::option::Option<()>;
+ let mut _50: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _52: isize;
+ let mut _53: !;
+ let mut _51: isize;
+ let mut _52: !;
+ scope 23 {
+ }
+ }
@ -246,28 +245,25 @@
+ StorageDead(_24);
+ StorageLive(_47);
+ StorageLive(_48);
+ StorageLive(_53);
+ StorageLive(_52);
+ StorageLive(_44);
+ StorageLive(_45);
+ StorageLive(_46);
+ _48 = &mut _19;
+ StorageLive(_49);
+ StorageLive(_50);
+ _50 = &mut (_19.0: &mut std::future::Ready<()>);
+ _49 = &mut (_19.0: &mut std::future::Ready<()>);
+ _47 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_50);
+ _49 = Pin::<&mut std::future::Ready<()>> { pointer: copy _47 };
+ StorageDead(_49);
+ _46 = &mut ((*_47).0: std::option::Option<()>);
+ StorageLive(_51);
+ _51 = Option::<()>::None;
+ StorageLive(_50);
+ _50 = Option::<()>::None;
+ _45 = copy ((*_47).0: std::option::Option<()>);
+ ((*_47).0: std::option::Option<()>) = copy _51;
+ StorageDead(_51);
+ ((*_47).0: std::option::Option<()>) = copy _50;
+ StorageDead(_50);
+ StorageDead(_46);
+ StorageLive(_52);
+ _52 = discriminant(_45);
+ switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7];
+ StorageLive(_51);
+ _51 = discriminant(_45);
+ switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7];
}
- bb6 (cleanup): {
@ -354,16 +350,16 @@
+ }
+
+ bb16: {
+ _53 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ _52 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ }
+
+ bb17: {
+ _44 = move ((_45 as Some).0: ());
+ StorageDead(_52);
+ StorageDead(_51);
+ StorageDead(_45);
+ _18 = Poll::<()>::Ready(move _44);
+ StorageDead(_44);
+ StorageDead(_53);
+ StorageDead(_52);
+ StorageDead(_48);
+ StorageDead(_47);
+ StorageDead(_22);