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