From 6a5ee110276aa0f24e569c15d10172e3fc40752f Mon Sep 17 00:00:00 2001
From: Luqman Aden <me@luqman.ca>
Date: Thu, 15 Dec 2022 23:18:25 -0800
Subject: [PATCH] Don't bitcast aggregate field.

---
 compiler/rustc_codegen_ssa/src/mir/operand.rs | 27 ++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 957ec8629fa..7623daeb96f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -237,13 +237,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
         };
 
         match (&mut val, field.abi) {
-            (OperandValue::Immediate(llval), _) => {
+            (
+                OperandValue::Immediate(llval),
+                Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. },
+            ) => {
                 // Bools in union fields needs to be truncated.
                 *llval = bx.to_immediate(*llval, field);
                 // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
                 let ty = bx.cx().immediate_backend_type(field);
                 if bx.type_kind(ty) == TypeKind::Pointer {
                     *llval = bx.pointercast(*llval, ty);
+                } else {
+                    *llval = bx.bitcast(*llval, ty);
                 }
             }
             (OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => {
@@ -255,11 +260,31 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                 let b_ty = bx.cx().scalar_pair_element_backend_type(field, 1, true);
                 if bx.type_kind(a_ty) == TypeKind::Pointer {
                     *a = bx.pointercast(*a, a_ty);
+                } else {
+                    *a = bx.bitcast(*a, a_ty);
                 }
                 if bx.type_kind(b_ty) == TypeKind::Pointer {
                     *b = bx.pointercast(*b, b_ty);
+                } else {
+                    *b = bx.bitcast(*b, b_ty);
                 }
             }
+            // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
+            (OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => {
+                assert!(matches!(self.layout.abi, Abi::Vector { .. }));
+
+                let llty = bx.cx().backend_type(self.layout);
+                let llfield_ty = bx.cx().backend_type(field);
+
+                // Can't bitcast an aggregate, so round trip through memory.
+                let lltemp = bx.alloca(llfield_ty, field.align.abi);
+                let llptr = bx.pointercast(lltemp, bx.cx().type_ptr_to(llty));
+                bx.store(*llval, llptr, field.align.abi);
+                *llval = bx.load(llfield_ty, lltemp, field.align.abi);
+            }
+            (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => {
+                bug!()
+            }
             (OperandValue::Pair(..), _) => bug!(),
             (OperandValue::Ref(..), _) => bug!(),
         }