mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-30 20:44:34 +00:00 
			
		
		
		
	 9dad77f337
			
		
	
	
		9dad77f337
		
	
	
	
	
		
			
			Emit `x86_no_sse` in the compiler-builtins (and builtins-test) build script, and use it to simplify `all(target_arch = "x86", not(target_fefature = "sse))` configuration.
		
			
				
	
	
		
			165 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| #![feature(f128)]
 | |
| #![allow(unused_macros)]
 | |
| 
 | |
| use builtins_test::*;
 | |
| use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4};
 | |
| use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc};
 | |
| 
 | |
| // Division algorithms have by far the nastiest and largest number of edge cases, and experience shows
 | |
| // that sometimes 100_000 iterations of the random fuzzer is needed.
 | |
| 
 | |
| /// Creates intensive test functions for division functions of a certain size
 | |
| macro_rules! test {
 | |
|     (
 | |
|         $n:expr, // the number of bits in a $iX or $uX
 | |
|         $uX:ident, // unsigned integer that will be shifted
 | |
|         $iX:ident, // signed version of $uX
 | |
|         $test_name:ident, // name of the test function
 | |
|         $unsigned_name:ident, // unsigned division function
 | |
|         $signed_name:ident // signed division function
 | |
|     ) => {
 | |
|         #[test]
 | |
|         fn $test_name() {
 | |
|             fuzz_2(N, |lhs, rhs| {
 | |
|                 if rhs == 0 {
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 let mut rem: $uX = 0;
 | |
|                 let quo: $uX = $unsigned_name(lhs, rhs, Some(&mut rem));
 | |
|                 if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) {
 | |
|                     panic!(
 | |
|                         "unsigned division function failed with lhs:{} rhs:{} \
 | |
|                         std:({}, {}) builtins:({}, {})",
 | |
|                         lhs,
 | |
|                         rhs,
 | |
|                         lhs.wrapping_div(rhs),
 | |
|                         lhs.wrapping_rem(rhs),
 | |
|                         quo,
 | |
|                         rem
 | |
|                     );
 | |
|                 }
 | |
| 
 | |
|                 // test the signed division function also
 | |
|                 let lhs = lhs as $iX;
 | |
|                 let rhs = rhs as $iX;
 | |
|                 let mut rem: $iX = 0;
 | |
|                 let quo: $iX = $signed_name(lhs, rhs, &mut rem);
 | |
|                 // We cannot just test that
 | |
|                 // `lhs == rhs.wrapping_mul(quo).wrapping_add(rem)`, but also
 | |
|                 // need to make sure the remainder isn't larger than the divisor
 | |
|                 // and has the correct sign.
 | |
|                 let incorrect_rem = if rem == 0 {
 | |
|                     false
 | |
|                 } else if rhs == $iX::MIN {
 | |
|                     // `rhs.wrapping_abs()` would overflow, so handle this case
 | |
|                     // separately.
 | |
|                     (lhs.is_negative() != rem.is_negative()) || (rem == $iX::MIN)
 | |
|                 } else {
 | |
|                     (lhs.is_negative() != rem.is_negative())
 | |
|                         || (rhs.wrapping_abs() <= rem.wrapping_abs())
 | |
|                 };
 | |
|                 if incorrect_rem || lhs != rhs.wrapping_mul(quo).wrapping_add(rem) {
 | |
|                     panic!(
 | |
|                         "signed division function failed with lhs:{} rhs:{} \
 | |
|                         std:({}, {}) builtins:({}, {})",
 | |
|                         lhs,
 | |
|                         rhs,
 | |
|                         lhs.wrapping_div(rhs),
 | |
|                         lhs.wrapping_rem(rhs),
 | |
|                         quo,
 | |
|                         rem
 | |
|                     );
 | |
|                 }
 | |
|             });
 | |
|         }
 | |
|     };
 | |
| }
 | |
| 
 | |
| test!(32, u32, i32, div_rem_si4, __udivmodsi4, __divmodsi4);
 | |
| test!(64, u64, i64, div_rem_di4, __udivmoddi4, __divmoddi4);
 | |
| test!(128, u128, i128, div_rem_ti4, __udivmodti4, __divmodti4);
 | |
| 
 | |
| #[test]
 | |
| fn divide_sparc() {
 | |
|     fuzz_2(N, |lhs, rhs| {
 | |
|         if rhs == 0 {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         let mut rem: u128 = 0;
 | |
|         let quo: u128 = u128_divide_sparc(lhs, rhs, &mut rem);
 | |
|         if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) {
 | |
|             panic!(
 | |
|                 "u128_divide_sparc({}, {}): \
 | |
|                 std:({}, {}), builtins:({}, {})",
 | |
|                 lhs,
 | |
|                 rhs,
 | |
|                 lhs.wrapping_div(rhs),
 | |
|                 lhs.wrapping_rem(rhs),
 | |
|                 quo,
 | |
|                 rem
 | |
|             );
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| macro_rules! float {
 | |
|     ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
 | |
|         $(
 | |
|             #[test]
 | |
|             fn $fn() {
 | |
|                 use compiler_builtins::float::{div::$fn, Float};
 | |
|                 use core::ops::Div;
 | |
| 
 | |
|                 fuzz_float_2(N, |x: $f, y: $f| {
 | |
|                     let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y);
 | |
|                     let quo1: $f = $fn(x, y);
 | |
| 
 | |
|                     // ARM SIMD instructions always flush subnormals to zero
 | |
|                     if cfg!(target_arch = "arm") &&
 | |
|                         ((Float::is_subnormal(quo0)) || Float::is_subnormal(quo1)) {
 | |
|                         return;
 | |
|                     }
 | |
| 
 | |
|                     if !Float::eq_repr(quo0, quo1) {
 | |
|                         panic!(
 | |
|                             "{}({:?}, {:?}): std: {:?}, builtins: {:?}",
 | |
|                             stringify!($fn),
 | |
|                             x,
 | |
|                             y,
 | |
|                             quo0,
 | |
|                             quo1
 | |
|                         );
 | |
|                     }
 | |
|                 });
 | |
|             }
 | |
|         )*
 | |
|     };
 | |
| }
 | |
| 
 | |
| #[cfg(not(x86_no_sse))]
 | |
| mod float_div {
 | |
|     use super::*;
 | |
| 
 | |
|     float! {
 | |
|         f32, __divsf3, Single, all();
 | |
|         f64, __divdf3, Double, all();
 | |
|     }
 | |
| 
 | |
|     #[cfg(f128_enabled)]
 | |
|     #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
 | |
|     float! {
 | |
|         f128, __divtf3, Quad,
 | |
|         // FIXME(llvm): there is a bug in LLVM rt.
 | |
|         // See <https://github.com/llvm/llvm-project/issues/91840>.
 | |
|         not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux")));
 | |
|     }
 | |
| 
 | |
|     #[cfg(f128_enabled)]
 | |
|     #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
 | |
|     float! {
 | |
|         f128, __divkf3, Quad, not(feature = "no-sys-f128");
 | |
|     }
 | |
| }
 |