Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x86-32 float return for 'Rust' ABI: treat all float types consistently #131871

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 15 additions & 22 deletions compiler/rustc_ty_utils/src/abi.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::iter;

use rustc_abi::Float::*;
use rustc_abi::Primitive::{Float, Pointer};
use rustc_abi::{Abi, AddressSpace, PointerKind, Scalar, Size};
use rustc_hir as hir;
Expand Down Expand Up @@ -695,37 +694,31 @@ fn fn_abi_adjust_for_abi<'tcx>(
}

// Avoid returning floats in x87 registers on x86 as loading and storing from x87
// registers will quiet signalling NaNs.
// registers will quiet signalling NaNs. Also avoid using SSE registers since they
// are not always available (depending on target features).
if tcx.sess.target.arch == "x86"
&& arg_idx.is_none()
// Intrinsics themselves are not actual "real" functions, so theres no need to
// change their ABIs.
&& abi != SpecAbi::RustIntrinsic
{
match arg.layout.abi {
// Handle similar to the way arguments with an `Abi::Aggregate` abi are handled
// below, by returning arguments up to the size of a pointer (32 bits on x86)
// cast to an appropriately sized integer.
Abi::Scalar(s) if s.primitive() == Float(F32) => {
// Same size as a pointer, return in a register.
arg.cast_to(Reg::i32());
return;
let has_float = match arg.layout.abi {
Abi::Scalar(s) => matches!(s.primitive(), Float(_)),
Abi::ScalarPair(s1, s2) => {
matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_))
Comment on lines +706 to +708
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Abi::Scalar(s) => matches!(s.primitive(), Float(_)),
Abi::ScalarPair(s1, s2) => {
matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_))
Abi::Scalar(s) => matches!(s.primitive(), Float(F16 | F32 | F64)),
Abi::ScalarPair(s1, s2) => {
matches!(s1.primitive(), Float(F16 | F32 | F64)) || matches!(s2.primitive(), Float(F16 | F32 | F64))

nit: There's no need to include f128 here as the 32-bit x86 ABI already guarantees it gets passed in memory.

Copy link
Member Author

@RalfJung RalfJung Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we should treat all float types uniformly here, that's more future-proof. The result is the same both ways but my code makes it more clear what happens, relying on fewer external assumptions.

We don't care about being consistent with the C ABI here, after all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I kinda agree morally with beetrees but not actually: this seems fine as-is.

I don't think it's worth spending too much time on this. While I do need to be able to read this code to refactor it, I do intend to bulldoze it.

}
Abi::Scalar(s) if s.primitive() == Float(F64) => {
// Larger than a pointer, return indirectly.
arg.make_indirect();
return;
}
Abi::ScalarPair(s1, s2)
if matches!(s1.primitive(), Float(F32 | F64))
|| matches!(s2.primitive(), Float(F32 | F64)) =>
{
_ => false, // anyway not passed via registers on x86
};
if has_float {
if arg.layout.size <= Pointer(AddressSpace::DATA).size(cx) {
// Same size or smaller than pointer, return in a register.
arg.cast_to(Reg { kind: RegKind::Integer, size: arg.layout.size });
} else {
// Larger than a pointer, return indirectly.
arg.make_indirect();
return;
}
_ => {}
};
return;
}
}

match arg.layout.abi {
Expand Down
Loading