about summary refs log tree commit diff
path: root/compiler/rustc_target/src
diff options
context:
space:
mode:
authorErik Desjardins <erikdesjardins@users.noreply.github.com>2024-03-17 00:14:20 -0400
committerErik Desjardins <erikdesjardins@users.noreply.github.com>2024-03-17 00:38:19 -0400
commit74ef47e90ca1466ea7f3dd8c3ec3738f05345809 (patch)
tree7e8028bd540b92be68819f7af09fe0a55eaf3436 /compiler/rustc_target/src
parent41c6fa812b0bed63e54c455134734452f9cee97c (diff)
downloadrust-74ef47e90ca1466ea7f3dd8c3ec3738f05345809.tar.gz
rust-74ef47e90ca1466ea7f3dd8c3ec3738f05345809.zip
make CastTarget::size and CastTarget::llvm_type consistent, remove
special case that's not present in Clang

Making the methods consistent doesn't require much justification. It's
required for us to generate correct code.

The special case was present near the end of `CastTarget::llvm_type`, and
resulted in the final integer component of the ABI type being shrunk to
the smallest integer that fits.

You can see this in action here (https://godbolt.org/z/Pe73cr91d),
where, for a struct with 5 u16 elements, rustc generates
`{ i64, i16 }`, while Clang generates `[2 x i64]`.

This special case was added a long time ago, when the function was
originally written [1]. That commit consolidated logic from many
backends, and in some of the code it deleted, sparc64 [2] and
powerpc64 [3] had similar special cases.

However, looking at Clang today, it doesn't have this special case for
sparc64 (https://godbolt.org/z/YaafvYWdf) or powerpc64
(https://godbolt.org/z/5c3YePTje), so this change just removes it.

[1]: https://github.com/rust-lang/rust/commit/f0636b61c7f84962a609e831760db9d77f4f5e14#diff-183c4dadf10704bd1f521b71f71d89bf755c9603a93f894d66c03bb1effc6021R231
[2]: https://github.com/rust-lang/rust/commit/f0636b61c7f84962a609e831760db9d77f4f5e14#diff-2d8f87ea6db6d7f0a6fbeb1d5549adc07e93331278d951a1e051a40f92914436L163-L166
[3]: https://github.com/rust-lang/rust/commit/f0636b61c7f84962a609e831760db9d77f4f5e14#diff-88af4a9df9ead503a5c7774a0455d270dea3ba60e9b0ec1ce550b4c53d3bce3bL172-L175
Diffstat (limited to 'compiler/rustc_target/src')
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs25
1 files changed, 14 insertions, 11 deletions
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 486afc5f8f3..643ba9f1cdd 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -251,9 +251,9 @@ pub struct Uniform {
     /// The total size of the argument, which can be:
     /// * equal to `unit.size` (one scalar/vector),
     /// * a multiple of `unit.size` (an array of scalar/vectors),
-    /// * if `unit.kind` is `Integer`, the last element
-    ///   can be shorter, i.e., `{ i64, i64, i32 }` for
-    ///   64-bit integers with a total size of 20 bytes.
+    /// * if `unit.kind` is `Integer`, the last element can be shorter, i.e., `{ i64, i64, i32 }`
+    ///   for 64-bit integers with a total size of 20 bytes. When the argument is actually passed,
+    ///   this size will be rounded up to the nearest multiple of `unit.size`.
     pub total: Size,
 }
 
@@ -319,14 +319,17 @@ impl CastTarget {
     }
 
     pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
-        let mut size = self.rest.total;
-        for i in 0..self.prefix.iter().count() {
-            match self.prefix[i] {
-                Some(v) => size += v.size,
-                None => {}
-            }
-        }
-        return size;
+        // Prefix arguments are passed in specific designated registers
+        let prefix_size = self
+            .prefix
+            .iter()
+            .filter_map(|x| x.map(|reg| reg.size))
+            .fold(Size::ZERO, |acc, size| acc + size);
+        // Remaining arguments are passed in chunks of the unit size
+        let rest_size =
+            self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes());
+
+        prefix_size + rest_size
     }
 
     pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {