|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  | #include <limits.h> | 
|  | #include <stdbool.h> | 
|  |  | 
|  | #include "libgccjit.h" | 
|  |  | 
|  | #include "harness.h" | 
|  |  | 
|  | static void | 
|  | create_overflow_fn (gcc_jit_context *ctxt, | 
|  | gcc_jit_type *type, | 
|  | const char *funcname, | 
|  | const char *builtin_name) | 
|  | { | 
|  | /* Create the equivalent of this C: | 
|  |  | 
|  | int | 
|  | test_overflow_T_OP (T x, T y, bool *ovf) | 
|  | { | 
|  | T result; | 
|  | result = x OP y; | 
|  | *ovf = ...; // did overflow happen? | 
|  | return result; | 
|  | } | 
|  |  | 
|  | */ | 
|  | gcc_jit_type *t_bool = | 
|  | gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL); | 
|  | gcc_jit_type *t_bool_star = | 
|  | gcc_jit_type_get_pointer (t_bool); | 
|  |  | 
|  | gcc_jit_param *x = | 
|  | gcc_jit_context_new_param ( | 
|  | ctxt, | 
|  | NULL, | 
|  | type, "x"); | 
|  | gcc_jit_param *y = | 
|  | gcc_jit_context_new_param ( | 
|  | ctxt, | 
|  | NULL, | 
|  | type, "y"); | 
|  | gcc_jit_param *ovf = | 
|  | gcc_jit_context_new_param ( | 
|  | ctxt, | 
|  | NULL, | 
|  | t_bool_star, "ovf"); | 
|  | gcc_jit_param *params[3] = {x, y, ovf}; | 
|  |  | 
|  | gcc_jit_function *func = | 
|  | gcc_jit_context_new_function (ctxt, | 
|  | NULL, | 
|  | GCC_JIT_FUNCTION_EXPORTED, | 
|  | type, | 
|  | funcname, | 
|  | 3, params, 0); | 
|  |  | 
|  | gcc_jit_lvalue *result = | 
|  | gcc_jit_function_new_local (func, NULL, type, "result"); | 
|  |  | 
|  | gcc_jit_block *b_initial = | 
|  | gcc_jit_function_new_block (func, "initial"); | 
|  |  | 
|  | /* The builtins are listed in builtins.def as being variadic, but | 
|  | the have these signatures: | 
|  | bool __builtin_add_overflow (type1 a, type2 b, type3 *res); | 
|  | bool __builtin_sub_overflow (type1 a, type2 b, type3 *res); | 
|  | bool __builtin_mul_overflow (type1 a, type2 b, type3 *res);  */ | 
|  |  | 
|  | gcc_jit_function *builtin_fn = | 
|  | gcc_jit_context_get_builtin_function (ctxt, builtin_name); | 
|  |  | 
|  | /* Construct a call of the form: | 
|  | (returns bool) __builtin_add_overflow (x, y, &result).  */ | 
|  | gcc_jit_rvalue *args[3] = {gcc_jit_param_as_rvalue (x), | 
|  | gcc_jit_param_as_rvalue (y), | 
|  | gcc_jit_lvalue_get_address (result, NULL)}; | 
|  | gcc_jit_rvalue *call = | 
|  | gcc_jit_context_new_call (ctxt, | 
|  | NULL, | 
|  | builtin_fn, | 
|  | 3, args); | 
|  |  | 
|  | /* "*ovf = BUILTIN_CALL ();" */ | 
|  | gcc_jit_block_add_assignment ( | 
|  | b_initial, NULL, | 
|  | gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (ovf), | 
|  | NULL), | 
|  | call); | 
|  |  | 
|  | /* "return result;" */ | 
|  | gcc_jit_block_end_with_return ( | 
|  | b_initial, NULL, | 
|  | gcc_jit_lvalue_as_rvalue (result)); | 
|  | } | 
|  |  | 
|  | void | 
|  | create_code (gcc_jit_context *ctxt, void *user_data) | 
|  | { | 
|  | /* int */ | 
|  | gcc_jit_type *int_type = | 
|  | gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); | 
|  | create_overflow_fn (ctxt, int_type, | 
|  | "test_overflow_int_add", | 
|  | "__builtin_add_overflow"); | 
|  | create_overflow_fn (ctxt, int_type, | 
|  | "test_overflow_int_sub", | 
|  | "__builtin_sub_overflow"); | 
|  | create_overflow_fn (ctxt, int_type, | 
|  | "test_overflow_int_mul", | 
|  | "__builtin_mul_overflow"); | 
|  |  | 
|  | /* uint */ | 
|  | gcc_jit_type *uint_type = | 
|  | gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT); | 
|  | create_overflow_fn (ctxt, uint_type, | 
|  | "test_overflow_uint_add", | 
|  | "__builtin_add_overflow"); | 
|  | create_overflow_fn (ctxt, uint_type, | 
|  | "test_overflow_uint_sub", | 
|  | "__builtin_sub_overflow"); | 
|  | create_overflow_fn (ctxt, uint_type, | 
|  | "test_overflow_uint_mul", | 
|  | "__builtin_mul_overflow"); | 
|  | } | 
|  |  | 
|  | void | 
|  | verify_int_overflow_fn (gcc_jit_result *jit_result, | 
|  | const char *funcname, | 
|  | int x, int y, | 
|  | int expected_result, | 
|  | bool expected_ovf) | 
|  | { | 
|  | CHECK_NON_NULL (jit_result); | 
|  | typedef int (*overflow_fn_type) (int, int, bool *); | 
|  | overflow_fn_type fn = | 
|  | (overflow_fn_type)gcc_jit_result_get_code (jit_result, funcname); | 
|  | CHECK_NON_NULL (fn); | 
|  |  | 
|  | /* Call the function:  */ | 
|  | bool actual_ovf = 0; | 
|  | int actual_result = fn (x, y, &actual_ovf); | 
|  | note ("%s (%d, %d) returned: %d with ovf: %d", | 
|  | funcname, x, y, actual_result, actual_ovf); | 
|  | CHECK_VALUE (actual_result, expected_result); | 
|  | CHECK_VALUE (actual_ovf, expected_ovf); | 
|  | } | 
|  |  | 
|  | 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) | 
|  | { | 
|  | CHECK_NON_NULL (jit_result); | 
|  | typedef unsigned int (*overflow_fn_type) (unsigned int, unsigned int, | 
|  | bool *); | 
|  | overflow_fn_type fn = | 
|  | (overflow_fn_type)gcc_jit_result_get_code (jit_result, funcname); | 
|  | CHECK_NON_NULL (fn); | 
|  |  | 
|  | /* Call the function:  */ | 
|  | bool actual_ovf = 0; | 
|  | unsigned int actual_result = fn (x, y, &actual_ovf); | 
|  | note ("%s (%d, %d) returned: %d with ovf: %d", | 
|  | funcname, x, y, actual_result, actual_ovf); | 
|  | CHECK_VALUE (actual_result, expected_result); | 
|  | CHECK_VALUE (actual_ovf, expected_ovf); | 
|  | } | 
|  |  | 
|  | void | 
|  | verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) | 
|  | { | 
|  | verify_int_overflow_fn (result, "test_overflow_int_add", | 
|  | 5, 15, | 
|  | 20, 0); | 
|  | verify_int_overflow_fn (result, "test_overflow_int_add", | 
|  | INT_MAX, 1, | 
|  | INT_MIN, 1); | 
|  | verify_int_overflow_fn (result, "test_overflow_int_sub", | 
|  | 5, 15, | 
|  | -10, 0); | 
|  | verify_int_overflow_fn (result, "test_overflow_int_sub", | 
|  | INT_MIN, 1, | 
|  | INT_MAX, 1); | 
|  | verify_int_overflow_fn (result, "test_overflow_int_mul", | 
|  | 5, 15, | 
|  | 75, 0); | 
|  | verify_int_overflow_fn (result, "test_overflow_int_mul", | 
|  | INT_MAX, 1, | 
|  | INT_MAX, 0); | 
|  | verify_int_overflow_fn (result, "test_overflow_int_mul", | 
|  | INT_MAX, 2, | 
|  | -2, 1); | 
|  |  | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_add", | 
|  | 5, 15, | 
|  | 20, 0); | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_add", | 
|  | INT_MAX, 1, | 
|  | (((unsigned int)INT_MAX) + 1), 0); | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_add", | 
|  | UINT_MAX, 1, | 
|  | 0, 1); | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_sub", | 
|  | 5, 15, | 
|  | (UINT_MAX - 9), 1); | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_sub", | 
|  | INT_MIN, 1, | 
|  | ((unsigned int)INT_MIN - 1), 0); | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_mul", | 
|  | 5, 15, | 
|  | 75, 0); | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_mul", | 
|  | INT_MAX, 1, | 
|  | INT_MAX, 0); | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_mul", | 
|  | INT_MAX, 2, | 
|  | (unsigned int)INT_MAX * 2, 0); | 
|  | verify_uint_overflow_fn (result, "test_overflow_uint_mul", | 
|  | UINT_MAX, 2, | 
|  | -2/*(unsigned int)INT_MAX * 2*/, 1); | 
|  | } |