1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <limits.h>
5 #include <stdbool.h>
6
7 #include "libgccjit.h"
8
9 #include "harness.h"
10
11 static void
create_overflow_fn(gcc_jit_context * ctxt,gcc_jit_type * type,const char * funcname,const char * builtin_name)12 create_overflow_fn (gcc_jit_context *ctxt,
13 gcc_jit_type *type,
14 const char *funcname,
15 const char *builtin_name)
16 {
17 /* Create the equivalent of this C:
18
19 int
20 test_overflow_T_OP (T x, T y, bool *ovf)
21 {
22 T result;
23 result = x OP y;
24 *ovf = ...; // did overflow happen?
25 return result;
26 }
27
28 */
29 gcc_jit_type *t_bool =
30 gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
31 gcc_jit_type *t_bool_star =
32 gcc_jit_type_get_pointer (t_bool);
33
34 gcc_jit_param *x =
35 gcc_jit_context_new_param (
36 ctxt,
37 NULL,
38 type, "x");
39 gcc_jit_param *y =
40 gcc_jit_context_new_param (
41 ctxt,
42 NULL,
43 type, "y");
44 gcc_jit_param *ovf =
45 gcc_jit_context_new_param (
46 ctxt,
47 NULL,
48 t_bool_star, "ovf");
49 gcc_jit_param *params[3] = {x, y, ovf};
50
51 gcc_jit_function *func =
52 gcc_jit_context_new_function (ctxt,
53 NULL,
54 GCC_JIT_FUNCTION_EXPORTED,
55 type,
56 funcname,
57 3, params, 0);
58
59 gcc_jit_lvalue *result =
60 gcc_jit_function_new_local (func, NULL, type, "result");
61
62 gcc_jit_block *b_initial =
63 gcc_jit_function_new_block (func, "initial");
64
65 /* The builtins are listed in builtins.def as being variadic, but
66 the have these signatures:
67 bool __builtin_add_overflow (type1 a, type2 b, type3 *res);
68 bool __builtin_sub_overflow (type1 a, type2 b, type3 *res);
69 bool __builtin_mul_overflow (type1 a, type2 b, type3 *res); */
70
71 gcc_jit_function *builtin_fn =
72 gcc_jit_context_get_builtin_function (ctxt, builtin_name);
73
74 /* Construct a call of the form:
75 (returns bool) __builtin_add_overflow (x, y, &result). */
76 gcc_jit_rvalue *args[3] = {gcc_jit_param_as_rvalue (x),
77 gcc_jit_param_as_rvalue (y),
78 gcc_jit_lvalue_get_address (result, NULL)};
79 gcc_jit_rvalue *call =
80 gcc_jit_context_new_call (ctxt,
81 NULL,
82 builtin_fn,
83 3, args);
84
85 /* "*ovf = BUILTIN_CALL ();" */
86 gcc_jit_block_add_assignment (
87 b_initial, NULL,
88 gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (ovf),
89 NULL),
90 call);
91
92 /* "return result;" */
93 gcc_jit_block_end_with_return (
94 b_initial, NULL,
95 gcc_jit_lvalue_as_rvalue (result));
96 }
97
98 void
create_code(gcc_jit_context * ctxt,void * user_data)99 create_code (gcc_jit_context *ctxt, void *user_data)
100 {
101 /* int */
102 gcc_jit_type *int_type =
103 gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
104 create_overflow_fn (ctxt, int_type,
105 "test_overflow_int_add",
106 "__builtin_add_overflow");
107 create_overflow_fn (ctxt, int_type,
108 "test_overflow_int_sub",
109 "__builtin_sub_overflow");
110 create_overflow_fn (ctxt, int_type,
111 "test_overflow_int_mul",
112 "__builtin_mul_overflow");
113
114 /* uint */
115 gcc_jit_type *uint_type =
116 gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT);
117 create_overflow_fn (ctxt, uint_type,
118 "test_overflow_uint_add",
119 "__builtin_add_overflow");
120 create_overflow_fn (ctxt, uint_type,
121 "test_overflow_uint_sub",
122 "__builtin_sub_overflow");
123 create_overflow_fn (ctxt, uint_type,
124 "test_overflow_uint_mul",
125 "__builtin_mul_overflow");
126 }
127
128 void
verify_int_overflow_fn(gcc_jit_result * jit_result,const char * funcname,int x,int y,int expected_result,bool expected_ovf)129 verify_int_overflow_fn (gcc_jit_result *jit_result,
130 const char *funcname,
131 int x, int y,
132 int expected_result,
133 bool expected_ovf)
134 {
135 CHECK_NON_NULL (jit_result);
136 typedef int (*overflow_fn_type) (int, int, bool *);
137 overflow_fn_type fn =
138 (overflow_fn_type)gcc_jit_result_get_code (jit_result, funcname);
139 CHECK_NON_NULL (fn);
140
141 /* Call the function: */
142 bool actual_ovf = 0;
143 int actual_result = fn (x, y, &actual_ovf);
144 note ("%s (%d, %d) returned: %d with ovf: %d",
145 funcname, x, y, actual_result, actual_ovf);
146 CHECK_VALUE (actual_result, expected_result);
147 CHECK_VALUE (actual_ovf, expected_ovf);
148 }
149
150 void
verify_uint_overflow_fn(gcc_jit_result * jit_result,const char * funcname,unsigned int x,unsigned int y,unsigned int expected_result,bool expected_ovf)151 verify_uint_overflow_fn (gcc_jit_result *jit_result,
152 const char *funcname,
153 unsigned int x, unsigned int y,
154 unsigned int expected_result,
155 bool expected_ovf)
156 {
157 CHECK_NON_NULL (jit_result);
158 typedef unsigned int (*overflow_fn_type) (unsigned int, unsigned int,
159 bool *);
160 overflow_fn_type fn =
161 (overflow_fn_type)gcc_jit_result_get_code (jit_result, funcname);
162 CHECK_NON_NULL (fn);
163
164 /* Call the function: */
165 bool actual_ovf = 0;
166 unsigned int actual_result = fn (x, y, &actual_ovf);
167 note ("%s (%d, %d) returned: %d with ovf: %d",
168 funcname, x, y, actual_result, actual_ovf);
169 CHECK_VALUE (actual_result, expected_result);
170 CHECK_VALUE (actual_ovf, expected_ovf);
171 }
172
173 void
verify_code(gcc_jit_context * ctxt,gcc_jit_result * result)174 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
175 {
176 verify_int_overflow_fn (result, "test_overflow_int_add",
177 5, 15,
178 20, 0);
179 verify_int_overflow_fn (result, "test_overflow_int_add",
180 INT_MAX, 1,
181 INT_MIN, 1);
182 verify_int_overflow_fn (result, "test_overflow_int_sub",
183 5, 15,
184 -10, 0);
185 verify_int_overflow_fn (result, "test_overflow_int_sub",
186 INT_MIN, 1,
187 INT_MAX, 1);
188 verify_int_overflow_fn (result, "test_overflow_int_mul",
189 5, 15,
190 75, 0);
191 verify_int_overflow_fn (result, "test_overflow_int_mul",
192 INT_MAX, 1,
193 INT_MAX, 0);
194 verify_int_overflow_fn (result, "test_overflow_int_mul",
195 INT_MAX, 2,
196 -2, 1);
197
198 verify_uint_overflow_fn (result, "test_overflow_uint_add",
199 5, 15,
200 20, 0);
201 verify_uint_overflow_fn (result, "test_overflow_uint_add",
202 INT_MAX, 1,
203 (((unsigned int)INT_MAX) + 1), 0);
204 verify_uint_overflow_fn (result, "test_overflow_uint_add",
205 UINT_MAX, 1,
206 0, 1);
207 verify_uint_overflow_fn (result, "test_overflow_uint_sub",
208 5, 15,
209 (UINT_MAX - 9), 1);
210 verify_uint_overflow_fn (result, "test_overflow_uint_sub",
211 INT_MIN, 1,
212 ((unsigned int)INT_MIN - 1), 0);
213 verify_uint_overflow_fn (result, "test_overflow_uint_mul",
214 5, 15,
215 75, 0);
216 verify_uint_overflow_fn (result, "test_overflow_uint_mul",
217 INT_MAX, 1,
218 INT_MAX, 0);
219 verify_uint_overflow_fn (result, "test_overflow_uint_mul",
220 INT_MAX, 2,
221 (unsigned int)INT_MAX * 2, 0);
222 verify_uint_overflow_fn (result, "test_overflow_uint_mul",
223 UINT_MAX, 2,
224 -2/*(unsigned int)INT_MAX * 2*/, 1);
225 }
226