div_rem.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #![allow(unused_macros)]
  2. use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4};
  3. use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc};
  4. use testcrate::*;
  5. // Division algorithms have by far the nastiest and largest number of edge cases, and experience shows
  6. // that sometimes 100_000 iterations of the random fuzzer is needed.
  7. /// Creates intensive test functions for division functions of a certain size
  8. macro_rules! test {
  9. (
  10. $n:expr, // the number of bits in a $iX or $uX
  11. $uX:ident, // unsigned integer that will be shifted
  12. $iX:ident, // signed version of $uX
  13. $test_name:ident, // name of the test function
  14. $unsigned_name:ident, // unsigned division function
  15. $signed_name:ident // signed division function
  16. ) => {
  17. #[test]
  18. fn $test_name() {
  19. fuzz_2(N, |lhs, rhs| {
  20. if rhs == 0 {
  21. return;
  22. }
  23. let mut rem: $uX = 0;
  24. let quo: $uX = $unsigned_name(lhs, rhs, Some(&mut rem));
  25. if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) {
  26. panic!(
  27. "unsigned division function failed with lhs:{} rhs:{} \
  28. std:({}, {}) builtins:({}, {})",
  29. lhs,
  30. rhs,
  31. lhs.wrapping_div(rhs),
  32. lhs.wrapping_rem(rhs),
  33. quo,
  34. rem
  35. );
  36. }
  37. // test the signed division function also
  38. let lhs = lhs as $iX;
  39. let rhs = rhs as $iX;
  40. let mut rem: $iX = 0;
  41. let quo: $iX = $signed_name(lhs, rhs, &mut rem);
  42. // We cannot just test that
  43. // `lhs == rhs.wrapping_mul(quo).wrapping_add(rem)`, but also
  44. // need to make sure the remainder isn't larger than the divisor
  45. // and has the correct sign.
  46. let incorrect_rem = if rem == 0 {
  47. false
  48. } else if rhs == $iX::MIN {
  49. // `rhs.wrapping_abs()` would overflow, so handle this case
  50. // separately.
  51. (lhs.is_negative() != rem.is_negative()) || (rem == $iX::MIN)
  52. } else {
  53. (lhs.is_negative() != rem.is_negative())
  54. || (rhs.wrapping_abs() <= rem.wrapping_abs())
  55. };
  56. if incorrect_rem || lhs != rhs.wrapping_mul(quo).wrapping_add(rem) {
  57. panic!(
  58. "signed division function failed with lhs:{} rhs:{} \
  59. std:({}, {}) builtins:({}, {})",
  60. lhs,
  61. rhs,
  62. lhs.wrapping_div(rhs),
  63. lhs.wrapping_rem(rhs),
  64. quo,
  65. rem
  66. );
  67. }
  68. });
  69. }
  70. };
  71. }
  72. test!(32, u32, i32, div_rem_si4, __udivmodsi4, __divmodsi4);
  73. test!(64, u64, i64, div_rem_di4, __udivmoddi4, __divmoddi4);
  74. test!(128, u128, i128, div_rem_ti4, __udivmodti4, __divmodti4);
  75. #[test]
  76. fn divide_sparc() {
  77. fuzz_2(N, |lhs, rhs| {
  78. if rhs == 0 {
  79. return;
  80. }
  81. let mut rem: u128 = 0;
  82. let quo: u128 = u128_divide_sparc(lhs, rhs, &mut rem);
  83. if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) {
  84. panic!(
  85. "u128_divide_sparc({}, {}): \
  86. std:({}, {}), builtins:({}, {})",
  87. lhs,
  88. rhs,
  89. lhs.wrapping_div(rhs),
  90. lhs.wrapping_rem(rhs),
  91. quo,
  92. rem
  93. );
  94. }
  95. });
  96. }
  97. macro_rules! float {
  98. ($($i:ty, $fn:ident);*;) => {
  99. $(
  100. fuzz_float_2(N, |x: $i, y: $i| {
  101. let quo0 = x / y;
  102. let quo1: $i = $fn(x, y);
  103. // division of subnormals is not currently handled
  104. if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) {
  105. if !Float::eq_repr(quo0, quo1) {
  106. panic!(
  107. "{}({}, {}): std: {}, builtins: {}",
  108. stringify!($fn), x, y, quo0, quo1
  109. );
  110. }
  111. }
  112. });
  113. )*
  114. };
  115. }
  116. #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
  117. #[test]
  118. fn float_div() {
  119. use compiler_builtins::float::{
  120. div::{__divdf3, __divsf3},
  121. Float,
  122. };
  123. float!(
  124. f32, __divsf3;
  125. f64, __divdf3;
  126. );
  127. }
  128. #[cfg(target_arch = "arm")]
  129. #[test]
  130. fn float_div_arm() {
  131. use compiler_builtins::float::{
  132. div::{__divdf3vfp, __divsf3vfp},
  133. Float,
  134. };
  135. float!(
  136. f32, __divsf3vfp;
  137. f64, __divdf3vfp;
  138. );
  139. }