about summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Desjardins <erikdesjardins@users.noreply.github.com>2023-05-20 16:11:09 -0400
committerErik Desjardins <erikdesjardins@users.noreply.github.com>2023-07-10 19:19:38 -0400
commited317e4a479b4bacf102188445d03fabfb81a2c5 (patch)
tree6665df282145b0592ee265f42564bb09218dcd59
parent7089321c6deabb3c25cf0ec829ca209f77b8ee5a (diff)
downloadrust-ed317e4a479b4bacf102188445d03fabfb81a2c5.tar.gz
rust-ed317e4a479b4bacf102188445d03fabfb81a2c5.zip
i686-windows: pass arguments with requested alignment > 4 indirectly
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs9
-rw-r--r--compiler/rustc_target/src/abi/call/x86.rs29
-rw-r--r--compiler/rustc_target/src/abi/mod.rs8
-rw-r--r--compiler/rustc_target/src/lib.rs1
-rw-r--r--tests/run-make/extern-fn-struct-passing-abi/test.rs6
5 files changed, 48 insertions, 5 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index d95b05ef754..dc116e616fa 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1104,6 +1104,15 @@ where
     fn is_unit(this: TyAndLayout<'tcx>) -> bool {
         matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
     }
+
+    fn repr_options(this: TyAndLayout<'tcx>) -> ReprOptions {
+        match *this.ty.kind() {
+            ty::Adt(def, ..) => def.repr(),
+            _ => {
+                bug!("TyAndLayout::repr_options({:?}): not applicable", this)
+            }
+        }
+    }
 }
 
 /// Calculates whether a function's ABI can unwind or not.
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index d2c604fafa6..dd52b3cb520 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -54,7 +54,31 @@ where
             continue;
         }
 
-        if arg.layout.is_aggregate() {
+        // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2
+        // See https://reviews.llvm.org/D72114 for Clang behavior
+
+        let t = cx.target_spec();
+        let align_4 = Align::from_bytes(4).unwrap();
+        let align_16 = Align::from_bytes(16).unwrap();
+
+        if t.is_like_msvc
+            && arg.layout.is_adt()
+            && let Some(requested_align) = arg.layout.repr_options().align
+            && requested_align > align_4
+        {
+            // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114.
+            // Summarized here:
+            // - Arguments with _requested_ alignment > 4 are passed indirectly.
+            // - For backwards compatibility, arguments with natural alignment > 4 are still passed
+            //   on stack (via `byval`). For example, this includes `double`, `int64_t`,
+            //   and structs containing them, provided they lack an explicit alignment attribute.
+            assert!(arg.layout.align.abi >= requested_align,
+                "abi alignment {:?} less than requested alignment {:?}",
+                arg.layout.align.abi,
+                requested_align
+            );
+            arg.make_indirect();
+        } else if arg.layout.is_aggregate() {
             // We need to compute the alignment of the `byval` argument. The rules can be found in
             // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized
             // here, they are:
@@ -87,9 +111,6 @@ where
                 }
             }
 
-            let t = cx.target_spec();
-            let align_4 = Align::from_bytes(4).unwrap();
-            let align_16 = Align::from_bytes(16).unwrap();
             let byval_align = if arg.layout.align.abi < align_4 {
                 // (1.)
                 align_4
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 589cd3cf96b..aecf8b339f0 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -55,6 +55,7 @@ pub trait TyAbiInterface<'a, C>: Sized {
     fn is_never(this: TyAndLayout<'a, Self>) -> bool;
     fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
     fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
+    fn repr_options(this: TyAndLayout<'a, Self>) -> ReprOptions;
 }
 
 impl<'a, Ty> TyAndLayout<'a, Ty> {
@@ -125,6 +126,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
         Ty::is_unit(self)
     }
 
+    pub fn repr_options<C>(self) -> ReprOptions
+    where
+        Ty: TyAbiInterface<'a, C>,
+    {
+        Ty::repr_options(self)
+    }
+
     pub fn offset_of_subfield<C>(self, cx: &C, indices: impl Iterator<Item = usize>) -> Size
     where
         Ty: TyAbiInterface<'a, C>,
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index a7b54766bc6..3307244a217 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -12,6 +12,7 @@
 #![feature(associated_type_bounds)]
 #![feature(exhaustive_patterns)]
 #![feature(iter_intersperse)]
+#![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
diff --git a/tests/run-make/extern-fn-struct-passing-abi/test.rs b/tests/run-make/extern-fn-struct-passing-abi/test.rs
index d58254301cc..99e079f98a8 100644
--- a/tests/run-make/extern-fn-struct-passing-abi/test.rs
+++ b/tests/run-make/extern-fn-struct-passing-abi/test.rs
@@ -89,7 +89,11 @@ extern "C" {
 
     fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);
 
-    fn byval_rect_with_many_huge64(a: Huge64, b: Huge64, c: Huge64, d: Huge64, e: Huge64, f: Huge64, g: Rect);
+    fn byval_rect_with_many_huge64(
+        a: Huge64, b: Huge64, c: Huge64,
+        d: Huge64, e: Huge64, f: Huge64,
+        g: Rect,
+    );
 
     fn split_rect(a: i32, b: i32, s: Rect);