diff options
| author | Trevor Gross <tmgross@umich.edu> | 2025-05-23 17:26:39 +0000 |
|---|---|---|
| committer | Trevor Gross <t.gross35@gmail.com> | 2025-05-28 02:58:42 -0400 |
| commit | 4c264c96ae30e45c503fbb24e452ea948c5229af (patch) | |
| tree | 8baaa8ca15c4d9b5ca8bc8e14797cfab6d2860d8 | |
| parent | db21837095f18a76d1fecb7d55547688a6b19647 (diff) | |
| download | rust-4c264c96ae30e45c503fbb24e452ea948c5229af.tar.gz rust-4c264c96ae30e45c503fbb24e452ea948c5229af.zip | |
Update `CmpResult` to use a pointer-sized return type
As seen at [1], LLVM uses `long long` on LLP64 (to get a 64-bit integer matching pointer size) and `long` on everything else, with exceptions for AArch64 and AVR. Our current logic always uses an `i32`. This happens to work because LLVM uses 32-bit instructions to check the output on x86-64, but the GCC checks the full 64-bit register so garbage in the upper half leads to incorrect results. Update our return type to be `isize`, with exceptions for AArch64 and AVR. Fixes: https://github.com/rust-lang/compiler-builtins/issues/919 [1]: https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27
4 files changed, 48 insertions, 26 deletions
diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs index 42d6652397d..87a89efb5a4 100644 --- a/library/compiler-builtins/builtins-test/benches/float_cmp.rs +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -1,12 +1,23 @@ #![cfg_attr(f128_enabled, feature(f128))] use builtins_test::float_bench; -use compiler_builtins::float::cmp; +use compiler_builtins::float::cmp::{self, CmpResult}; use criterion::{Criterion, criterion_main}; /// `gt` symbols are allowed to return differing results, they just get compared /// to 0. -fn gt_res_eq(a: i32, b: i32) -> bool { +fn gt_res_eq(mut a: CmpResult, mut b: CmpResult) -> bool { + // FIXME: Our CmpResult used to be `i32`, but GCC/LLVM expect `isize`. on 64-bit platforms, + // this means the top half of the word may be garbage if built with an old version of + // `compiler-builtins`, so add a hack around this. + // + // This can be removed once a version of `compiler-builtins` with the return type fix makes + // it upstream. + if size_of::<CmpResult>() == 8 { + a = a as i32 as CmpResult; + b = b as i32 as CmpResult; + } + let a_lt_0 = a <= 0; let b_lt_0 = b <= 0; (a_lt_0 && b_lt_0) || (!a_lt_0 && !b_lt_0) @@ -14,14 +25,14 @@ fn gt_res_eq(a: i32, b: i32) -> bool { float_bench! { name: cmp_f32_gt, - sig: (a: f32, b: f32) -> i32, + sig: (a: f32, b: f32) -> CmpResult, crate_fn: cmp::__gtsf2, sys_fn: __gtsf2, sys_available: all(), output_eq: gt_res_eq, asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomiss {a}, {b}", @@ -36,7 +47,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:s}, {b:s}", "cset {ret:w}, gt", @@ -53,13 +64,13 @@ float_bench! { float_bench! { name: cmp_f32_unord, - sig: (a: f32, b: f32) -> i32, + sig: (a: f32, b: f32) -> CmpResult, crate_fn: cmp::__unordsf2, sys_fn: __unordsf2, sys_available: all(), asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomiss {a}, {b}", @@ -74,7 +85,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:s}, {b:s}", "cset {ret:w}, vs", @@ -91,14 +102,14 @@ float_bench! { float_bench! { name: cmp_f64_gt, - sig: (a: f64, b: f64) -> i32, + sig: (a: f64, b: f64) -> CmpResult, crate_fn: cmp::__gtdf2, sys_fn: __gtdf2, sys_available: all(), output_eq: gt_res_eq, asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomisd {a}, {b}", @@ -113,7 +124,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:d}, {b:d}", "cset {ret:w}, gt", @@ -130,13 +141,13 @@ float_bench! { float_bench! { name: cmp_f64_unord, - sig: (a: f64, b: f64) -> i32, + sig: (a: f64, b: f64) -> CmpResult, crate_fn: cmp::__unorddf2, sys_fn: __unorddf2, sys_available: all(), asm: [ #[cfg(target_arch = "x86_64")] { - let ret: i32; + let ret: CmpResult; asm!( "xor {ret:e}, {ret:e}", "ucomisd {a}, {b}", @@ -151,7 +162,7 @@ float_bench! { }; #[cfg(target_arch = "aarch64")] { - let ret: i32; + let ret: CmpResult; asm!( "fcmp {a:d}, {b:d}", "cset {ret:w}, vs", @@ -168,7 +179,7 @@ float_bench! { float_bench! { name: cmp_f128_gt, - sig: (a: f128, b: f128) -> i32, + sig: (a: f128, b: f128) -> CmpResult, crate_fn: cmp::__gttf2, crate_fn_ppc: cmp::__gtkf2, sys_fn: __gttf2, @@ -180,7 +191,7 @@ float_bench! { float_bench! { name: cmp_f128_unord, - sig: (a: f128, b: f128) -> i32, + sig: (a: f128, b: f128) -> CmpResult, crate_fn: cmp::__unordtf2, crate_fn_ppc: cmp::__unordkf2, sys_fn: __unordtf2, diff --git a/library/compiler-builtins/builtins-test/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs index 2348f6bc973..0987185670e 100644 --- a/library/compiler-builtins/builtins-test/src/bench.rs +++ b/library/compiler-builtins/builtins-test/src/bench.rs @@ -358,8 +358,8 @@ impl_testio!(float f16); impl_testio!(float f32, f64); #[cfg(f128_enabled)] impl_testio!(float f128); -impl_testio!(int i16, i32, i64, i128); -impl_testio!(int u16, u32, u64, u128); +impl_testio!(int i8, i16, i32, i64, i128, isize); +impl_testio!(int u8, u16, u32, u64, u128, usize); impl_testio!((float, int)(f32, i32)); impl_testio!((float, int)(f64, i32)); #[cfg(f128_enabled)] diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index 296952821cb..f1e54dc1c83 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -2,14 +2,23 @@ use crate::float::Float; use crate::int::MinInt; - -// https://github.com/llvm/llvm-project/blob/1e6ba3cd2fe96be00b6ed6ba28b3d9f9271d784d/compiler-rt/lib/builtins/fp_compare_impl.inc#L22 -#[cfg(target_arch = "avr")] -pub type CmpResult = i8; - -// https://github.com/llvm/llvm-project/blob/1e6ba3cd2fe96be00b6ed6ba28b3d9f9271d784d/compiler-rt/lib/builtins/fp_compare_impl.inc#L25 -#[cfg(not(target_arch = "avr"))] -pub type CmpResult = i32; +use crate::support::cfg_if; + +// Taken from LLVM config: +// https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 +cfg_if! { + if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { + // Aarch64 uses `int` rather than a pointer-sized value. + pub type CmpResult = i32; + } else if #[cfg(target_arch = "avr")] { + // AVR uses a single byte. + pub type CmpResult = i8; + } else { + // In compiler-rt, LLP64 ABIs use `long long` and everything else uses `long`. In effect, + // this means the return value is always pointer-sized. + pub type CmpResult = isize; + } +} #[derive(Clone, Copy)] enum Result { diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index a4f596ab844..2771cfd32c8 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -11,6 +11,8 @@ mod int_traits; #[allow(unused_imports)] pub use big::{i256, u256}; +#[allow(unused_imports)] +pub(crate) use cfg_if; pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; |
