test-quadratic.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include "libgccjit.h"
  4. #include "harness.h"
  5. struct quadratic
  6. {
  7. double a;
  8. double b;
  9. double c;
  10. double discriminant;
  11. };
  12. /* Let's try to inject the equivalent of:
  13. extern double sqrt (double);
  14. static void
  15. calc_discriminant (struct quadratic *q)
  16. {
  17. // (b^2 - 4ac)
  18. q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
  19. }
  20. int
  21. test_quadratic (double a, double b, double c, double *r1, double *r2)
  22. {
  23. struct quadratic q;
  24. q.a = a;
  25. q.b = b;
  26. q.c = c;
  27. calc_discriminant (&q);
  28. if (q.discriminant > 0)
  29. {
  30. double s = sqrt (q.discriminant);
  31. *r1 = (-b + s) / (2 * a);
  32. *r2 = (-b - s) / (2 * a);
  33. return 2;
  34. }
  35. else if (q.discriminant == 0)
  36. {
  37. *r1 = -b / (2 * a);
  38. return 1;
  39. }
  40. else return 0;
  41. }
  42. */
  43. struct quadratic_test
  44. {
  45. gcc_jit_context *ctxt;
  46. /* "double" and "(double *)". */
  47. gcc_jit_type *numeric_type;
  48. gcc_jit_type *numeric_type_ptr;
  49. /* The value (double)0. */
  50. gcc_jit_rvalue *zero;
  51. gcc_jit_type *int_type;
  52. gcc_jit_type *void_type;
  53. /* "struct quadratic" */
  54. gcc_jit_type *quadratic;
  55. gcc_jit_field *a;
  56. gcc_jit_field *b;
  57. gcc_jit_field *c;
  58. gcc_jit_field *discriminant;
  59. /* "(struct quadratic *)" */
  60. gcc_jit_type *quadratic_ptr;
  61. gcc_jit_function *calc_discriminant;
  62. gcc_jit_function *sqrt;
  63. };
  64. static void
  65. make_types (struct quadratic_test *testcase)
  66. {
  67. testcase->numeric_type =
  68. gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_DOUBLE);
  69. testcase->numeric_type_ptr =
  70. gcc_jit_type_get_pointer (testcase->numeric_type);
  71. testcase->zero =
  72. gcc_jit_context_zero (testcase->ctxt, testcase->numeric_type);
  73. testcase->int_type =
  74. gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_INT);
  75. testcase->void_type =
  76. gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_VOID);
  77. testcase->a =
  78. gcc_jit_context_new_field (testcase->ctxt,
  79. NULL,
  80. testcase->numeric_type,
  81. "a");
  82. testcase->b =
  83. gcc_jit_context_new_field (testcase->ctxt,
  84. NULL,
  85. testcase->numeric_type,
  86. "b");
  87. testcase->c =
  88. gcc_jit_context_new_field (testcase->ctxt,
  89. NULL,
  90. testcase->numeric_type,
  91. "c");
  92. testcase->discriminant =
  93. gcc_jit_context_new_field (testcase->ctxt,
  94. NULL,
  95. testcase->numeric_type,
  96. "discriminant");
  97. gcc_jit_field *fields[] = {testcase->a,
  98. testcase->b,
  99. testcase->c,
  100. testcase->discriminant};
  101. testcase->quadratic =
  102. gcc_jit_struct_as_type (
  103. gcc_jit_context_new_struct_type (testcase->ctxt, NULL,
  104. "quadratic", 4, fields));
  105. testcase->quadratic_ptr = gcc_jit_type_get_pointer (testcase->quadratic);
  106. }
  107. static void
  108. make_sqrt (struct quadratic_test *testcase)
  109. {
  110. gcc_jit_param *param_x =
  111. gcc_jit_context_new_param (testcase->ctxt, NULL,
  112. testcase->numeric_type, "x");
  113. testcase->sqrt =
  114. gcc_jit_context_new_function (testcase->ctxt, NULL,
  115. GCC_JIT_FUNCTION_IMPORTED,
  116. testcase->numeric_type,
  117. "sqrt",
  118. 1, &param_x,
  119. 0);
  120. }
  121. static void
  122. make_calc_discriminant (struct quadratic_test *testcase)
  123. {
  124. /* Build "calc_discriminant". */
  125. gcc_jit_param *param_q =
  126. gcc_jit_context_new_param (testcase->ctxt, NULL,
  127. testcase->quadratic_ptr, "q");
  128. testcase->calc_discriminant =
  129. gcc_jit_context_new_function (testcase->ctxt, NULL,
  130. GCC_JIT_FUNCTION_INTERNAL,
  131. testcase->void_type,
  132. "calc_discriminant",
  133. 1, &param_q,
  134. 0);
  135. gcc_jit_block *blk =
  136. gcc_jit_function_new_block (testcase->calc_discriminant, NULL);
  137. gcc_jit_block_add_comment (
  138. blk, NULL,
  139. "(b^2 - 4ac)");
  140. gcc_jit_rvalue *q_a =
  141. gcc_jit_lvalue_as_rvalue (
  142. gcc_jit_rvalue_dereference_field (
  143. gcc_jit_param_as_rvalue (param_q),
  144. NULL, testcase->a));
  145. gcc_jit_rvalue *q_b =
  146. gcc_jit_lvalue_as_rvalue (
  147. gcc_jit_rvalue_dereference_field (
  148. gcc_jit_param_as_rvalue (param_q),
  149. NULL, testcase->b));
  150. gcc_jit_rvalue *q_c =
  151. gcc_jit_lvalue_as_rvalue (
  152. gcc_jit_rvalue_dereference_field (
  153. gcc_jit_param_as_rvalue (param_q),
  154. NULL, testcase->c));
  155. /* (q->b * q->b) - (4 * q->a * q->c) */
  156. gcc_jit_rvalue *rhs =
  157. gcc_jit_context_new_binary_op (
  158. testcase->ctxt, NULL,
  159. GCC_JIT_BINARY_OP_MINUS,
  160. testcase->numeric_type,
  161. /* (q->b * q->b) */
  162. gcc_jit_context_new_binary_op (
  163. testcase->ctxt, NULL,
  164. GCC_JIT_BINARY_OP_MULT,
  165. testcase->numeric_type,
  166. q_b, q_b),
  167. /* (4 * (q->a * q->c)) */
  168. gcc_jit_context_new_binary_op (
  169. testcase->ctxt, NULL,
  170. GCC_JIT_BINARY_OP_MULT,
  171. testcase->numeric_type,
  172. /* 4.0 */
  173. gcc_jit_context_new_rvalue_from_int (
  174. testcase->ctxt,
  175. testcase->numeric_type,
  176. 4),
  177. /* (q->a * q->c) */
  178. gcc_jit_context_new_binary_op (
  179. testcase->ctxt, NULL,
  180. GCC_JIT_BINARY_OP_MULT,
  181. testcase->numeric_type,
  182. q_a, q_c)));
  183. CHECK_STRING_VALUE (
  184. gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (rhs)),
  185. "q->b * q->b - (double)4 * q->a * q->c");
  186. gcc_jit_block_add_assignment (
  187. blk, NULL,
  188. /* q->discriminant =... */
  189. gcc_jit_rvalue_dereference_field (
  190. gcc_jit_param_as_rvalue (param_q),
  191. NULL,
  192. testcase->discriminant),
  193. rhs);
  194. gcc_jit_block_end_with_void_return (blk, NULL);
  195. }
  196. static void
  197. make_test_quadratic (struct quadratic_test *testcase)
  198. {
  199. gcc_jit_param *a =
  200. gcc_jit_context_new_param (testcase->ctxt, NULL,
  201. testcase->numeric_type, "a");
  202. gcc_jit_param *b =
  203. gcc_jit_context_new_param (testcase->ctxt, NULL,
  204. testcase->numeric_type, "b");
  205. gcc_jit_param *c =
  206. gcc_jit_context_new_param (testcase->ctxt, NULL,
  207. testcase->numeric_type, "c");
  208. gcc_jit_param *r1 =
  209. gcc_jit_context_new_param (testcase->ctxt, NULL,
  210. testcase->numeric_type_ptr, "r1");
  211. gcc_jit_param *r2 =
  212. gcc_jit_context_new_param (testcase->ctxt, NULL,
  213. testcase->numeric_type_ptr, "r2");
  214. gcc_jit_param *params[] = {a, b, c, r1, r2};
  215. gcc_jit_function *test_quadratic =
  216. gcc_jit_context_new_function (testcase->ctxt, NULL,
  217. GCC_JIT_FUNCTION_EXPORTED,
  218. testcase->int_type,
  219. "test_quadratic",
  220. 5, params,
  221. 0);
  222. /* struct quadratic q; */
  223. gcc_jit_lvalue *q =
  224. gcc_jit_function_new_local (
  225. test_quadratic, NULL,
  226. testcase->quadratic,
  227. "q");
  228. gcc_jit_block *initial =
  229. gcc_jit_function_new_block (test_quadratic,
  230. "initial");
  231. gcc_jit_block *on_positive_discriminant
  232. = gcc_jit_function_new_block (test_quadratic,
  233. "positive_discriminant");
  234. gcc_jit_block *on_nonpositive_discriminant
  235. = gcc_jit_function_new_block (test_quadratic,
  236. "nonpositive_discriminant");
  237. gcc_jit_block *on_zero_discriminant
  238. = gcc_jit_function_new_block (test_quadratic,
  239. "zero_discriminant");
  240. gcc_jit_block *on_negative_discriminant
  241. = gcc_jit_function_new_block (test_quadratic,
  242. "negative_discriminant");
  243. /* Initial block. */
  244. /* q.a = a; */
  245. gcc_jit_block_add_assignment (
  246. initial, NULL,
  247. gcc_jit_lvalue_access_field (q, NULL, testcase->a),
  248. gcc_jit_param_as_rvalue (a));
  249. /* q.b = b; */
  250. gcc_jit_block_add_assignment (
  251. initial, NULL,
  252. gcc_jit_lvalue_access_field (q, NULL, testcase->b),
  253. gcc_jit_param_as_rvalue (b));
  254. /* q.c = c; */
  255. gcc_jit_block_add_assignment (
  256. initial, NULL,
  257. gcc_jit_lvalue_access_field (q, NULL, testcase->c),
  258. gcc_jit_param_as_rvalue (c));
  259. /* calc_discriminant (&q); */
  260. gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
  261. gcc_jit_block_add_eval (
  262. initial, NULL,
  263. gcc_jit_context_new_call (
  264. testcase->ctxt, NULL,
  265. testcase->calc_discriminant,
  266. 1, &address_of_q));
  267. gcc_jit_block_add_comment (
  268. initial, NULL,
  269. "if (q.discriminant > 0)");
  270. gcc_jit_block_end_with_conditional (
  271. initial, NULL,
  272. gcc_jit_context_new_comparison (
  273. testcase->ctxt, NULL,
  274. GCC_JIT_COMPARISON_GT,
  275. gcc_jit_rvalue_access_field (
  276. gcc_jit_lvalue_as_rvalue (q),
  277. NULL,
  278. testcase->discriminant),
  279. testcase->zero),
  280. on_positive_discriminant,
  281. on_nonpositive_discriminant);
  282. /* Block: "on_positive_discriminant" */
  283. /* double s = sqrt (q.discriminant); */
  284. gcc_jit_lvalue *s = gcc_jit_function_new_local (
  285. test_quadratic, NULL,
  286. testcase->numeric_type,
  287. "s");
  288. gcc_jit_rvalue *discriminant_of_q =
  289. gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
  290. NULL,
  291. testcase->discriminant);
  292. gcc_jit_block_add_assignment (
  293. on_positive_discriminant, NULL,
  294. s,
  295. gcc_jit_context_new_call (
  296. testcase->ctxt, NULL,
  297. testcase->sqrt,
  298. 1, &discriminant_of_q));
  299. gcc_jit_rvalue *minus_b =
  300. gcc_jit_context_new_unary_op (
  301. testcase->ctxt, NULL,
  302. GCC_JIT_UNARY_OP_MINUS,
  303. testcase->numeric_type,
  304. gcc_jit_param_as_rvalue (b));
  305. gcc_jit_rvalue *two_a =
  306. gcc_jit_context_new_binary_op (
  307. testcase->ctxt, NULL,
  308. GCC_JIT_BINARY_OP_MULT,
  309. testcase->numeric_type,
  310. gcc_jit_context_new_rvalue_from_int (
  311. testcase->ctxt,
  312. testcase->numeric_type,
  313. 2),
  314. gcc_jit_param_as_rvalue (a));
  315. gcc_jit_block_add_comment (
  316. on_positive_discriminant, NULL,
  317. "*r1 = (-b + s) / (2 * a);");
  318. gcc_jit_block_add_assignment (
  319. on_positive_discriminant, NULL,
  320. /* "*r1 = ..." */
  321. gcc_jit_rvalue_dereference (
  322. gcc_jit_param_as_rvalue (r1), NULL),
  323. /* (-b + s) / (2 * a) */
  324. gcc_jit_context_new_binary_op (
  325. testcase->ctxt, NULL,
  326. GCC_JIT_BINARY_OP_DIVIDE,
  327. testcase->numeric_type,
  328. gcc_jit_context_new_binary_op (
  329. testcase->ctxt, NULL,
  330. GCC_JIT_BINARY_OP_PLUS,
  331. testcase->numeric_type,
  332. minus_b,
  333. gcc_jit_lvalue_as_rvalue (s)),
  334. two_a));
  335. gcc_jit_block_add_comment (
  336. on_positive_discriminant, NULL,
  337. "*r2 = (-b - s) / (2 * a)");
  338. gcc_jit_block_add_assignment (
  339. on_positive_discriminant, NULL,
  340. /* "*r2 = ..." */
  341. gcc_jit_rvalue_dereference (
  342. gcc_jit_param_as_rvalue (r2), NULL),
  343. /* (-b - s) / (2 * a) */
  344. gcc_jit_context_new_binary_op (
  345. testcase->ctxt, NULL,
  346. GCC_JIT_BINARY_OP_DIVIDE,
  347. testcase->numeric_type,
  348. gcc_jit_context_new_binary_op (
  349. testcase->ctxt, NULL,
  350. GCC_JIT_BINARY_OP_MINUS,
  351. testcase->numeric_type,
  352. minus_b,
  353. gcc_jit_lvalue_as_rvalue (s)),
  354. two_a));
  355. /* "return 2;" */
  356. gcc_jit_block_end_with_return (
  357. on_positive_discriminant, NULL,
  358. gcc_jit_context_new_rvalue_from_int (
  359. testcase->ctxt,
  360. testcase->int_type,
  361. 2));
  362. /* Block: "on_nonpositive_discriminant" */
  363. gcc_jit_block_add_comment (
  364. on_nonpositive_discriminant, NULL,
  365. "else if (q.discriminant == 0)");
  366. gcc_jit_block_end_with_conditional (
  367. on_nonpositive_discriminant, NULL,
  368. gcc_jit_context_new_comparison (
  369. testcase->ctxt, NULL,
  370. GCC_JIT_COMPARISON_EQ,
  371. gcc_jit_rvalue_access_field (
  372. gcc_jit_lvalue_as_rvalue (q),
  373. NULL,
  374. testcase->discriminant),
  375. testcase->zero),
  376. on_zero_discriminant,
  377. on_negative_discriminant);
  378. /* Block: "on_zero_discriminant" */
  379. gcc_jit_block_add_comment (
  380. on_zero_discriminant, NULL,
  381. "*r1 = -b / (2 * a);");
  382. gcc_jit_block_add_assignment (
  383. on_zero_discriminant, NULL,
  384. /* "*r1 = ..." */
  385. gcc_jit_rvalue_dereference (
  386. gcc_jit_param_as_rvalue (r1), NULL),
  387. /* -b / (2 * a) */
  388. gcc_jit_context_new_binary_op (
  389. testcase->ctxt, NULL,
  390. GCC_JIT_BINARY_OP_DIVIDE,
  391. testcase->numeric_type,
  392. minus_b,
  393. two_a));
  394. gcc_jit_block_end_with_return (
  395. /* "return 1;" */
  396. on_zero_discriminant, NULL,
  397. gcc_jit_context_one (testcase->ctxt, testcase->int_type));
  398. /* Block: "on_negative_discriminant" */
  399. gcc_jit_block_end_with_return (
  400. /* "else return 0;" */
  401. on_negative_discriminant, NULL,
  402. gcc_jit_context_zero (testcase->ctxt, testcase->int_type));
  403. }
  404. void
  405. create_code (gcc_jit_context *ctxt, void *user_data)
  406. {
  407. struct quadratic_test testcase;
  408. memset (&testcase, 0, sizeof (testcase));
  409. testcase.ctxt = ctxt;
  410. make_types (&testcase);
  411. make_sqrt (&testcase);
  412. make_calc_discriminant (&testcase);
  413. make_test_quadratic (&testcase);
  414. }
  415. void
  416. verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
  417. {
  418. typedef int (*fn_type) (double a, double b, double c,
  419. double *r1, double *r2);
  420. CHECK_NON_NULL (result);
  421. fn_type test_quadratic =
  422. (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
  423. CHECK_NON_NULL (test_quadratic);
  424. /* Verify that the code correctly solves quadratic equations. */
  425. double r1, r2;
  426. /* This one has two solutions: */
  427. CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
  428. CHECK_VALUE (r1, 1);
  429. CHECK_VALUE (r2, -4);
  430. /* This one has one solution: */
  431. CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
  432. CHECK_VALUE (r1, -0.5);
  433. /* This one has no real solutions: */
  434. CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
  435. }