1
Fork 0

fix ZST handling for Windows ABIs on MSVC target

This commit is contained in:
Ralf Jung 2025-01-07 15:50:04 +01:00
parent 67951d946a
commit d760bb6603
10 changed files with 130 additions and 275 deletions

View file

@ -1,7 +1,7 @@
use std::str::FromStr;
use std::{fmt, iter};
pub use rustc_abi::{Reg, RegKind};
pub use rustc_abi::{ExternAbi, Reg, RegKind};
use rustc_macros::HashStable_Generic;
use rustc_span::Symbol;
@ -9,8 +9,7 @@ use crate::abi::{
self, AddressSpace, Align, BackendRepr, HasDataLayout, Pointer, Size, TyAbiInterface,
TyAndLayout,
};
use crate::spec::abi::Abi as SpecAbi;
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
mod aarch64;
mod amdgpu;
@ -627,20 +626,20 @@ impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> {
#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum AdjustForForeignAbiError {
/// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
Unsupported { arch: Symbol, abi: spec::abi::Abi },
Unsupported { arch: Symbol, abi: ExternAbi },
}
impl<'a, Ty> FnAbi<'a, Ty> {
pub fn adjust_for_foreign_abi<C>(
&mut self,
cx: &C,
abi: spec::abi::Abi,
abi: ExternAbi,
) -> Result<(), AdjustForForeignAbiError>
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt,
{
if abi == spec::abi::Abi::X86Interrupt {
if abi == ExternAbi::X86Interrupt {
if let Some(arg) = self.args.first_mut() {
arg.pass_by_stack_offset(None);
}
@ -651,12 +650,10 @@ impl<'a, Ty> FnAbi<'a, Ty> {
match &spec.arch[..] {
"x86" => {
let (flavor, regparm) = match abi {
spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } => {
ExternAbi::Fastcall { .. } | ExternAbi::Vectorcall { .. } => {
(x86::Flavor::FastcallOrVectorcall, None)
}
spec::abi::Abi::C { .. }
| spec::abi::Abi::Cdecl { .. }
| spec::abi::Abi::Stdcall { .. } => {
ExternAbi::C { .. } | ExternAbi::Cdecl { .. } | ExternAbi::Stdcall { .. } => {
(x86::Flavor::General, cx.x86_abi_opt().regparm)
}
_ => (x86::Flavor::General, None),
@ -666,11 +663,13 @@ impl<'a, Ty> FnAbi<'a, Ty> {
x86::compute_abi_info(cx, self, opts);
}
"x86_64" => match abi {
spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(cx, self),
ExternAbi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
ExternAbi::Win64 { .. } | ExternAbi::Vectorcall { .. } => {
x86_win64::compute_abi_info(cx, self, abi)
}
_ => {
if cx.target_spec().is_like_windows {
x86_win64::compute_abi_info(cx, self)
x86_win64::compute_abi_info(cx, self, abi)
} else {
x86_64::compute_abi_info(cx, self)
}
@ -701,7 +700,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
"sparc" => sparc::compute_abi_info(cx, self),
"sparc64" => sparc64::compute_abi_info(cx, self),
"nvptx64" => {
if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::PtxKernel {
if cx.target_spec().adjust_abi(abi, self.c_variadic) == ExternAbi::PtxKernel {
nvptx64::compute_ptx_kernel_abi_info(cx, self)
} else {
nvptx64::compute_abi_info(self)
@ -730,7 +729,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
Ok(())
}
pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: SpecAbi)
pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: ExternAbi)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec,
@ -821,7 +820,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
// that's how we connect up to LLVM and it's unstable
// anyway, we control all calls to it in libstd.
BackendRepr::Vector { .. }
if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect =>
if abi != ExternAbi::RustIntrinsic && spec.simd_types_indirect =>
{
arg.make_indirect();
continue;

View file

@ -1,11 +1,15 @@
use rustc_abi::{BackendRepr, Float, Primitive};
use rustc_abi::{BackendRepr, ExternAbi, Float, Primitive};
use crate::abi::call::{ArgAbi, FnAbi, Reg};
use crate::spec::HasTargetSpec;
// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
pub(crate) fn compute_abi_info<Ty>(
cx: &impl HasTargetSpec,
fn_abi: &mut FnAbi<'_, Ty>,
abi: ExternAbi,
) {
let fixup = |a: &mut ArgAbi<'_, Ty>| {
match a.layout.backend_repr {
BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {}
@ -40,11 +44,15 @@ pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'
fixup(&mut fn_abi.ret);
}
for arg in fn_abi.args.iter_mut() {
if arg.is_ignore() {
// x86_64-pc-windows-gnu doesn't ignore ZSTs.
if cx.target_spec().os == "windows"
&& cx.target_spec().env == "gnu"
&& arg.layout.is_zst()
if arg.is_ignore() && arg.layout.is_zst() {
// Windows ABIs do not talk about ZST since such types do not exist in MSVC.
// In that sense we can do whatever we want here, and maybe we should throw an error
// (but of course that would be a massive breaking change now).
// We try to match clang and gcc, so we make windows-gnu and the native
// Windows ABIs (i.e., everything except for `extern "C"`) pass ZST via
// pointer indirection. windows-msvc `extern "C"` still skips ZST.
if (cx.target_spec().os == "windows" && cx.target_spec().env == "gnu")
|| !matches!(abi, ExternAbi::C { .. })
{
arg.make_indirect_from_ignore();
}

View file

@ -2815,12 +2815,17 @@ impl Target {
Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
Abi::EfiApi => Abi::C { unwind: false },
// See commentary in `is_abi_supported`.
Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi,
Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind },
Abi::Fastcall { .. } if self.arch == "x86" => abi,
// See commentary in `is_abi_supported`: we map these ABIs to "C" when they do not make sense.
Abi::Stdcall { .. } | Abi::Thiscall { .. } | Abi::Fastcall { .. }
if self.arch == "x86" =>
{
abi
}
Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
Abi::Stdcall { unwind }
| Abi::Thiscall { unwind }
| Abi::Fastcall { unwind }
| Abi::Vectorcall { unwind } => Abi::C { unwind },
// The Windows x64 calling convention we use for `extern "Rust"`
// <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>