div_rem.rs 4.7 KB

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