Skip to content

Commit fed8bd1

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 fed8bd1

File tree

4 files changed

+12
-4
lines changed

4 files changed

+12
-4
lines changed

Diff for: compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,7 @@ symbols! {
14891489
sreg,
14901490
sreg_low16,
14911491
sse,
1492+
sse2,
14921493
sse4a_target_feature,
14931494
stable,
14941495
staged_api,

Diff for: compiler/rustc_ty_utils/src/abi.rs

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_middle::ty::layout::{
77
use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
88
use rustc_session::config::OptLevel;
99
use rustc_span::def_id::DefId;
10+
use rustc_span::symbol::sym;
1011
use rustc_target::abi::call::{
1112
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
1213
RiscvInterruptKind,
@@ -371,6 +372,8 @@ fn fn_abi_new_uncached<'tcx>(
371372
let target = &cx.tcx.sess.target;
372373
let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc");
373374
let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
375+
let x86_sse2 = target.arch == "x86"
376+
&& cx.tcx.sess.parse_sess.config.contains(&(sym::target_feature, Some(sym::sse2)));
374377
let linux_s390x_gnu_like =
375378
target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
376379
let linux_sparc64_gnu_like =
@@ -415,6 +418,10 @@ fn fn_abi_new_uncached<'tcx>(
415418
is_return,
416419
drop_target_pointee,
417420
);
421+
// Use XMM0 instead of FP0 to preserve NaN payloads
422+
if x86_sse2 && rust_abi && is_return && matches!(scalar.primitive(), F32 | F64) {
423+
attrs.set(ArgAttribute::InReg);
424+
}
418425
attrs
419426
});
420427

Diff for: 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);

Diff for: 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)