summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_target/src/abi/call
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_target/src/abi/call
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_target/src/abi/call')
-rw-r--r--compiler/rustc_target/src/abi/call/aarch64.rs70
-rw-r--r--compiler/rustc_target/src/abi/call/csky.rs31
-rw-r--r--compiler/rustc_target/src/abi/call/m68k.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs60
-rw-r--r--compiler/rustc_target/src/abi/call/wasm.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/x86.rs73
-rw-r--r--compiler/rustc_target/src/abi/call/x86_64.rs2
7 files changed, 190 insertions, 50 deletions
diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs
index a84988fa7..b4c7b0f12 100644
--- a/compiler/rustc_target/src/abi/call/aarch64.rs
+++ b/compiler/rustc_target/src/abi/call/aarch64.rs
@@ -1,25 +1,15 @@
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
use crate::abi::{HasDataLayout, TyAbiInterface};
-/// Given integer-types M and register width N (e.g. M=u16 and N=32 bits), the
-/// `ParamExtension` policy specifies how a uM value should be treated when
-/// passed via register or stack-slot of width N. See also rust-lang/rust#97463.
+/// Indicates the variant of the AArch64 ABI we are compiling for.
+/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
+///
+/// Corresponds to Clang's `AArch64ABIInfo::ABIKind`.
#[derive(Copy, Clone, PartialEq)]
-pub enum ParamExtension {
- /// Indicates that when passing an i8/i16, either as a function argument or
- /// as a return value, it must be sign-extended to 32 bits, and likewise a
- /// u8/u16 must be zero-extended to 32-bits. (This variant is here to
- /// accommodate Apple's deviation from the usual AArch64 ABI as defined by
- /// ARM.)
- ///
- /// See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
- ExtendTo32Bits,
-
- /// Indicates that no sign- nor zero-extension is performed: if a value of
- /// type with bitwidth M is passed as function argument or return value,
- /// then M bits are copied into the least significant M bits, and the
- /// remaining bits of the register (or word of memory) are untouched.
- NoExtension,
+pub enum AbiKind {
+ AAPCS,
+ DarwinPCS,
+ Win64,
}
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
@@ -45,15 +35,17 @@ where
})
}
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension)
+fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout,
{
if !ret.layout.is_aggregate() {
- match param_policy {
- ParamExtension::ExtendTo32Bits => ret.extend_integer_width_to(32),
- ParamExtension::NoExtension => {}
+ if kind == AbiKind::DarwinPCS {
+ // On Darwin, when returning an i8/i16, it must be sign-extended to 32 bits,
+ // and likewise a u8/u16 must be zero-extended to 32-bits.
+ // See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
+ ret.extend_integer_width_to(32)
}
return;
}
@@ -70,15 +62,17 @@ where
ret.make_indirect();
}
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension)
+fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout,
{
if !arg.layout.is_aggregate() {
- match param_policy {
- ParamExtension::ExtendTo32Bits => arg.extend_integer_width_to(32),
- ParamExtension::NoExtension => {}
+ if kind == AbiKind::DarwinPCS {
+ // On Darwin, when passing an i8/i16, it must be sign-extended to 32 bits,
+ // and likewise a u8/u16 must be zero-extended to 32-bits.
+ // See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
+ arg.extend_integer_width_to(32);
}
return;
}
@@ -87,27 +81,39 @@ where
return;
}
let size = arg.layout.size;
- let bits = size.bits();
- if bits <= 128 {
- arg.cast_to(Uniform { unit: Reg::i64(), total: size });
+ let align = if kind == AbiKind::AAPCS {
+ // When passing small aggregates by value, the AAPCS ABI mandates using the unadjusted
+ // alignment of the type (not including `repr(align)`).
+ // This matches behavior of `AArch64ABIInfo::classifyArgumentType` in Clang.
+ // See: <https://github.com/llvm/llvm-project/blob/5e691a1c9b0ad22689d4a434ddf4fed940e58dec/clang/lib/CodeGen/TargetInfo.cpp#L5816-L5823>
+ arg.layout.unadjusted_abi_align
+ } else {
+ arg.layout.align.abi
+ };
+ if size.bits() <= 128 {
+ if align.bits() == 128 {
+ arg.cast_to(Uniform { unit: Reg::i128(), total: size });
+ } else {
+ arg.cast_to(Uniform { unit: Reg::i64(), total: size });
+ }
return;
}
arg.make_indirect();
}
-pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, param_policy: ParamExtension)
+pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, kind: AbiKind)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
- classify_ret(cx, &mut fn_abi.ret, param_policy);
+ classify_ret(cx, &mut fn_abi.ret, kind);
}
for arg in fn_abi.args.iter_mut() {
if arg.is_ignore() {
continue;
}
- classify_arg(cx, arg, param_policy);
+ classify_arg(cx, arg, kind);
}
}
diff --git a/compiler/rustc_target/src/abi/call/csky.rs b/compiler/rustc_target/src/abi/call/csky.rs
new file mode 100644
index 000000000..bbe95fa20
--- /dev/null
+++ b/compiler/rustc_target/src/abi/call/csky.rs
@@ -0,0 +1,31 @@
+// See https://github.com/llvm/llvm-project/blob/d85b94bf0080dcd780656c0f5e6342800720eba9/llvm/lib/Target/CSKY/CSKYCallingConv.td
+use crate::abi::call::{ArgAbi, FnAbi};
+
+fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
+ if ret.layout.is_aggregate() || ret.layout.size.bits() > 64 {
+ ret.make_indirect();
+ } else {
+ ret.extend_integer_width_to(32);
+ }
+}
+
+fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+ if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 {
+ arg.make_indirect();
+ } else {
+ arg.extend_integer_width_to(32);
+ }
+}
+
+pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+ if !fn_abi.ret.is_ignore() {
+ classify_ret(&mut fn_abi.ret);
+ }
+
+ for arg in fn_abi.args.iter_mut() {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg(arg);
+ }
+}
diff --git a/compiler/rustc_target/src/abi/call/m68k.rs b/compiler/rustc_target/src/abi/call/m68k.rs
index c1e0f54af..1d4649ed8 100644
--- a/compiler/rustc_target/src/abi/call/m68k.rs
+++ b/compiler/rustc_target/src/abi/call/m68k.rs
@@ -10,7 +10,7 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
if arg.layout.is_aggregate() {
- arg.make_indirect_byval();
+ arg.make_indirect_byval(None);
} else {
arg.extend_integer_width_to(32);
}
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index c4abf6f4b..8fab13d5d 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -9,6 +9,7 @@ mod amdgpu;
mod arm;
mod avr;
mod bpf;
+mod csky;
mod hexagon;
mod loongarch;
mod m68k;
@@ -494,9 +495,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
.set(ArgAttribute::NonNull)
.set(ArgAttribute::NoUndef);
attrs.pointee_size = layout.size;
- // FIXME(eddyb) We should be doing this, but at least on
- // i686-pc-windows-msvc, it results in wrong stack offsets.
- // attrs.pointee_align = Some(layout.align.abi);
+ attrs.pointee_align = Some(layout.align.abi);
let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new());
@@ -513,11 +512,19 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
self.mode = Self::indirect_pass_mode(&self.layout);
}
- pub fn make_indirect_byval(&mut self) {
+ pub fn make_indirect_byval(&mut self, byval_align: Option<Align>) {
self.make_indirect();
match self.mode {
- PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => {
+ PassMode::Indirect { ref mut attrs, extra_attrs: _, ref mut on_stack } => {
*on_stack = true;
+
+ // Some platforms, like 32-bit x86, change the alignment of the type when passing
+ // `byval`. Account for that.
+ if let Some(byval_align) = byval_align {
+ // On all targets with byval align this is currently true, so let's assert it.
+ debug_assert!(byval_align >= Align::from_bytes(4).unwrap());
+ attrs.pointee_align = Some(byval_align);
+ }
}
_ => unreachable!(),
}
@@ -597,6 +604,25 @@ pub enum Conv {
AmdGpuKernel,
AvrInterrupt,
AvrNonBlockingInterrupt,
+
+ RiscvInterrupt {
+ kind: RiscvInterruptKind,
+ },
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+pub enum RiscvInterruptKind {
+ Machine,
+ Supervisor,
+}
+
+impl RiscvInterruptKind {
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ Self::Machine => "machine",
+ Self::Supervisor => "supervisor",
+ }
+ }
}
/// Metadata describing how the arguments to a native function
@@ -644,7 +670,8 @@ impl<'a, Ty> FnAbi<'a, Ty> {
{
if abi == spec::abi::Abi::X86Interrupt {
if let Some(arg) = self.args.first_mut() {
- arg.make_indirect_byval();
+ // FIXME(pcwalton): This probably should use the x86 `byval` ABI...
+ arg.make_indirect_byval(None);
}
return Ok(());
}
@@ -672,20 +699,23 @@ impl<'a, Ty> FnAbi<'a, Ty> {
}
},
"aarch64" => {
- let param_policy = if cx.target_spec().is_like_osx {
- aarch64::ParamExtension::ExtendTo32Bits
+ let kind = if cx.target_spec().is_like_osx {
+ aarch64::AbiKind::DarwinPCS
+ } else if cx.target_spec().is_like_windows {
+ aarch64::AbiKind::Win64
} else {
- aarch64::ParamExtension::NoExtension
+ aarch64::AbiKind::AAPCS
};
- aarch64::compute_abi_info(cx, self, param_policy)
+ aarch64::compute_abi_info(cx, self, kind)
}
"amdgpu" => amdgpu::compute_abi_info(cx, self),
"arm" => arm::compute_abi_info(cx, self),
"avr" => avr::compute_abi_info(self),
"loongarch64" => loongarch::compute_abi_info(cx, self),
"m68k" => m68k::compute_abi_info(self),
- "mips" => mips::compute_abi_info(cx, self),
- "mips64" => mips64::compute_abi_info(cx, self),
+ "csky" => csky::compute_abi_info(self),
+ "mips" | "mips32r6" => mips::compute_abi_info(cx, self),
+ "mips64" | "mips64r6" => mips64::compute_abi_info(cx, self),
"powerpc" => powerpc::compute_abi_info(self),
"powerpc64" => powerpc64::compute_abi_info(cx, self),
"s390x" => s390x::compute_abi_info(cx, self),
@@ -744,6 +774,12 @@ impl FromStr for Conv {
"AmdGpuKernel" => Ok(Conv::AmdGpuKernel),
"AvrInterrupt" => Ok(Conv::AvrInterrupt),
"AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt),
+ "RiscvInterrupt(machine)" => {
+ Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine })
+ }
+ "RiscvInterrupt(supervisor)" => {
+ Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor })
+ }
_ => Err(format!("'{s}' is not a valid value for entry function call convention.")),
}
}
diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs
index 44427ee53..0eb2309ec 100644
--- a/compiler/rustc_target/src/abi/call/wasm.rs
+++ b/compiler/rustc_target/src/abi/call/wasm.rs
@@ -36,7 +36,7 @@ where
{
arg.extend_integer_width_to(32);
if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) {
- arg.make_indirect_byval();
+ arg.make_indirect_byval(None);
}
}
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index 7c26335dc..b738c3133 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -1,5 +1,5 @@
use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
-use crate::abi::{HasDataLayout, TyAbiInterface};
+use crate::abi::{Abi, Align, HasDataLayout, TyAbiInterface, TyAndLayout};
use crate::spec::HasTargetSpec;
#[derive(PartialEq)]
@@ -53,8 +53,75 @@ where
if arg.is_ignore() {
continue;
}
- if arg.layout.is_aggregate() {
- arg.make_indirect_byval();
+
+ // 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(max_repr_align) = arg.layout.max_repr_align
+ && max_repr_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 >= max_repr_align,
+ "abi alignment {:?} less than requested alignment {max_repr_align:?}",
+ arg.layout.align.abi,
+ );
+ 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:
+ //
+ // 1. If the natural alignment of the type is <= 4, the alignment is 4.
+ //
+ // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment.
+ // This doesn't matter here because we only pass aggregates via `byval`, not vectors.
+ //
+ // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector
+ // type is 16.
+ //
+ // 4. If none of these conditions are true, the alignment is 4.
+
+ fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
+ where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ {
+ match layout.abi {
+ Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) => false,
+ Abi::Vector { .. } => true,
+ Abi::Aggregate { .. } => {
+ for i in 0..layout.fields.count() {
+ if contains_vector(cx, layout.field(cx, i)) {
+ return true;
+ }
+ }
+ false
+ }
+ }
+ }
+
+ let byval_align = if arg.layout.align.abi < align_4 {
+ // (1.)
+ align_4
+ } else if t.is_like_osx && contains_vector(cx, arg.layout) {
+ // (3.)
+ align_16
+ } else {
+ // (4.)
+ align_4
+ };
+
+ arg.make_indirect_byval(Some(byval_align));
} else {
arg.extend_integer_width_to(32);
}
diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs
index b1aefaf05..d1efe9776 100644
--- a/compiler/rustc_target/src/abi/call/x86_64.rs
+++ b/compiler/rustc_target/src/abi/call/x86_64.rs
@@ -213,7 +213,7 @@ where
match cls_or_mem {
Err(Memory) => {
if is_arg {
- arg.make_indirect_byval();
+ arg.make_indirect_byval(None);
} else {
// `sret` parameter thus one less integer register available
arg.make_indirect();