test-quadratic.cc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /* Test of C++ API. */
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include "libgccjit++.h"
  5. #include <sstream>
  6. #include "harness.h"
  7. struct quadratic
  8. {
  9. double a;
  10. double b;
  11. double c;
  12. double discriminant;
  13. };
  14. /* As per test-quadratic.c, let's try to inject the equivalent of:
  15. extern double sqrt (double);
  16. void
  17. calc_discriminant (struct quadratic *q)
  18. {
  19. // (b^2 - 4ac)
  20. q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
  21. }
  22. int
  23. test_quadratic (double a, double b, double c, double *r1, double *r2)
  24. {
  25. struct quadratic q;
  26. q.a = a;
  27. q.b = b;
  28. q.c = c;
  29. calc_discriminant (&q);
  30. if (q.discriminant > 0)
  31. {
  32. double s = sqrt (q.discriminant);
  33. *r1 = (-b + s) / (2 * a);
  34. *r2 = (-b - s) / (2 * a);
  35. return 2;
  36. }
  37. else if (q.discriminant == 0)
  38. {
  39. *r1 = -b / (2 * a);
  40. return 1;
  41. }
  42. else return 0;
  43. }
  44. However, we'll use the C++ bindings.
  45. */
  46. /****************************************************************************
  47. Test case
  48. ****************************************************************************/
  49. struct quadratic_test
  50. {
  51. gccjit::context ctxt;
  52. /* "double" and "(double *)". */
  53. gccjit::type numeric_type;
  54. gccjit::type numeric_type_ptr;
  55. /* The value (double)0. */
  56. gccjit::rvalue zero;
  57. gccjit::type int_type;
  58. gccjit::type void_type;
  59. /* "struct quadratic" */
  60. gccjit::type quadratic;
  61. gccjit::field a;
  62. gccjit::field b;
  63. gccjit::field c;
  64. gccjit::field discriminant;
  65. /* "(struct quadratic *)" */
  66. gccjit::type quadratic_ptr;
  67. gccjit::function calc_discriminant;
  68. gccjit::function sqrt;
  69. };
  70. static void
  71. make_types (quadratic_test &testcase)
  72. {
  73. testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE);
  74. testcase.numeric_type_ptr = testcase.numeric_type.get_pointer ();
  75. testcase.zero = testcase.ctxt.zero (testcase.numeric_type);
  76. testcase.int_type = testcase.ctxt.get_int_type <int> ();
  77. testcase.void_type = testcase.ctxt.get_type (GCC_JIT_TYPE_VOID);
  78. testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a");
  79. testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b");
  80. testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c");
  81. testcase.discriminant =
  82. testcase.ctxt.new_field (testcase.numeric_type, "discriminant");
  83. CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (),
  84. "discriminant");
  85. std::vector<gccjit::field> fields (4);
  86. fields[0] = testcase.a;
  87. fields[1] = testcase.b;
  88. fields[2] = testcase.c;
  89. fields[3] = testcase.discriminant;
  90. testcase.quadratic =
  91. testcase.ctxt.new_struct_type (
  92. "quadratic",
  93. fields);
  94. testcase.quadratic_ptr = testcase.quadratic.get_pointer ();
  95. }
  96. static void
  97. make_sqrt (quadratic_test &testcase)
  98. {
  99. std::vector<gccjit::param> params (1);
  100. params[0] =
  101. testcase.ctxt.new_param (testcase.numeric_type, "x");
  102. testcase.sqrt =
  103. testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
  104. testcase.numeric_type,
  105. "sqrt",
  106. params,
  107. 0);
  108. }
  109. static void
  110. make_calc_discriminant (quadratic_test &testcase)
  111. {
  112. /* Build "calc_discriminant". */
  113. gccjit::param param_q =
  114. testcase.ctxt.new_param (testcase.quadratic_ptr, "q");
  115. std::vector <gccjit::param> params (1);
  116. params[0] = param_q;
  117. testcase.calc_discriminant =
  118. testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
  119. testcase.void_type,
  120. "calc_discriminant",
  121. params,
  122. 0);
  123. gccjit::block block = testcase.calc_discriminant.new_block ();
  124. block.add_comment ("(b^2 - 4ac)");
  125. gccjit::rvalue q_a = param_q.dereference_field (testcase.a);
  126. gccjit::rvalue q_b = param_q.dereference_field (testcase.b);
  127. gccjit::rvalue q_c = param_q.dereference_field (testcase.c);
  128. block.add_assignment (
  129. /* q->discriminant =... */
  130. param_q.dereference_field (testcase.discriminant),
  131. /* (q->b * q->b) - (4 * q->a * q->c) */
  132. testcase.ctxt.new_minus (
  133. testcase.numeric_type,
  134. /* (q->b * q->b) */
  135. testcase.ctxt.new_mult (
  136. testcase.numeric_type,
  137. q_b, q_b),
  138. /* (4 * (q->a * q->c)) */
  139. testcase.ctxt.new_mult (
  140. testcase.numeric_type,
  141. /* 4.0 */
  142. testcase.ctxt.new_rvalue (
  143. testcase.numeric_type,
  144. 4),
  145. /* (q->a * q->c) */
  146. testcase.ctxt.new_mult (
  147. testcase.numeric_type,
  148. q_a, q_c)))); /* end of add_assignment call. */
  149. block.end_with_return ();
  150. }
  151. static void
  152. make_test_quadratic (quadratic_test &testcase)
  153. {
  154. gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a");
  155. gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b");
  156. gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c");
  157. gccjit::param r1 =
  158. testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1");
  159. gccjit::param r2 =
  160. testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2");
  161. std::vector<gccjit::param> params (5);
  162. params[0] = a;
  163. params[1] = b;
  164. params[2] = c;
  165. params[3] = r1;
  166. params[4] = r2;
  167. gccjit::function test_quadratic =
  168. testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
  169. testcase.int_type,
  170. "test_quadratic",
  171. params,
  172. 0);
  173. /* struct quadratic q; */
  174. gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q");
  175. gccjit::block initial = test_quadratic.new_block ("initial");
  176. gccjit::block on_positive_discriminant
  177. = test_quadratic.new_block ("positive_discriminant");
  178. gccjit::block on_nonpositive_discriminant
  179. = test_quadratic.new_block ("nonpositive_discriminant");
  180. gccjit::block on_zero_discriminant
  181. = test_quadratic.new_block ("zero_discriminant");
  182. gccjit::block on_negative_discriminant
  183. = test_quadratic.new_block ("negative_discriminant");
  184. CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (),
  185. "zero_discriminant");
  186. /* q.a = a; */
  187. initial.add_assignment (q.access_field (testcase.a), a);
  188. /* q.b = b; */
  189. initial.add_assignment (q.access_field (testcase.b), b);
  190. /* q.c = c; */
  191. initial.add_assignment (q.access_field (testcase.c), c);
  192. /* calc_discriminant (&q); */
  193. gccjit::rvalue address_of_q = q.get_address ();
  194. initial.add_call (testcase.calc_discriminant, address_of_q);
  195. initial.add_comment ("if (q.discriminant > 0)");
  196. initial.end_with_conditional (
  197. testcase.ctxt.new_gt (
  198. q.access_field (testcase.discriminant),
  199. testcase.zero),
  200. on_positive_discriminant,
  201. on_nonpositive_discriminant);
  202. /* Block: "on_positive_discriminant" */
  203. /* double s = sqrt (q.discriminant); */
  204. gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s");
  205. gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant);
  206. on_positive_discriminant.add_assignment (
  207. s,
  208. testcase.ctxt.new_call (testcase.sqrt, discriminant_of_q));
  209. gccjit::rvalue minus_b =
  210. testcase.ctxt.new_minus (
  211. testcase.numeric_type,
  212. b);
  213. gccjit::rvalue two_a =
  214. testcase.ctxt.new_mult (
  215. testcase.numeric_type,
  216. testcase.ctxt.new_rvalue (testcase.numeric_type, 2),
  217. a);
  218. CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (),
  219. "(double)2 * a");
  220. on_positive_discriminant.add_comment ("*r1 = (-b + s) / (2 * a);");
  221. on_positive_discriminant.add_assignment (
  222. /* "*r1 = ..." */
  223. r1.dereference (),
  224. /* (-b + s) / (2 * a) */
  225. testcase.ctxt.new_divide (
  226. testcase.numeric_type,
  227. testcase.ctxt.new_plus (
  228. testcase.numeric_type,
  229. minus_b,
  230. s),
  231. two_a));
  232. on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)");
  233. on_positive_discriminant.add_assignment (
  234. /* "*r2 = ..." */
  235. r2.dereference (),
  236. /* (-b - s) / (2 * a) */
  237. testcase.ctxt.new_divide (
  238. testcase.numeric_type,
  239. testcase.ctxt.new_minus (
  240. testcase.numeric_type,
  241. minus_b,
  242. s),
  243. two_a));
  244. /* "return 2;" */
  245. on_positive_discriminant.end_with_return (
  246. testcase.ctxt.new_rvalue (testcase.int_type, 2));
  247. /* Block: "on_nonpositive_discriminant" */
  248. on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)");
  249. on_nonpositive_discriminant.end_with_conditional (
  250. testcase.ctxt.new_eq (
  251. q.access_field (testcase.discriminant),
  252. testcase.zero),
  253. on_zero_discriminant,
  254. on_negative_discriminant);
  255. /* Block: "on_zero_discriminant" */
  256. /* if (q.discriminant == 0) */
  257. on_zero_discriminant.add_comment ("*r1 = -b / (2 * a);");
  258. on_zero_discriminant.add_assignment (
  259. /* "*r1 = ..." */
  260. r1.dereference (),
  261. /* -b / (2 * a) */
  262. testcase.ctxt.new_divide (
  263. testcase.numeric_type,
  264. minus_b,
  265. two_a));
  266. /* "return 1;" */
  267. on_zero_discriminant.end_with_return (
  268. testcase.ctxt.one (testcase.int_type));
  269. /* Block: "on_negative_discriminant" */
  270. /* else return 0; */
  271. on_negative_discriminant.end_with_return (
  272. testcase.ctxt.zero (testcase.int_type));
  273. /* Verify that output stream operator << works. */
  274. std::ostringstream os;
  275. os << "streamed output: " << address_of_q;
  276. CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q");
  277. }
  278. void
  279. create_code (gcc_jit_context *ctxt, void *user_data)
  280. {
  281. struct quadratic_test testcase;
  282. memset (&testcase, 0, sizeof (testcase));
  283. testcase.ctxt = ctxt;
  284. make_types (testcase);
  285. make_sqrt (testcase);
  286. make_calc_discriminant (testcase);
  287. make_test_quadratic (testcase);
  288. }
  289. void
  290. verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
  291. {
  292. typedef int (*fn_type) (double a, double b, double c,
  293. double *r1, double *r2);
  294. CHECK_NON_NULL (result);
  295. fn_type test_quadratic =
  296. (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
  297. CHECK_NON_NULL (test_quadratic);
  298. /* Verify that the code correctly solves quadratic equations. */
  299. double r1, r2;
  300. /* This one has two solutions: */
  301. CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
  302. CHECK_VALUE (r1, 1);
  303. CHECK_VALUE (r2, -4);
  304. /* This one has one solution: */
  305. CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
  306. CHECK_VALUE (r1, -0.5);
  307. /* This one has no real solutions: */
  308. CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
  309. }