Skip to content

Commit 19acbf4

Browse files
author
Günther Brammer
committed
Return f32 and f64 in XMM0 instead of FP0 on i686 Rust calling convention
i686 already uses SSE2 to do calculations with f32 and f64, but the C calling convention uses the x87 stack to return values. The Rust calling convention does not need to do this, and LLVM makes it easy to use XMM0 instead, which saves move instructions and fixes problems with NaN values.
1 parent 203c57d commit 19acbf4

File tree

3 files changed

+10
-4
lines changed

3 files changed

+10
-4
lines changed

compiler/rustc_ty_utils/src/abi.rs

+6
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ fn fn_abi_new_uncached<'tcx>(
371371
let target = &cx.tcx.sess.target;
372372
let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc");
373373
let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
374+
let x86_sse2 =
375+
target.arch == "x86" && (target.features.contains("sse2") || target.cpu == "pentium4");
374376
let linux_s390x_gnu_like =
375377
target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
376378
let linux_sparc64_gnu_like =
@@ -415,6 +417,10 @@ fn fn_abi_new_uncached<'tcx>(
415417
is_return,
416418
drop_target_pointee,
417419
);
420+
// Use XMM0 instead of FP0 to preserve NaN payloads
421+
if x86_sse2 && rust_abi && is_return && matches!(scalar.primitive(), F32 | F64) {
422+
attrs.set(ArgAttribute::InReg);
423+
}
418424
attrs
419425
});
420426

library/std/src/f32/tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ macro_rules! assert_f32_biteq {
328328

329329
// Ignore test on x87 floating point, these platforms do not guarantee NaN
330330
// payloads are preserved and flush denormals to zero, failing the tests.
331-
#[cfg(not(target_arch = "x86"))]
331+
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse2"))))]
332332
#[test]
333333
fn test_next_up() {
334334
let tiny = f32::from_bits(1);
@@ -361,7 +361,7 @@ fn test_next_up() {
361361

362362
// Ignore test on x87 floating point, these platforms do not guarantee NaN
363363
// payloads are preserved and flush denormals to zero, failing the tests.
364-
#[cfg(not(target_arch = "x86"))]
364+
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse2"))))]
365365
#[test]
366366
fn test_next_down() {
367367
let tiny = f32::from_bits(1);

library/std/src/f64/tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ macro_rules! assert_f64_biteq {
318318

319319
// Ignore test on x87 floating point, these platforms do not guarantee NaN
320320
// payloads are preserved and flush denormals to zero, failing the tests.
321-
#[cfg(not(target_arch = "x86"))]
321+
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse2"))))]
322322
#[test]
323323
fn test_next_up() {
324324
let tiny = f64::from_bits(1);
@@ -350,7 +350,7 @@ fn test_next_up() {
350350

351351
// Ignore test on x87 floating point, these platforms do not guarantee NaN
352352
// payloads are preserved and flush denormals to zero, failing the tests.
353-
#[cfg(not(target_arch = "x86"))]
353+
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse2"))))]
354354
#[test]
355355
fn test_next_down() {
356356
let tiny = f64::from_bits(1);

0 commit comments

Comments
 (0)