qc.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // When testing functions, QuickCheck (QC) uses small values for integer (`u*`/`i*`) arguments
  2. // (~ `[-100, 100]`), but these values don't stress all the code paths in our intrinsics. Here we
  3. // create newtypes over the primitive integer types with the goal of having full control over the
  4. // random values that will be used to test our intrinsics.
  5. use std::boxed::Box;
  6. use std::fmt;
  7. use core::{f32, f64};
  8. use quickcheck::{Arbitrary, Gen};
  9. use int::LargeInt;
  10. use float::Float;
  11. // Generates values in the full range of the integer type
  12. macro_rules! arbitrary {
  13. ($TY:ident : $ty:ident) => {
  14. #[derive(Clone, Copy)]
  15. pub struct $TY(pub $ty);
  16. impl Arbitrary for $TY {
  17. fn arbitrary<G>(g: &mut G) -> $TY
  18. where G: Gen
  19. {
  20. // NOTE Generate edge cases with a 10% chance
  21. let t = if g.gen_weighted_bool(10) {
  22. *g.choose(&[
  23. $ty::min_value(),
  24. 0,
  25. $ty::max_value(),
  26. ]).unwrap()
  27. } else {
  28. g.gen()
  29. };
  30. $TY(t)
  31. }
  32. fn shrink(&self) -> Box<Iterator<Item=$TY>> {
  33. struct Shrinker {
  34. x: $ty,
  35. }
  36. impl Iterator for Shrinker {
  37. type Item = $TY;
  38. fn next(&mut self) -> Option<$TY> {
  39. self.x /= 2;
  40. if self.x == 0 {
  41. None
  42. } else {
  43. Some($TY(self.x))
  44. }
  45. }
  46. }
  47. if self.0 == 0 {
  48. ::quickcheck::empty_shrinker()
  49. } else {
  50. Box::new(Shrinker { x: self.0 })
  51. }
  52. }
  53. }
  54. impl fmt::Debug for $TY {
  55. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  56. fmt::Debug::fmt(&self.0, f)
  57. }
  58. }
  59. }
  60. }
  61. arbitrary!(I32: i32);
  62. arbitrary!(U32: u32);
  63. // These integers are "too large". If we generate e.g. `u64` values in the full range then there's
  64. // only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits)
  65. // is `0`)! But this is an important group of values to tests because we have special code paths for
  66. // them. Instead we'll generate e.g. `u64` integers this way: uniformly pick between (a) setting the
  67. // low word to 0 and generating a random high word, (b) vice versa: high word to 0 and random low
  68. // word or (c) generate both words randomly. This let's cover better the code paths in our
  69. // intrinsics.
  70. macro_rules! arbitrary_large {
  71. ($TY:ident : $ty:ident) => {
  72. #[derive(Clone, Copy)]
  73. pub struct $TY(pub $ty);
  74. impl Arbitrary for $TY {
  75. fn arbitrary<G>(g: &mut G) -> $TY
  76. where G: Gen
  77. {
  78. // NOTE Generate edge cases with a 10% chance
  79. let t = if g.gen_weighted_bool(10) {
  80. *g.choose(&[
  81. $ty::min_value(),
  82. 0,
  83. $ty::max_value(),
  84. ]).unwrap()
  85. } else {
  86. match g.gen_range(0, 3) {
  87. 0 => $ty::from_parts(g.gen(), g.gen()),
  88. 1 => $ty::from_parts(0, g.gen()),
  89. 2 => $ty::from_parts(g.gen(), 0),
  90. _ => unreachable!(),
  91. }
  92. };
  93. $TY(t)
  94. }
  95. fn shrink(&self) -> Box<Iterator<Item=$TY>> {
  96. struct Shrinker {
  97. x: $ty,
  98. }
  99. impl Iterator for Shrinker {
  100. type Item = $TY;
  101. fn next(&mut self) -> Option<$TY> {
  102. self.x /= 2;
  103. if self.x == 0 {
  104. None
  105. } else {
  106. Some($TY(self.x))
  107. }
  108. }
  109. }
  110. if self.0 == 0 {
  111. ::quickcheck::empty_shrinker()
  112. } else {
  113. Box::new(Shrinker { x: self.0 })
  114. }
  115. }
  116. }
  117. impl fmt::Debug for $TY {
  118. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  119. fmt::Debug::fmt(&self.0, f)
  120. }
  121. }
  122. }
  123. }
  124. arbitrary_large!(I64: i64);
  125. arbitrary_large!(U64: u64);
  126. macro_rules! arbitrary_float {
  127. ($TY:ident : $ty:ident) => {
  128. #[derive(Clone, Copy)]
  129. pub struct $TY(pub $ty);
  130. impl Arbitrary for $TY {
  131. fn arbitrary<G>(g: &mut G) -> $TY
  132. where G: Gen
  133. {
  134. let special = [
  135. -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY
  136. ];
  137. if g.gen_weighted_bool(10) { // Random special case
  138. $TY(*g.choose(&special).unwrap())
  139. } else if g.gen_weighted_bool(10) { // NaN variants
  140. let sign: bool = g.gen();
  141. let exponent: <$ty as Float>::Int = g.gen();
  142. let significand: <$ty as Float>::Int = 0;
  143. $TY($ty::from_parts(sign, exponent, significand))
  144. } else if g.gen() { // Denormalized
  145. let sign: bool = g.gen();
  146. let exponent: <$ty as Float>::Int = 0;
  147. let significand: <$ty as Float>::Int = g.gen();
  148. $TY($ty::from_parts(sign, exponent, significand))
  149. } else { // Random anything
  150. let sign: bool = g.gen();
  151. let exponent: <$ty as Float>::Int = g.gen();
  152. let significand: <$ty as Float>::Int = g.gen();
  153. $TY($ty::from_parts(sign, exponent, significand))
  154. }
  155. }
  156. fn shrink(&self) -> Box<Iterator<Item=$TY>> {
  157. ::quickcheck::empty_shrinker()
  158. }
  159. }
  160. impl fmt::Debug for $TY {
  161. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  162. fmt::Debug::fmt(&self.0, f)
  163. }
  164. }
  165. impl PartialEq for $TY {
  166. fn eq(&self, other: &$TY) -> bool {
  167. self.0.eq_repr(other.0)
  168. }
  169. }
  170. }
  171. }
  172. arbitrary_float!(F32: f32);
  173. arbitrary_float!(F64: f64);
  174. // Convenience macro to test intrinsics against their reference implementations.
  175. //
  176. // Each intrinsic is tested against both the `gcc_s` library as well as
  177. // `compiler-rt`. These libraries are defined in the `gcc_s` crate as well as
  178. // the `compiler-rt` crate in this repository. Both load a dynamic library and
  179. // lookup symbols through that dynamic library to ensure that we're using the
  180. // right intrinsic.
  181. //
  182. // This macro hopefully allows you to define a bare minimum of how to test an
  183. // intrinsic without worrying about these implementation details. A sample
  184. // invocation looks like:
  185. //
  186. //
  187. // check! {
  188. // // First argument is the function we're testing (either from this lib
  189. // // or a dynamically loaded one. Further arguments are all generated by
  190. // // quickcheck.
  191. // fn __my_intrinsic(f: extern fn(i32) -> i32,
  192. // a: I32)
  193. // -> Option<(i32, i64)> {
  194. //
  195. // // Discard tests by returning Some
  196. // if a.0 == 0 {
  197. // return None
  198. // }
  199. //
  200. // // Return the result via `Some` if the test can run
  201. // let mut other_result = 0;
  202. // let result = f(a.0, &mut other_result);
  203. // Some((result, other_result))
  204. // }
  205. // }
  206. //
  207. // If anything returns `None` then the test is discarded, otherwise the two
  208. // results are compared for equality and the test fails if this equality check
  209. // fails.
  210. macro_rules! check {
  211. ($(
  212. fn $name:ident($f:ident: extern fn($($farg:ty),*) -> $fret:ty,
  213. $($arg:ident: $t:ty),*)
  214. -> Option<$ret:ty>
  215. {
  216. $($code:tt)*
  217. }
  218. )*) => (
  219. $(
  220. fn $name($f: extern fn($($farg),*) -> $fret,
  221. $($arg: $t),*) -> Option<$ret> {
  222. $($code)*
  223. }
  224. )*
  225. mod _test {
  226. use qc::*;
  227. use std::mem;
  228. use quickcheck::TestResult;
  229. $(
  230. #[test]
  231. fn $name() {
  232. fn my_check($($arg:$t),*) -> TestResult {
  233. let my_answer = super::$name(super::super::$name,
  234. $($arg),*);
  235. let compiler_rt_fn = ::compiler_rt::get(stringify!($name));
  236. let compiler_rt_answer = unsafe {
  237. super::$name(mem::transmute(compiler_rt_fn),
  238. $($arg),*)
  239. };
  240. let gcc_s_answer =
  241. match ::gcc_s::get(stringify!($name)) {
  242. Some(f) => unsafe {
  243. Some(super::$name(mem::transmute(f),
  244. $($arg),*))
  245. },
  246. None => None,
  247. };
  248. let print_values = || {
  249. print!("{} - Args: ", stringify!($name));
  250. $(print!("{:?} ", $arg);)*
  251. print!("\n");
  252. println!(" compiler-builtins: {:?}", my_answer);
  253. println!(" compiler_rt: {:?}", compiler_rt_answer);
  254. println!(" gcc_s: {:?}", gcc_s_answer);
  255. };
  256. if my_answer != compiler_rt_answer {
  257. print_values();
  258. TestResult::from_bool(false)
  259. } else if gcc_s_answer.is_some() &&
  260. my_answer != gcc_s_answer.unwrap() {
  261. print_values();
  262. TestResult::from_bool(false)
  263. } else {
  264. TestResult::from_bool(true)
  265. }
  266. }
  267. ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult)
  268. }
  269. )*
  270. }
  271. )
  272. }