about summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2025-07-29 20:41:34 -0700
committerScott McMurray <scottmcm@users.noreply.github.com>2025-07-29 20:41:34 -0700
commitfe08ba0bae44b870fdda45a98ac51f435ddfc044 (patch)
tree8ed6d7fc741be527ebb4c93915acb639212ab905
parentba7e63b63871a429533c189adbfb1d9a6337e000 (diff)
downloadrust-fe08ba0bae44b870fdda45a98ac51f435ddfc044.tar.gz
rust-fe08ba0bae44b870fdda45a98ac51f435ddfc044.zip
Re-block SRoA on SIMD types
Fixes 144621

-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs6
-rw-r--r--tests/mir-opt/sroa/simd_sroa.foo.ScalarReplacementOfAggregates.diff32
-rw-r--r--tests/mir-opt/sroa/simd_sroa.rs18
3 files changed, 55 insertions, 1 deletions
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 80c4b58a574..38769885f36 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -72,8 +72,12 @@ fn escaping_locals<'tcx>(
             return true;
         }
         if let ty::Adt(def, _args) = ty.kind()
-            && tcx.is_lang_item(def.did(), LangItem::DynMetadata)
+            && (def.repr().simd() || tcx.is_lang_item(def.did(), LangItem::DynMetadata))
         {
+            // Exclude #[repr(simd)] types so that they are not de-optimized into an array
+            // (MCP#838 banned projections into SIMD types, but if the value is unused
+            // this pass sees "all the uses are of the fields" and expands it.)
+
             // codegen wants to see the `DynMetadata<T>`,
             // not the inner reference-to-opaque-type.
             return true;
diff --git a/tests/mir-opt/sroa/simd_sroa.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/simd_sroa.foo.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..74403247108
--- /dev/null
+++ b/tests/mir-opt/sroa/simd_sroa.foo.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,32 @@
+- // MIR for `foo` before ScalarReplacementOfAggregates
++ // MIR for `foo` after ScalarReplacementOfAggregates
+  
+  fn foo(_1: &[Simd<u8, 16>], _2: Simd<u8, 16>) -> () {
+      debug simds => _1;
+      debug _unused => _2;
+      let mut _0: ();
+      let _3: std::simd::Simd<u8, 16>;
+      let _4: usize;
+      let mut _5: usize;
+      let mut _6: bool;
+      scope 1 {
+          debug a => _3;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = const 0_usize;
+          _5 = PtrMetadata(copy _1);
+          _6 = Lt(copy _4, copy _5);
+          assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+          _3 = copy (*_1)[_4];
+          StorageDead(_4);
+          StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/simd_sroa.rs b/tests/mir-opt/sroa/simd_sroa.rs
new file mode 100644
index 00000000000..1ae84d3f975
--- /dev/null
+++ b/tests/mir-opt/sroa/simd_sroa.rs
@@ -0,0 +1,18 @@
+//@ needs-unwind
+#![feature(portable_simd)]
+
+// SRoA expands things even if they're unused
+// <https://github.com/rust-lang/rust/issues/144621>
+
+use std::simd::Simd;
+
+// EMIT_MIR simd_sroa.foo.ScalarReplacementOfAggregates.diff
+pub(crate) fn foo(simds: &[Simd<u8, 16>], _unused: Simd<u8, 16>) {
+    // CHECK-LABEL: fn foo
+    // CHECK-NOT: [u8; 16]
+    // CHECK: let [[SIMD:_.+]]: std::simd::Simd<u8, 16>;
+    // CHECK-NOT: [u8; 16]
+    // CHECK: [[SIMD]] = copy (*_1)[0 of 1];
+    // CHECK-NOT: [u8; 16]
+    let a = simds[0];
+}