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