about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLuqman Aden <me@luqman.ca>2022-12-15 23:18:25 -0800
committerLuqman Aden <me@luqman.ca>2023-05-05 14:25:56 -0700
commit6a5ee110276aa0f24e569c15d10172e3fc40752f (patch)
tree9d35e0fa621dec39aa334fc5f2aaf0a1cc776e50
parentaf69cc0ea0698d47b281e6b5da78d4794dc5df04 (diff)
downloadrust-6a5ee110276aa0f24e569c15d10172e3fc40752f.tar.gz
rust-6a5ee110276aa0f24e569c15d10172e3fc40752f.zip
Don't bitcast aggregate field.
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs27
1 files changed, 26 insertions, 1 deletions
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!(),
         }