5 #include "libgccjit++.h"
19 /* As per test-quadratic.cc, let's try to inject the equivalent of:
21 extern double sqrt (double);
24 calc_discriminant (struct quadratic *q)
27 q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
31 test_quadratic (double a, double b, double c, double *r1, double *r2)
37 calc_discriminant (&q);
38 if (q.discriminant > 0)
40 double s = sqrt (q.discriminant);
41 *r1 = (-b + s) / (2 * a);
42 *r2 = (-b - s) / (2 * a);
45 else if (q.discriminant == 0)
53 However, we'll use operator overloading for maxium brevity, at the
54 risk of perhaps being too "magical".
57 /****************************************************************************
59 ****************************************************************************/
65 /* "double" and "(double *)". */
66 gccjit::type numeric_type
;
67 gccjit::type numeric_type_ptr
;
69 /* The value (double)0. */
72 gccjit::type int_type
;
73 gccjit::type void_type
;
75 /* "struct quadratic" */
76 gccjit::type quadratic
;
80 gccjit::field discriminant
;
82 /* "(struct quadratic *)" */
83 gccjit::type quadratic_ptr
;
85 gccjit::function calc_discriminant
;
87 gccjit::function sqrt
;
92 make_types (quadratic_test
&testcase
)
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
);
98 testcase
.int_type
= testcase
.ctxt
.get_int_type
<int> ();
99 testcase
.void_type
= testcase
.ctxt
.get_type (GCC_JIT_TYPE_VOID
);
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 (),
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
;
114 testcase
.ctxt
.new_struct_type (
117 testcase
.quadratic_ptr
= testcase
.quadratic
.get_pointer ();
121 make_sqrt (quadratic_test
&testcase
)
123 std::vector
<gccjit::param
> params (1);
125 testcase
.ctxt
.new_param (testcase
.numeric_type
, "x");
127 testcase
.ctxt
.new_function (GCC_JIT_FUNCTION_IMPORTED
,
128 testcase
.numeric_type
,
135 make_calc_discriminant (quadratic_test
&testcase
)
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);
142 testcase
.calc_discriminant
=
143 testcase
.ctxt
.new_function (GCC_JIT_FUNCTION_EXPORTED
,
148 gccjit::block block
= testcase
.calc_discriminant
.new_block ();
149 block
.add_comment ("(b^2 - 4ac)");
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
);
155 gccjit::rvalue four
=
156 testcase
.ctxt
.new_rvalue (testcase
.numeric_type
, 4);
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 ();
167 make_test_quadratic (quadratic_test
&testcase
)
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");
173 testcase
.ctxt
.new_param (testcase
.numeric_type_ptr
, "r1");
175 testcase
.ctxt
.new_param (testcase
.numeric_type_ptr
, "r2");
177 std::vector
<gccjit::param
> params (5);
184 gccjit::function test_quadratic
=
185 testcase
.ctxt
.new_function (GCC_JIT_FUNCTION_EXPORTED
,
191 /* struct quadratic q; */
192 gccjit::lvalue q
= test_quadratic
.new_local (testcase
.quadratic
, "q");
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");
204 CHECK_STRING_VALUE (on_zero_discriminant
.get_debug_string ().c_str (),
205 "zero_discriminant");
208 initial
.add_assignment (q
.access_field (testcase
.a
), a
);
210 initial
.add_assignment (q
.access_field (testcase
.b
), b
);
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
));
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
);
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
));
229 gccjit::rvalue minus_b
= -b
;
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 (),
236 on_positive_discriminant
.add_comment ("*r1 = (-b + s) / (2 * a);");
237 on_positive_discriminant
.add_assignment (*r1
, (minus_b
+ s
) / two_a
);
239 on_positive_discriminant
.add_comment ("*r2 = (-b - s) / (2 * a)");
240 on_positive_discriminant
.add_assignment (*r2
, (minus_b
- s
) / two_a
);
243 on_positive_discriminant
.end_with_return (
244 testcase
.ctxt
.new_rvalue (testcase
.int_type
, 2));
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
);
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
);
260 on_zero_discriminant
.end_with_return (testcase
.int_type
.one ());
262 /* Block: "on_negative_discriminant" */
264 on_negative_discriminant
.end_with_return (testcase
.int_type
.zero ());
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");
273 create_code (gcc_jit_context
*ctxt
, void *user_data
)
275 struct quadratic_test testcase
;
276 memset (&testcase
, 0, sizeof (testcase
));
277 testcase
.ctxt
= ctxt
;
278 make_types (testcase
);
279 make_sqrt (testcase
);
280 make_calc_discriminant (testcase
);
281 make_test_quadratic (testcase
);
285 verify_code (gcc_jit_context
*ctxt
, gcc_jit_result
*result
)
287 typedef int (*fn_type
) (double a
, double b
, double c
,
288 double *r1
, double *r2
);
290 CHECK_NON_NULL (result
);
292 fn_type test_quadratic
=
293 (fn_type
)gcc_jit_result_get_code (result
, "test_quadratic");
294 CHECK_NON_NULL (test_quadratic
);
296 /* Verify that the code correctly solves quadratic equations. */
299 /* This one has two solutions: */
300 CHECK_VALUE (test_quadratic (1, 3, -4, &r1
, &r2
), 2);
302 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);
308 /* This one has no real solutions: */
309 CHECK_VALUE (test_quadratic (4, 1, 1, &r1
, &r2
), 0);