Message ID | 20161115140313.GE3541@tucnak.redhat.com |
---|---|
State | New |
Headers | show |
On 11/15/2016 07:03 AM, Jakub Jelinek wrote: > Hi! > > On Mon, Nov 14, 2016 at 10:58:51AM +0100, Jakub Jelinek wrote: >> Working virtually out of Samoa. >> >> The following patch is an attempt to handle -fsanitize=undefined >> for vectors. We already diagnose out of bounds accesses for vector >> subscripts, this patch adds expansion for vector UBSAN_CHECK_* and generates >> those in ubsan. Haven't finished up the many vect elements handling (want >> to emit a loop for code size). Is this something we want for GCC 7? > > Here is the full patch (just for -fsanitize=signed-integer-overflow, not > for -fsanitize=shift or -fsanitize={integer,float}-divide-by-zero for now). > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2016-11-15 Jakub Jelinek <jakub@redhat.com> > > PR sanitizer/77823 > * ubsan.c (ubsan_build_overflow_builtin): Add DATAP argument, if > it points to non-NULL tree, use it instead of ubsan_create_data. > (instrument_si_overflow): Handle vector signed integer overflow > checking. > * ubsan.h (ubsan_build_overflow_builtin): Add DATAP argument. > * tree-vrp.c (simplify_internal_call_using_ranges): Punt for > vector IFN_UBSAN_CHECK_*. > * internal-fn.c (expand_addsub_overflow): Add DATAP argument, > pass it through to ubsan_build_overflow_builtin. > (expand_neg_overflow, expand_mul_overflow): Likewise. > (expand_vector_ubsan_overflow): New function. > (expand_UBSAN_CHECK_ADD, expand_UBSAN_CHECK_SUB, > expand_UBSAN_CHECK_MUL): Use tit for vector arithmetics. > (expand_arith_overflow): Adjust expand_*_overflow callers. > > * c-c++-common/ubsan/overflow-vec-1.c: New test. > * c-c++-common/ubsan/overflow-vec-2.c: New test. I certainly don't see any reason why we wouldn't want additional sanitizers, so ISTM it's really a matter of are you happy with the implementation. While there's a fair amount of changes in internal-fn.c, they're all sanitizer specific routines AFAICT. Jeff
On Tue, 15 Nov 2016, Jakub Jelinek wrote: > Hi! > > On Mon, Nov 14, 2016 at 10:58:51AM +0100, Jakub Jelinek wrote: > > Working virtually out of Samoa. > > > > The following patch is an attempt to handle -fsanitize=undefined > > for vectors. We already diagnose out of bounds accesses for vector > > subscripts, this patch adds expansion for vector UBSAN_CHECK_* and generates > > those in ubsan. Haven't finished up the many vect elements handling (want > > to emit a loop for code size). Is this something we want for GCC 7? > > Here is the full patch (just for -fsanitize=signed-integer-overflow, not > for -fsanitize=shift or -fsanitize={integer,float}-divide-by-zero for now). > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? LGTM. Thanks, Richard. > 2016-11-15 Jakub Jelinek <jakub@redhat.com> > > PR sanitizer/77823 > * ubsan.c (ubsan_build_overflow_builtin): Add DATAP argument, if > it points to non-NULL tree, use it instead of ubsan_create_data. > (instrument_si_overflow): Handle vector signed integer overflow > checking. > * ubsan.h (ubsan_build_overflow_builtin): Add DATAP argument. > * tree-vrp.c (simplify_internal_call_using_ranges): Punt for > vector IFN_UBSAN_CHECK_*. > * internal-fn.c (expand_addsub_overflow): Add DATAP argument, > pass it through to ubsan_build_overflow_builtin. > (expand_neg_overflow, expand_mul_overflow): Likewise. > (expand_vector_ubsan_overflow): New function. > (expand_UBSAN_CHECK_ADD, expand_UBSAN_CHECK_SUB, > expand_UBSAN_CHECK_MUL): Use tit for vector arithmetics. > (expand_arith_overflow): Adjust expand_*_overflow callers. > > * c-c++-common/ubsan/overflow-vec-1.c: New test. > * c-c++-common/ubsan/overflow-vec-2.c: New test. > > --- gcc/ubsan.c.jj 2016-11-14 19:57:07.005897502 +0100 > +++ gcc/ubsan.c 2016-11-15 09:09:33.288146293 +0100 > @@ -1219,14 +1219,20 @@ instrument_null (gimple_stmt_iterator gs > > tree > ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype, > - tree op0, tree op1) > + tree op0, tree op1, tree *datap) > { > if (flag_sanitize_undefined_trap_on_error) > return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); > > - tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc, > - ubsan_type_descriptor (lhstype), NULL_TREE, > - NULL_TREE); > + tree data; > + if (datap && *datap) > + data = *datap; > + else > + data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc, > + ubsan_type_descriptor (lhstype), NULL_TREE, > + NULL_TREE); > + if (datap) > + *datap = data; > enum built_in_function fn_code; > > switch (code) > @@ -1272,14 +1278,15 @@ instrument_si_overflow (gimple_stmt_iter > tree_code code = gimple_assign_rhs_code (stmt); > tree lhs = gimple_assign_lhs (stmt); > tree lhstype = TREE_TYPE (lhs); > + tree lhsinner = VECTOR_TYPE_P (lhstype) ? TREE_TYPE (lhstype) : lhstype; > tree a, b; > gimple *g; > > /* If this is not a signed operation, don't instrument anything here. > Also punt on bit-fields. */ > - if (!INTEGRAL_TYPE_P (lhstype) > - || TYPE_OVERFLOW_WRAPS (lhstype) > - || GET_MODE_BITSIZE (TYPE_MODE (lhstype)) != TYPE_PRECISION (lhstype)) > + if (!INTEGRAL_TYPE_P (lhsinner) > + || TYPE_OVERFLOW_WRAPS (lhsinner) > + || GET_MODE_BITSIZE (TYPE_MODE (lhsinner)) != TYPE_PRECISION (lhsinner)) > return; > > switch (code) > @@ -1305,7 +1312,7 @@ instrument_si_overflow (gimple_stmt_iter > /* Represent i = -u; > as > i = UBSAN_CHECK_SUB (0, u); */ > - a = build_int_cst (lhstype, 0); > + a = build_zero_cst (lhstype); > b = gimple_assign_rhs1 (stmt); > g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b); > gimple_call_set_lhs (g, lhs); > @@ -1316,7 +1323,7 @@ instrument_si_overflow (gimple_stmt_iter > into > _N = UBSAN_CHECK_SUB (0, u); > i = ABS_EXPR<_N>; */ > - a = build_int_cst (lhstype, 0); > + a = build_zero_cst (lhstype); > b = gimple_assign_rhs1 (stmt); > g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b); > a = make_ssa_name (lhstype); > --- gcc/ubsan.h.jj 2016-11-14 19:57:07.027897220 +0100 > +++ gcc/ubsan.h 2016-11-14 20:37:20.892032650 +0100 > @@ -52,7 +52,8 @@ extern tree ubsan_create_data (const cha > extern tree ubsan_type_descriptor (tree, enum ubsan_print_style = UBSAN_PRINT_NORMAL); > extern tree ubsan_encode_value (tree, bool = false); > extern bool is_ubsan_builtin_p (tree); > -extern tree ubsan_build_overflow_builtin (tree_code, location_t, tree, tree, tree); > +extern tree ubsan_build_overflow_builtin (tree_code, location_t, tree, tree, > + tree, tree *); > extern tree ubsan_instrument_float_cast (location_t, tree, tree); > extern tree ubsan_get_source_location_type (void); > > --- gcc/tree-vrp.c.jj 2016-11-14 19:57:06.957898116 +0100 > +++ gcc/tree-vrp.c 2016-11-14 20:37:20.897032586 +0100 > @@ -10023,7 +10023,11 @@ simplify_internal_call_using_ranges (gim > tree op1 = gimple_call_arg (stmt, 1); > tree type; > if (is_ubsan) > - type = TREE_TYPE (op0); > + { > + type = TREE_TYPE (op0); > + if (VECTOR_TYPE_P (type)) > + return false; > + } > else if (gimple_call_lhs (stmt) == NULL_TREE) > return false; > else > --- gcc/internal-fn.c.jj 2016-11-14 19:57:10.754849526 +0100 > +++ gcc/internal-fn.c 2016-11-15 09:15:13.375839832 +0100 > @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. > #include "ubsan.h" > #include "recog.h" > #include "builtins.h" > +#include "optabs-tree.h" > > /* The names of each internal function, indexed by function number. */ > const char *const internal_fn_name_array[] = { > @@ -513,7 +514,7 @@ expand_ubsan_result_store (rtx target, r > static void > expand_addsub_overflow (location_t loc, tree_code code, tree lhs, > tree arg0, tree arg1, bool unsr_p, bool uns0_p, > - bool uns1_p, bool is_ubsan) > + bool uns1_p, bool is_ubsan, tree *datap) > { > rtx res, target = NULL_RTX; > tree fn; > @@ -929,7 +930,7 @@ expand_addsub_overflow (location_t loc, > /* Expand the ubsan builtin call. */ > push_temp_slots (); > fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0), > - arg0, arg1); > + arg0, arg1, datap); > expand_normal (fn); > pop_temp_slots (); > do_pending_stack_adjust (); > @@ -958,7 +959,8 @@ expand_addsub_overflow (location_t loc, > /* Add negate overflow checking to the statement STMT. */ > > static void > -expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan) > +expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan, > + tree *datap) > { > rtx res, op1; > tree fn; > @@ -1024,7 +1026,7 @@ expand_neg_overflow (location_t loc, tre > /* Expand the ubsan builtin call. */ > push_temp_slots (); > fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1), > - arg1, NULL_TREE); > + arg1, NULL_TREE, datap); > expand_normal (fn); > pop_temp_slots (); > do_pending_stack_adjust (); > @@ -1048,7 +1050,8 @@ expand_neg_overflow (location_t loc, tre > > static void > expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, > - bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan) > + bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan, > + tree *datap) > { > rtx res, op0, op1; > tree fn, type; > @@ -1685,7 +1688,7 @@ expand_mul_overflow (location_t loc, tre > /* Expand the ubsan builtin call. */ > push_temp_slots (); > fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (arg0), > - arg0, arg1); > + arg0, arg1, datap); > expand_normal (fn); > pop_temp_slots (); > do_pending_stack_adjust (); > @@ -1734,6 +1737,145 @@ expand_mul_overflow (location_t loc, tre > } > } > > +/* Expand UBSAN_CHECK_* internal function if it has vector operands. */ > + > +static void > +expand_vector_ubsan_overflow (location_t loc, enum tree_code code, tree lhs, > + tree arg0, tree arg1) > +{ > + int cnt = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); > + rtx_code_label *loop_lab = NULL; > + rtx cntvar = NULL_RTX; > + tree cntv = NULL_TREE; > + tree eltype = TREE_TYPE (TREE_TYPE (arg0)); > + tree sz = TYPE_SIZE (eltype); > + tree data = NULL_TREE; > + tree resv = NULL_TREE; > + rtx lhsr = NULL_RTX; > + rtx resvr = NULL_RTX; > + > + if (lhs) > + { > + optab op; > + lhsr = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); > + if (GET_MODE (lhsr) == BLKmode > + || (op = optab_for_tree_code (code, TREE_TYPE (arg0), > + optab_default)) == unknown_optab > + || (optab_handler (op, TYPE_MODE (TREE_TYPE (arg0))) > + == CODE_FOR_nothing)) > + { > + if (MEM_P (lhsr)) > + resv = make_tree (TREE_TYPE (lhs), lhsr); > + else > + { > + resvr = assign_temp (TREE_TYPE (lhs), 1, 1); > + resv = make_tree (TREE_TYPE (lhs), resvr); > + } > + } > + } > + if (cnt > 4) > + { > + do_pending_stack_adjust (); > + loop_lab = gen_label_rtx (); > + cntvar = gen_reg_rtx (TYPE_MODE (sizetype)); > + cntv = make_tree (sizetype, cntvar); > + emit_move_insn (cntvar, const0_rtx); > + emit_label (loop_lab); > + } > + if (TREE_CODE (arg0) != VECTOR_CST) > + { > + rtx arg0r = expand_normal (arg0); > + arg0 = make_tree (TREE_TYPE (arg0), arg0r); > + } > + if (TREE_CODE (arg1) != VECTOR_CST) > + { > + rtx arg1r = expand_normal (arg1); > + arg1 = make_tree (TREE_TYPE (arg1), arg1r); > + } > + for (int i = 0; i < (cnt > 4 ? 1 : cnt); i++) > + { > + tree op0, op1, res = NULL_TREE; > + if (cnt > 4) > + { > + tree atype = build_array_type_nelts (eltype, cnt); > + op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg0); > + op0 = build4_loc (loc, ARRAY_REF, eltype, op0, cntv, > + NULL_TREE, NULL_TREE); > + op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg1); > + op1 = build4_loc (loc, ARRAY_REF, eltype, op1, cntv, > + NULL_TREE, NULL_TREE); > + if (resv) > + { > + res = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, resv); > + res = build4_loc (loc, ARRAY_REF, eltype, res, cntv, > + NULL_TREE, NULL_TREE); > + } > + } > + else > + { > + tree bitpos = bitsize_int (tree_to_uhwi (sz) * i); > + op0 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg0, sz, bitpos); > + op1 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg1, sz, bitpos); > + if (resv) > + res = fold_build3_loc (loc, BIT_FIELD_REF, eltype, resv, sz, > + bitpos); > + } > + switch (code) > + { > + case PLUS_EXPR: > + expand_addsub_overflow (loc, PLUS_EXPR, res, op0, op1, > + false, false, false, true, &data); > + break; > + case MINUS_EXPR: > + if (cnt > 4 ? integer_zerop (arg0) : integer_zerop (op0)) > + expand_neg_overflow (loc, res, op1, true, &data); > + else > + expand_addsub_overflow (loc, MINUS_EXPR, res, op0, op1, > + false, false, false, true, &data); > + break; > + case MULT_EXPR: > + expand_mul_overflow (loc, res, op0, op1, false, false, false, > + true, &data); > + break; > + default: > + gcc_unreachable (); > + } > + } > + if (cnt > 4) > + { > + struct separate_ops ops; > + ops.code = PLUS_EXPR; > + ops.type = TREE_TYPE (cntv); > + ops.op0 = cntv; > + ops.op1 = build_int_cst (TREE_TYPE (cntv), 1); > + ops.op2 = NULL_TREE; > + ops.location = loc; > + rtx ret = expand_expr_real_2 (&ops, cntvar, TYPE_MODE (sizetype), > + EXPAND_NORMAL); > + if (ret != cntvar) > + emit_move_insn (cntvar, ret); > + do_compare_rtx_and_jump (cntvar, GEN_INT (cnt), NE, false, > + TYPE_MODE (sizetype), NULL_RTX, NULL, loop_lab, > + PROB_VERY_LIKELY); > + } > + if (lhs && resv == NULL_TREE) > + { > + struct separate_ops ops; > + ops.code = code; > + ops.type = TREE_TYPE (arg0); > + ops.op0 = arg0; > + ops.op1 = arg1; > + ops.op2 = NULL_TREE; > + ops.location = loc; > + rtx ret = expand_expr_real_2 (&ops, lhsr, TYPE_MODE (TREE_TYPE (arg0)), > + EXPAND_NORMAL); > + if (ret != lhsr) > + emit_move_insn (lhsr, ret); > + } > + else if (resvr) > + emit_move_insn (lhsr, resvr); > +} > + > /* Expand UBSAN_CHECK_ADD call STMT. */ > > static void > @@ -1743,8 +1885,11 @@ expand_UBSAN_CHECK_ADD (internal_fn, gca > tree lhs = gimple_call_lhs (stmt); > tree arg0 = gimple_call_arg (stmt, 0); > tree arg1 = gimple_call_arg (stmt, 1); > - expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1, > - false, false, false, true); > + if (VECTOR_TYPE_P (TREE_TYPE (arg0))) > + expand_vector_ubsan_overflow (loc, PLUS_EXPR, lhs, arg0, arg1); > + else > + expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1, > + false, false, false, true, NULL); > } > > /* Expand UBSAN_CHECK_SUB call STMT. */ > @@ -1756,11 +1901,13 @@ expand_UBSAN_CHECK_SUB (internal_fn, gca > tree lhs = gimple_call_lhs (stmt); > tree arg0 = gimple_call_arg (stmt, 0); > tree arg1 = gimple_call_arg (stmt, 1); > - if (integer_zerop (arg0)) > - expand_neg_overflow (loc, lhs, arg1, true); > + if (VECTOR_TYPE_P (TREE_TYPE (arg0))) > + expand_vector_ubsan_overflow (loc, MINUS_EXPR, lhs, arg0, arg1); > + else if (integer_zerop (arg0)) > + expand_neg_overflow (loc, lhs, arg1, true, NULL); > else > expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1, > - false, false, false, true); > + false, false, false, true, NULL); > } > > /* Expand UBSAN_CHECK_MUL call STMT. */ > @@ -1772,7 +1919,11 @@ expand_UBSAN_CHECK_MUL (internal_fn, gca > tree lhs = gimple_call_lhs (stmt); > tree arg0 = gimple_call_arg (stmt, 0); > tree arg1 = gimple_call_arg (stmt, 1); > - expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true); > + if (VECTOR_TYPE_P (TREE_TYPE (arg0))) > + expand_vector_ubsan_overflow (loc, MULT_EXPR, lhs, arg0, arg1); > + else > + expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true, > + NULL); > } > > /* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion. */ > @@ -1864,17 +2015,17 @@ expand_arith_overflow (enum tree_code co > case MINUS_EXPR: > if (integer_zerop (arg0) && !unsr_p) > { > - expand_neg_overflow (loc, lhs, arg1, false); > + expand_neg_overflow (loc, lhs, arg1, false, NULL); > return; > } > /* FALLTHRU */ > case PLUS_EXPR: > - expand_addsub_overflow (loc, code, lhs, arg0, arg1, > - unsr_p, unsr_p, unsr_p, false); > + expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p, > + unsr_p, unsr_p, false, NULL); > return; > case MULT_EXPR: > - expand_mul_overflow (loc, lhs, arg0, arg1, > - unsr_p, unsr_p, unsr_p, false); > + expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p, > + unsr_p, unsr_p, false, NULL); > return; > default: > gcc_unreachable (); > @@ -1916,10 +2067,10 @@ expand_arith_overflow (enum tree_code co > arg1 = fold_convert_loc (loc, types[uns1_p], arg1); > if (code != MULT_EXPR) > expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p, > - uns0_p, uns1_p, false); > + uns0_p, uns1_p, false, NULL); > else > expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p, > - uns0_p, uns1_p, false); > + uns0_p, uns1_p, false, NULL); > return; > } > > --- gcc/testsuite/c-c++-common/ubsan/overflow-vec-1.c.jj 2016-11-14 20:37:20.893032637 +0100 > +++ gcc/testsuite/c-c++-common/ubsan/overflow-vec-1.c 2016-11-15 09:28:24.000000000 +0100 > @@ -0,0 +1,144 @@ > +/* { dg-do run } */ > +/* { dg-options "-Wno-psabi -fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover=signed-integer-overflow" } */ > + > +#define SCHAR_MAX __SCHAR_MAX__ > +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) > +#define SHRT_MAX __SHRT_MAX__ > +#define SHRT_MIN (-__SHRT_MAX__ - 1) > +#define INT_MAX __INT_MAX__ > +#define INT_MIN (-__INT_MAX__ - 1) > + > +typedef signed char VC __attribute__((vector_size (16))); > +typedef short VS __attribute__((vector_size (8 * sizeof (short)))); > +typedef int VI __attribute__((vector_size (4 * sizeof (int)))); > +typedef int VI2 __attribute__((vector_size (16 * sizeof (int)))); > + > +void __attribute__((noinline,noclone)) > +checkvc (VC i, VC j) > +{ > + if (__builtin_memcmp (&i, &j, sizeof (VC))) > + __builtin_abort (); > +} > + > +void __attribute__((noinline,noclone)) > +checkvs (VS i, VS j) > +{ > + if (__builtin_memcmp (&i, &j, sizeof (VS))) > + __builtin_abort (); > +} > + > +void __attribute__((noinline,noclone)) > +checkvi (VI i, VI j) > +{ > + if (__builtin_memcmp (&i, &j, sizeof (VI))) > + __builtin_abort (); > +} > + > +void __attribute__((noinline,noclone)) > +checkvi2 (VI2 i, VI2 j) > +{ > + if (__builtin_memcmp (&i, &j, sizeof (VI2))) > + __builtin_abort (); > +} > + > +VI __attribute__((noinline,noclone)) > +foo (VI i) > +{ > + return -i; > +} > + > +VS __attribute__((noinline,noclone)) > +bar (VS i, VS j) > +{ > + return i + j; > +} > + > +int > +main (void) > +{ > + /* Check that for a vector operation, only the first element with UB is reported. */ > + volatile VC a = (VC) { 0, SCHAR_MAX - 2, SCHAR_MAX - 2, 3, 2, 3, 4, 5, 0, 7, 1, 2, 3, 4, SCHAR_MAX - 13, SCHAR_MAX }; > + volatile VC b = (VC) { 5, 2, 1, 5, 0, 1, 2, 7, 8, 9, 10, 11, 6, -2, 13, 0 }; > + volatile VC k = b + a; > + checkvc (k, (VC) { 5, SCHAR_MAX, SCHAR_MAX - 1, 8, 2, 4, 6, 12, 8, 16, 11, 13, 9, 2, SCHAR_MAX, SCHAR_MAX }); > + k = a + b; > + checkvc (k, (VC) { 5, SCHAR_MAX, SCHAR_MAX - 1, 8, 2, 4, 6, 12, 8, 16, 11, 13, 9, 2, SCHAR_MAX, SCHAR_MAX }); > + > + volatile VS c = (VS) { 0, SHRT_MAX - 2, SHRT_MAX - 2, 3, 3, 4, SHRT_MAX - 13, SHRT_MAX }; > + volatile VS d = (VS) { 5, 2, -3, 5, 6, -2, 13, -1 }; > + volatile VS l = d + c; > + checkvs (l, (VS) { 5, SHRT_MAX, SHRT_MAX - 5, 8, 9, 2, SHRT_MAX, SHRT_MAX - 1 }); > + l = bar (c, d); > + checkvs (l, (VS) { 5, SHRT_MAX, SHRT_MAX - 5, 8, 9, 2, SHRT_MAX, SHRT_MAX - 1 }); > + > + volatile VI e = (VI) { INT_MAX - 4, INT_MAX - 5, INT_MAX - 13, INT_MAX }; > + volatile VI f = (VI) { 4, -6, 13, 0 }; > + volatile VI m = f + e; > + checkvi (m, (VI) { INT_MAX, INT_MAX - 11,INT_MAX, INT_MAX }); > + m = e + f; > + checkvi (m, (VI) { INT_MAX, INT_MAX - 11,INT_MAX, INT_MAX }); > + > + volatile VI2 g = (VI2) { 0, INT_MAX - 2, INT_MAX - 2, 3, 3, 4, INT_MAX - 13, INT_MAX }; > + volatile VI2 h = (VI2) { 5, 2, -5, 5, 6, -2, 13, -1 }; > + volatile VI2 n = h + g; > + checkvi2 (n, (VI2) { 5, INT_MAX, INT_MAX - 7, 8, 9, 2, INT_MAX, INT_MAX - 1 }); > + n = g + h; > + checkvi2 (n, (VI2) { 5, INT_MAX, INT_MAX - 7, 8, 9, 2, INT_MAX, INT_MAX - 1 }); > + > + volatile VC a2 = k - b; > + checkvc (a2, a); > + volatile VC b2 = k - a; > + checkvc (b2, b); > + > + volatile VS c2 = l - d; > + checkvs (c2, c); > + volatile VS d2 = l - c; > + checkvs (d2, d); > + > + volatile VI e2 = m - f; > + checkvi (e2, e); > + volatile VI f2 = m - e; > + checkvi (f2, f); > + > + volatile VI2 g2 = n - h; > + checkvi2 (g2, g); > + volatile VI2 h2 = n - g; > + checkvi2 (h2, h); > + > + a = (VC) { 0, SCHAR_MAX / 4, SCHAR_MAX / 4, 3, 2, 3, 4, 5, 0, 7, 1, 2, 3, 4, SCHAR_MAX - 13, SCHAR_MAX }; > + b = (VC) { SCHAR_MAX, 4, 3, 2, 3, 4, 5, 2, 9, 2, 9, 1, 0, 8, 1, 1 }; > + k = a * b; > + checkvc (k, (VC) { 0, 124, 93, 6, 6,12,20,10, 0,14, 9, 2, 0,32, SCHAR_MAX - 13, SCHAR_MAX }); > + > + c = (VS) { 0, SHRT_MAX / 8, SHRT_MAX / 7, 5, 8, 9, SHRT_MAX - 10, SHRT_MAX }; > + d = (VS) { SHRT_MAX, 8, 6, 2, 3, 4, 1, 1 }; > + l = c * d; > + checkvs (l, (VS) { 0, 32760, 28086, 10,24,36, SHRT_MAX - 10, SHRT_MAX }); > + > + e = (VI) { INT_MAX, INT_MAX / 5, INT_MAX / 6, INT_MAX }; > + f = (VI) { 0, 5, 5, 1 }; > + m = e * f; > + checkvi (m, (VI) { 0, 2147483645, 1789569705, INT_MAX }); > + > + g = (VI2) { INT_MAX, INT_MAX / 9, INT_MAX / 8, 5, 6, 7, 8, INT_MAX }; > + h = (VI2) { 0, 8, 8, 2, 3, 4, 5, 1 }; > + n = g * h; > + checkvi2 (n,(VI2) { 0, 1908874352, 2147483640, 10,18,28,40, INT_MAX }); > + > + a = (VC) { 5, 7, 8, 9, SCHAR_MAX, SCHAR_MIN + 1, 24, 32, 0, 1, 2, 3, 4, 5, SCHAR_MAX, SCHAR_MIN + 2 }; > + k = -a; > + checkvc (k, (VC) {-5,-7,-8,-9,-SCHAR_MAX, SCHAR_MAX, -24,-32, 0,-1,-2,-3,-4,-5,-SCHAR_MAX, SCHAR_MAX - 1 }); > + > + c = (VS) { 0, 7, 23, SHRT_MIN + 1, SHRT_MIN + 2, SHRT_MAX, 2, 5 }; > + l = -c; > + checkvs (l, (VS) { 0,-7,-23, SHRT_MAX, SHRT_MAX - 1,-SHRT_MAX,-2,-5 }); > + > + e = (VI) { 5, INT_MAX, INT_MIN + 1, INT_MIN + 2 }; > + m = foo (e); > + checkvi (m, (VI) {-5,-INT_MAX, INT_MAX, INT_MAX - 1 }); > + > + g = (VI2) { 10, 11, 0, INT_MAX - 2, 1, INT_MIN + 1, 5, INT_MIN / 2 }; > + n = -g; > + checkvi2 (n, (VI2) {-10,-11, 0,-INT_MAX + 2,-1, INT_MAX, -5, INT_MAX / 2 + 1 }); > + return 0; > +} > --- gcc/testsuite/c-c++-common/ubsan/overflow-vec-2.c.jj 2016-11-14 20:37:20.894032625 +0100 > +++ gcc/testsuite/c-c++-common/ubsan/overflow-vec-2.c 2016-11-15 09:15:54.000000000 +0100 > @@ -0,0 +1,169 @@ > +/* { dg-do run } */ > +/* { dg-options "-Wno-psabi -fsanitize=signed-integer-overflow -Wno-unused-variable -fsanitize-recover=signed-integer-overflow" } */ > + > +#define SCHAR_MAX __SCHAR_MAX__ > +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) > +#define SHRT_MAX __SHRT_MAX__ > +#define SHRT_MIN (-__SHRT_MAX__ - 1) > +#define INT_MAX __INT_MAX__ > +#define INT_MIN (-__INT_MAX__ - 1) > + > +typedef signed char VC __attribute__((vector_size (16))); > +typedef short VS __attribute__((vector_size (8 * sizeof (short)))); > +typedef int VI __attribute__((vector_size (4 * sizeof (int)))); > +typedef int VI2 __attribute__((vector_size (16 * sizeof (int)))); > + > +void __attribute__((noinline,noclone)) > +checkvc (VC i, VC j) > +{ > + if (__builtin_memcmp (&i, &j, sizeof (VC))) > + __builtin_abort (); > +} > + > +void __attribute__((noinline,noclone)) > +checkvs (VS i, VS j) > +{ > + if (__builtin_memcmp (&i, &j, sizeof (VS))) > + __builtin_abort (); > +} > + > +void __attribute__((noinline,noclone)) > +checkvi (VI i, VI j) > +{ > + if (__builtin_memcmp (&i, &j, sizeof (VI))) > + __builtin_abort (); > +} > + > +void __attribute__((noinline,noclone)) > +checkvi2 (VI2 i, VI2 j) > +{ > + if (__builtin_memcmp (&i, &j, sizeof (VI2))) > + __builtin_abort (); > +} > + > +VI __attribute__((noinline,noclone)) > +foo (VI i) > +{ > + return -i; > +} > + > +VS __attribute__((noinline,noclone)) > +bar (VS i, VS j) > +{ > + return i + j; > +} > + > +int > +main (void) > +{ > + /* Check that for a vector operation, only the first element with UB is reported. */ > + volatile VC a = (VC) { 0, SCHAR_MAX - 2, SCHAR_MAX - 2, 3, 2, 3, 4, 5, 0, 7, 1, 2, 3, 4, SCHAR_MAX - 13, SCHAR_MAX }; > + volatile VC b = (VC) { 5, 2, 3, 5, 0, 1, 2, 7, 8, 9, 10, 11, 6, -2, 13, 1 }; > + volatile VC k = b + a; > + checkvc (k, (VC) { 5, SCHAR_MAX, SCHAR_MIN, 8, 2, 4, 6, 12, 8, 16, 11, 13, 9, 2, SCHAR_MAX, SCHAR_MIN }); > + k = a + b; > + checkvc (k, (VC) { 5, SCHAR_MAX, SCHAR_MIN, 8, 2, 4, 6, 12, 8, 16, 11, 13, 9, 2, SCHAR_MAX, SCHAR_MIN }); > + > + volatile VS c = (VS) { 0, SHRT_MAX - 2, SHRT_MAX - 2, 3, 3, 4, SHRT_MAX - 13, SHRT_MAX }; > + volatile VS d = (VS) { 5, 2, 3, 5, 6, -2, 13, 1 }; > + volatile VS l = d + c; > + checkvs (l, (VS) { 5, SHRT_MAX, SHRT_MIN, 8, 9, 2, SHRT_MAX, SHRT_MIN }); > + l = bar (c, d); > + checkvs (l, (VS) { 5, SHRT_MAX, SHRT_MIN, 8, 9, 2, SHRT_MAX, SHRT_MIN }); > + > + volatile VI e = (VI) { INT_MAX - 4, INT_MAX - 5, INT_MAX - 13, INT_MAX }; > + volatile VI f = (VI) { 4, 6, 13, 1 }; > + volatile VI m = f + e; > + checkvi (m, (VI) { INT_MAX, INT_MIN, INT_MAX, INT_MIN }); > + m = e + f; > + checkvi (m, (VI) { INT_MAX, INT_MIN, INT_MAX, INT_MIN }); > + > + volatile VI2 g = (VI2) { 0, INT_MAX - 2, INT_MAX - 2, 3, 3, 4, INT_MAX - 13, INT_MAX }; > + volatile VI2 h = (VI2) { 5, 2, 3, 5, 6, -2, 13, 1 }; > + volatile VI2 n = h + g; > + checkvi2 (n, (VI2) { 5, INT_MAX, INT_MIN, 8, 9, 2, INT_MAX, INT_MIN }); > + n = g + h; > + checkvi2 (n, (VI2) { 5, INT_MAX, INT_MIN, 8, 9, 2, INT_MAX, INT_MIN }); > + > + volatile VC a2 = k - b; > + checkvc (a2, a); > + volatile VC b2 = k - a; > + checkvc (b2, b); > + > + volatile VS c2 = l - d; > + checkvs (c2, c); > + volatile VS d2 = l - c; > + checkvs (d2, d); > + > + volatile VI e2 = m - f; > + checkvi (e2, e); > + volatile VI f2 = m - e; > + checkvi (f2, f); > + > + volatile VI2 g2 = n - h; > + checkvi2 (g2, g); > + volatile VI2 h2 = n - g; > + checkvi2 (h2, h); > + > + a = (VC) { 0, SCHAR_MAX / 4, SCHAR_MAX / 4, 3, 2, 3, 4, 5, 0, 7, 1, 2, 3, 4, SCHAR_MAX - 13, SCHAR_MAX }; > + b = (VC) { SCHAR_MAX, 4, 5, 2, 3, 4, 5, 2, 9, 2, 9, 1, 0, 8, 1, 2 }; > + k = a * b; > + checkvc (k, (VC) { 0, 124, -101, 6, 6,12,20,10, 0,14, 9, 2, 0,32, SCHAR_MAX - 13, -2 }); > + > + c = (VS) { 0, SHRT_MAX / 8, SHRT_MAX / 7, 5, 8, 9, SHRT_MAX - 10, SHRT_MAX }; > + d = (VS) { SHRT_MAX, 8, 17, 2, 3, 4, 1, 3 }; > + l = c * d; > + checkvs (l, (VS) { 0, 32760, 14041, 10,24,36, SHRT_MAX - 10, 32765 }); > + > + e = (VI) { INT_MAX, INT_MAX / 5, INT_MAX / 6, INT_MAX }; > + f = (VI) { 0, 5, 7, 2 }; > + m = e * f; > + checkvi (m, (VI) { 0, 2147483645, -1789569709, -2 }); > + > + g = (VI2) { INT_MAX, INT_MAX / 9, INT_MAX / 8, 5, 6, 7, 8, INT_MAX }; > + h = (VI2) { 0, 10, 8, 2, 3, 4, 5, 1 }; > + n = g * h; > + checkvi2 (n,(VI2) { 0, -1908874356, 2147483640, 10,18,28,40, INT_MAX }); > + > + a = (VC) { 5, 7, 8, 9, SCHAR_MAX, SCHAR_MIN, 24, 32, 0, 1, 2, 3, 4, 5, SCHAR_MAX, SCHAR_MIN }; > + k = -a; > + checkvc (k, (VC) {-5,-7,-8,-9,-SCHAR_MAX, SCHAR_MIN,-24,-32, 0,-1,-2,-3,-4,-5,-SCHAR_MAX, SCHAR_MIN }); > + > + c = (VS) { 0, 7, 23, SHRT_MIN, SHRT_MIN, SHRT_MAX, 2, 5 }; > + l = -c; > + checkvs (l, (VS) { 0,-7,-23, SHRT_MIN, SHRT_MIN,-SHRT_MAX,-2,-5 }); > + > + e = (VI) { 5, INT_MAX, INT_MIN, INT_MIN }; > + m = foo (e); > + checkvi (m, (VI) {-5,-INT_MAX, INT_MIN, INT_MIN }); > + > + g = (VI2) { 10, 11, 0, INT_MAX - 2, 1, INT_MIN + 1, 5, INT_MIN }; > + n = -g; > + checkvi2 (n, (VI2) {-10,-11, 0,-INT_MAX + 2,-1, INT_MAX, -5, INT_MIN }); > + return 0; > +} > + > +/* { dg-output "signed integer overflow: 3 \\+ 125 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 125 \\+ 3 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 3 \\+ 32765 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 32765 \\+ 3 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 6 \\+ 2147483642 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 2147483642 \\+ 6 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 3 \\+ 2147483645 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 2147483645 \\+ 3 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: -128 - 3 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: -128 - 125 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: -32768 - 3 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: -32768 - 32765 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 - 6 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 - 2147483642 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 - 3 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 - 2147483645 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 31 \\* 5 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 4681 \\* 17 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 357913941 \\* 7 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*signed integer overflow: 238609294 \\* 10 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*negation of -128 cannot be represented in type 'signed char'; cast to an unsigned type to negate this value to itself\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*negation of -32768 cannot be represented in type 'short int'; cast to an unsigned type to negate this value to itself\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself\[^\n\r]*(\n|\r\n|\r)" } */ > +/* { dg-output "\[^\n\r]*negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself" } */ > > > Jakub > >
--- gcc/ubsan.c.jj 2016-11-14 19:57:07.005897502 +0100 +++ gcc/ubsan.c 2016-11-15 09:09:33.288146293 +0100 @@ -1219,14 +1219,20 @@ instrument_null (gimple_stmt_iterator gs tree ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype, - tree op0, tree op1) + tree op0, tree op1, tree *datap) { if (flag_sanitize_undefined_trap_on_error) return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); - tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc, - ubsan_type_descriptor (lhstype), NULL_TREE, - NULL_TREE); + tree data; + if (datap && *datap) + data = *datap; + else + data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc, + ubsan_type_descriptor (lhstype), NULL_TREE, + NULL_TREE); + if (datap) + *datap = data; enum built_in_function fn_code; switch (code) @@ -1272,14 +1278,15 @@ instrument_si_overflow (gimple_stmt_iter tree_code code = gimple_assign_rhs_code (stmt); tree lhs = gimple_assign_lhs (stmt); tree lhstype = TREE_TYPE (lhs); + tree lhsinner = VECTOR_TYPE_P (lhstype) ? TREE_TYPE (lhstype) : lhstype; tree a, b; gimple *g; /* If this is not a signed operation, don't instrument anything here. Also punt on bit-fields. */ - if (!INTEGRAL_TYPE_P (lhstype) - || TYPE_OVERFLOW_WRAPS (lhstype) - || GET_MODE_BITSIZE (TYPE_MODE (lhstype)) != TYPE_PRECISION (lhstype)) + if (!INTEGRAL_TYPE_P (lhsinner) + || TYPE_OVERFLOW_WRAPS (lhsinner) + || GET_MODE_BITSIZE (TYPE_MODE (lhsinner)) != TYPE_PRECISION (lhsinner)) return; switch (code) @@ -1305,7 +1312,7 @@ instrument_si_overflow (gimple_stmt_iter /* Represent i = -u; as i = UBSAN_CHECK_SUB (0, u); */ - a = build_int_cst (lhstype, 0); + a = build_zero_cst (lhstype); b = gimple_assign_rhs1 (stmt); g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b); gimple_call_set_lhs (g, lhs); @@ -1316,7 +1323,7 @@ instrument_si_overflow (gimple_stmt_iter into _N = UBSAN_CHECK_SUB (0, u); i = ABS_EXPR<_N>; */ - a = build_int_cst (lhstype, 0); + a = build_zero_cst (lhstype); b = gimple_assign_rhs1 (stmt); g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b); a = make_ssa_name (lhstype); --- gcc/ubsan.h.jj 2016-11-14 19:57:07.027897220 +0100 +++ gcc/ubsan.h 2016-11-14 20:37:20.892032650 +0100 @@ -52,7 +52,8 @@ extern tree ubsan_create_data (const cha extern tree ubsan_type_descriptor (tree, enum ubsan_print_style = UBSAN_PRINT_NORMAL); extern tree ubsan_encode_value (tree, bool = false); extern bool is_ubsan_builtin_p (tree); -extern tree ubsan_build_overflow_builtin (tree_code, location_t, tree, tree, tree); +extern tree ubsan_build_overflow_builtin (tree_code, location_t, tree, tree, + tree, tree *); extern tree ubsan_instrument_float_cast (location_t, tree, tree); extern tree ubsan_get_source_location_type (void); --- gcc/tree-vrp.c.jj 2016-11-14 19:57:06.957898116 +0100 +++ gcc/tree-vrp.c 2016-11-14 20:37:20.897032586 +0100 @@ -10023,7 +10023,11 @@ simplify_internal_call_using_ranges (gim tree op1 = gimple_call_arg (stmt, 1); tree type; if (is_ubsan) - type = TREE_TYPE (op0); + { + type = TREE_TYPE (op0); + if (VECTOR_TYPE_P (type)) + return false; + } else if (gimple_call_lhs (stmt) == NULL_TREE) return false; else --- gcc/internal-fn.c.jj 2016-11-14 19:57:10.754849526 +0100 +++ gcc/internal-fn.c 2016-11-15 09:15:13.375839832 +0100 @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. #include "ubsan.h" #include "recog.h" #include "builtins.h" +#include "optabs-tree.h" /* The names of each internal function, indexed by function number. */ const char *const internal_fn_name_array[] = { @@ -513,7 +514,7 @@ expand_ubsan_result_store (rtx target, r static void expand_addsub_overflow (location_t loc, tree_code code, tree lhs, tree arg0, tree arg1, bool unsr_p, bool uns0_p, - bool uns1_p, bool is_ubsan) + bool uns1_p, bool is_ubsan, tree *datap) { rtx res, target = NULL_RTX; tree fn; @@ -929,7 +930,7 @@ expand_addsub_overflow (location_t loc, /* Expand the ubsan builtin call. */ push_temp_slots (); fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0), - arg0, arg1); + arg0, arg1, datap); expand_normal (fn); pop_temp_slots (); do_pending_stack_adjust (); @@ -958,7 +959,8 @@ expand_addsub_overflow (location_t loc, /* Add negate overflow checking to the statement STMT. */ static void -expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan) +expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan, + tree *datap) { rtx res, op1; tree fn; @@ -1024,7 +1026,7 @@ expand_neg_overflow (location_t loc, tre /* Expand the ubsan builtin call. */ push_temp_slots (); fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1), - arg1, NULL_TREE); + arg1, NULL_TREE, datap); expand_normal (fn); pop_temp_slots (); do_pending_stack_adjust (); @@ -1048,7 +1050,8 @@ expand_neg_overflow (location_t loc, tre static void expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, - bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan) + bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan, + tree *datap) { rtx res, op0, op1; tree fn, type; @@ -1685,7 +1688,7 @@ expand_mul_overflow (location_t loc, tre /* Expand the ubsan builtin call. */ push_temp_slots (); fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (arg0), - arg0, arg1); + arg0, arg1, datap); expand_normal (fn); pop_temp_slots (); do_pending_stack_adjust (); @@ -1734,6 +1737,145 @@ expand_mul_overflow (location_t loc, tre } } +/* Expand UBSAN_CHECK_* internal function if it has vector operands. */ + +static void +expand_vector_ubsan_overflow (location_t loc, enum tree_code code, tree lhs, + tree arg0, tree arg1) +{ + int cnt = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + rtx_code_label *loop_lab = NULL; + rtx cntvar = NULL_RTX; + tree cntv = NULL_TREE; + tree eltype = TREE_TYPE (TREE_TYPE (arg0)); + tree sz = TYPE_SIZE (eltype); + tree data = NULL_TREE; + tree resv = NULL_TREE; + rtx lhsr = NULL_RTX; + rtx resvr = NULL_RTX; + + if (lhs) + { + optab op; + lhsr = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); + if (GET_MODE (lhsr) == BLKmode + || (op = optab_for_tree_code (code, TREE_TYPE (arg0), + optab_default)) == unknown_optab + || (optab_handler (op, TYPE_MODE (TREE_TYPE (arg0))) + == CODE_FOR_nothing)) + { + if (MEM_P (lhsr)) + resv = make_tree (TREE_TYPE (lhs), lhsr); + else + { + resvr = assign_temp (TREE_TYPE (lhs), 1, 1); + resv = make_tree (TREE_TYPE (lhs), resvr); + } + } + } + if (cnt > 4) + { + do_pending_stack_adjust (); + loop_lab = gen_label_rtx (); + cntvar = gen_reg_rtx (TYPE_MODE (sizetype)); + cntv = make_tree (sizetype, cntvar); + emit_move_insn (cntvar, const0_rtx); + emit_label (loop_lab); + } + if (TREE_CODE (arg0) != VECTOR_CST) + { + rtx arg0r = expand_normal (arg0); + arg0 = make_tree (TREE_TYPE (arg0), arg0r); + } + if (TREE_CODE (arg1) != VECTOR_CST) + { + rtx arg1r = expand_normal (arg1); + arg1 = make_tree (TREE_TYPE (arg1), arg1r); + } + for (int i = 0; i < (cnt > 4 ? 1 : cnt); i++) + { + tree op0, op1, res = NULL_TREE; + if (cnt > 4) + { + tree atype = build_array_type_nelts (eltype, cnt); + op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg0); + op0 = build4_loc (loc, ARRAY_REF, eltype, op0, cntv, + NULL_TREE, NULL_TREE); + op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg1); + op1 = build4_loc (loc, ARRAY_REF, eltype, op1, cntv, + NULL_TREE, NULL_TREE); + if (resv) + { + res = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, resv); + res = build4_loc (loc, ARRAY_REF, eltype, res, cntv, + NULL_TREE, NULL_TREE); + } + } + else + { + tree bitpos = bitsize_int (tree_to_uhwi (sz) * i); + op0 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg0, sz, bitpos); + op1 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg1, sz, bitpos); + if (resv) + res = fold_build3_loc (loc, BIT_FIELD_REF, eltype, resv, sz, + bitpos); + } + switch (code) + { + case PLUS_EXPR: + expand_addsub_overflow (loc, PLUS_EXPR, res, op0, op1, + false, false, false, true, &data); + break; + case MINUS_EXPR: + if (cnt > 4 ? integer_zerop (arg0) : integer_zerop (op0)) + expand_neg_overflow (loc, res, op1, true, &data); + else + expand_addsub_overflow (loc, MINUS_EXPR, res, op0, op1, + false, false, false, true, &data); + break; + case MULT_EXPR: + expand_mul_overflow (loc, res, op0, op1, false, false, false, + true, &data); + break; + default: + gcc_unreachable (); + } + } + if (cnt > 4) + { + struct separate_ops ops; + ops.code = PLUS_EXPR; + ops.type = TREE_TYPE (cntv); + ops.op0 = cntv; + ops.op1 = build_int_cst (TREE_TYPE (cntv), 1); + ops.op2 = NULL_TREE; + ops.location = loc; + rtx ret = expand_expr_real_2 (&ops, cntvar, TYPE_MODE (sizetype), + EXPAND_NORMAL); + if (ret != cntvar) + emit_move_insn (cntvar, ret); + do_compare_rtx_and_jump (cntvar, GEN_INT (cnt), NE, false, + TYPE_MODE (sizetype), NULL_RTX, NULL, loop_lab, + PROB_VERY_LIKELY); + } + if (lhs && resv == NULL_TREE) + { + struct separate_ops ops; + ops.code = code; + ops.type = TREE_TYPE (arg0); + ops.op0 = arg0; + ops.op1 = arg1; + ops.op2 = NULL_TREE; + ops.location = loc; + rtx ret = expand_expr_real_2 (&ops, lhsr, TYPE_MODE (TREE_TYPE (arg0)), + EXPAND_NORMAL); + if (ret != lhsr) + emit_move_insn (lhsr, ret); + } + else if (resvr) + emit_move_insn (lhsr, resvr); +} + /* Expand UBSAN_CHECK_ADD call STMT. */ static void @@ -1743,8 +1885,11 @@ expand_UBSAN_CHECK_ADD (internal_fn, gca tree lhs = gimple_call_lhs (stmt); tree arg0 = gimple_call_arg (stmt, 0); tree arg1 = gimple_call_arg (stmt, 1); - expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1, - false, false, false, true); + if (VECTOR_TYPE_P (TREE_TYPE (arg0))) + expand_vector_ubsan_overflow (loc, PLUS_EXPR, lhs, arg0, arg1); + else + expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1, + false, false, false, true, NULL); } /* Expand UBSAN_CHECK_SUB call STMT. */ @@ -1756,11 +1901,13 @@ expand_UBSAN_CHECK_SUB (internal_fn, gca tree lhs = gimple_call_lhs (stmt); tree arg0 = gimple_call_arg (stmt, 0); tree arg1 = gimple_call_arg (stmt, 1); - if (integer_zerop (arg0)) - expand_neg_overflow (loc, lhs, arg1, true); + if (VECTOR_TYPE_P (TREE_TYPE (arg0))) + expand_vector_ubsan_overflow (loc, MINUS_EXPR, lhs, arg0, arg1); + else if (integer_zerop (arg0)) + expand_neg_overflow (loc, lhs, arg1, true, NULL); else expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1, - false, false, false, true); + false, false, false, true, NULL); } /* Expand UBSAN_CHECK_MUL call STMT. */ @@ -1772,7 +1919,11 @@ expand_UBSAN_CHECK_MUL (internal_fn, gca tree lhs = gimple_call_lhs (stmt); tree arg0 = gimple_call_arg (stmt, 0); tree arg1 = gimple_call_arg (stmt, 1); - expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true); + if (VECTOR_TYPE_P (TREE_TYPE (arg0))) + expand_vector_ubsan_overflow (loc, MULT_EXPR, lhs, arg0, arg1); + else + expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true, + NULL); } /* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion. */ @@ -1864,17 +2015,17 @@ expand_arith_overflow (enum tree_code co case MINUS_EXPR: if (integer_zerop (arg0) && !unsr_p) { - expand_neg_overflow (loc, lhs, arg1, false); + expand_neg_overflow (loc, lhs, arg1, false, NULL); return; } /* FALLTHRU */ case PLUS_EXPR: - expand_addsub_overflow (loc, code, lhs, arg0, arg1, - unsr_p, unsr_p, unsr_p, false); + expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p, + unsr_p, unsr_p, false, NULL); return; case MULT_EXPR: - expand_mul_overflow (loc, lhs, arg0, arg1, - unsr_p, unsr_p, unsr_p, false); + expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p, + unsr_p, unsr_p, false, NULL); return; default: gcc_unreachable (); @@ -1916,10 +2067,10 @@ expand_arith_overflow (enum tree_code co arg1 = fold_convert_loc (loc, types[uns1_p], arg1); if (code != MULT_EXPR) expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p, - uns0_p, uns1_p, false); + uns0_p, uns1_p, false, NULL); else expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p, - uns0_p, uns1_p, false); + uns0_p, uns1_p, false, NULL); return; } --- gcc/testsuite/c-c++-common/ubsan/overflow-vec-1.c.jj 2016-11-14 20:37:20.893032637 +0100 +++ gcc/testsuite/c-c++-common/ubsan/overflow-vec-1.c 2016-11-15 09:28:24.000000000 +0100 @@ -0,0 +1,144 @@ +/* { dg-do run } */ +/* { dg-options "-Wno-psabi -fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover=signed-integer-overflow" } */ + +#define SCHAR_MAX __SCHAR_MAX__ +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) +#define SHRT_MAX __SHRT_MAX__ +#define SHRT_MIN (-__SHRT_MAX__ - 1) +#define INT_MAX __INT_MAX__ +#define INT_MIN (-__INT_MAX__ - 1) + +typedef signed char VC __attribute__((vector_size (16))); +typedef short VS __attribute__((vector_size (8 * sizeof (short)))); +typedef int VI __attribute__((vector_size (4 * sizeof (int)))); +typedef int VI2 __attribute__((vector_size (16 * sizeof (int)))); + +void __attribute__((noinline,noclone)) +checkvc (VC i, VC j) +{ + if (__builtin_memcmp (&i, &j, sizeof (VC))) + __builtin_abort (); +} + +void __attribute__((noinline,noclone)) +checkvs (VS i, VS j) +{ + if (__builtin_memcmp (&i, &j, sizeof (VS))) + __builtin_abort (); +} + +void __attribute__((noinline,noclone)) +checkvi (VI i, VI j) +{ + if (__builtin_memcmp (&i, &j, sizeof (VI))) + __builtin_abort (); +} + +void __attribute__((noinline,noclone)) +checkvi2 (VI2 i, VI2 j) +{ + if (__builtin_memcmp (&i, &j, sizeof (VI2))) + __builtin_abort (); +} + +VI __attribute__((noinline,noclone)) +foo (VI i) +{ + return -i; +} + +VS __attribute__((noinline,noclone)) +bar (VS i, VS j) +{ + return i + j; +} + +int +main (void) +{ + /* Check that for a vector operation, only the first element with UB is reported. */ + volatile VC a = (VC) { 0, SCHAR_MAX - 2, SCHAR_MAX - 2, 3, 2, 3, 4, 5, 0, 7, 1, 2, 3, 4, SCHAR_MAX - 13, SCHAR_MAX }; + volatile VC b = (VC) { 5, 2, 1, 5, 0, 1, 2, 7, 8, 9, 10, 11, 6, -2, 13, 0 }; + volatile VC k = b + a; + checkvc (k, (VC) { 5, SCHAR_MAX, SCHAR_MAX - 1, 8, 2, 4, 6, 12, 8, 16, 11, 13, 9, 2, SCHAR_MAX, SCHAR_MAX }); + k = a + b; + checkvc (k, (VC) { 5, SCHAR_MAX, SCHAR_MAX - 1, 8, 2, 4, 6, 12, 8, 16, 11, 13, 9, 2, SCHAR_MAX, SCHAR_MAX }); + + volatile VS c = (VS) { 0, SHRT_MAX - 2, SHRT_MAX - 2, 3, 3, 4, SHRT_MAX - 13, SHRT_MAX }; + volatile VS d = (VS) { 5, 2, -3, 5, 6, -2, 13, -1 }; + volatile VS l = d + c; + checkvs (l, (VS) { 5, SHRT_MAX, SHRT_MAX - 5, 8, 9, 2, SHRT_MAX, SHRT_MAX - 1 }); + l = bar (c, d); + checkvs (l, (VS) { 5, SHRT_MAX, SHRT_MAX - 5, 8, 9, 2, SHRT_MAX, SHRT_MAX - 1 }); + + volatile VI e = (VI) { INT_MAX - 4, INT_MAX - 5, INT_MAX - 13, INT_MAX }; + volatile VI f = (VI) { 4, -6, 13, 0 }; + volatile VI m = f + e; + checkvi (m, (VI) { INT_MAX, INT_MAX - 11,INT_MAX, INT_MAX }); + m = e + f; + checkvi (m, (VI) { INT_MAX, INT_MAX - 11,INT_MAX, INT_MAX }); + + volatile VI2 g = (VI2) { 0, INT_MAX - 2, INT_MAX - 2, 3, 3, 4, INT_MAX - 13, INT_MAX }; + volatile VI2 h = (VI2) { 5, 2, -5, 5, 6, -2, 13, -1 }; + volatile VI2 n = h + g; + checkvi2 (n, (VI2) { 5, INT_MAX, INT_MAX - 7, 8, 9, 2, INT_MAX, INT_MAX - 1 }); + n = g + h; + checkvi2 (n, (VI2) { 5, INT_MAX, INT_MAX - 7, 8, 9, 2, INT_MAX, INT_MAX - 1 }); + + volatile VC a2 = k - b; + checkvc (a2, a); + volatile VC b2 = k - a; + checkvc (b2, b); + + volatile VS c2 = l - d; + checkvs (c2, c); + volatile VS d2 = l - c; + checkvs (d2, d); + + volatile VI e2 = m - f; + checkvi (e2, e); + volatile VI f2 = m - e; + checkvi (f2, f); + + volatile VI2 g2 = n - h; + checkvi2 (g2, g); + volatile VI2 h2 = n - g; + checkvi2 (h2, h); + + a = (VC) { 0, SCHAR_MAX / 4, SCHAR_MAX / 4, 3, 2, 3, 4, 5, 0, 7, 1, 2, 3, 4, SCHAR_MAX - 13, SCHAR_MAX }; + b = (VC) { SCHAR_MAX, 4, 3, 2, 3, 4, 5, 2, 9, 2, 9, 1, 0, 8, 1, 1 }; + k = a * b; + checkvc (k, (VC) { 0, 124, 93, 6, 6,12,20,10, 0,14, 9, 2, 0,32, SCHAR_MAX - 13, SCHAR_MAX }); + + c = (VS) { 0, SHRT_MAX / 8, SHRT_MAX / 7, 5, 8, 9, SHRT_MAX - 10, SHRT_MAX }; + d = (VS) { SHRT_MAX, 8, 6, 2, 3, 4, 1, 1 }; + l = c * d; + checkvs (l, (VS) { 0, 32760, 28086, 10,24,36, SHRT_MAX - 10, SHRT_MAX }); + + e = (VI) { INT_MAX, INT_MAX / 5, INT_MAX / 6, INT_MAX }; + f = (VI) { 0, 5, 5, 1 }; + m = e * f; + checkvi (m, (VI) { 0, 2147483645, 1789569705, INT_MAX }); + + g = (VI2) { INT_MAX, INT_MAX / 9, INT_MAX / 8, 5, 6, 7, 8, INT_MAX }; + h = (VI2) { 0, 8, 8, 2, 3, 4, 5, 1 }; + n = g * h; + checkvi2 (n,(VI2) { 0, 1908874352, 2147483640, 10,18,28,40, INT_MAX }); + + a = (VC) { 5, 7, 8, 9, SCHAR_MAX, SCHAR_MIN + 1, 24, 32, 0, 1, 2, 3, 4, 5, SCHAR_MAX, SCHAR_MIN + 2 }; + k = -a; + checkvc (k, (VC) {-5,-7,-8,-9,-SCHAR_MAX, SCHAR_MAX, -24,-32, 0,-1,-2,-3,-4,-5,-SCHAR_MAX, SCHAR_MAX - 1 }); + + c = (VS) { 0, 7, 23, SHRT_MIN + 1, SHRT_MIN + 2, SHRT_MAX, 2, 5 }; + l = -c; + checkvs (l, (VS) { 0,-7,-23, SHRT_MAX, SHRT_MAX - 1,-SHRT_MAX,-2,-5 }); + + e = (VI) { 5, INT_MAX, INT_MIN + 1, INT_MIN + 2 }; + m = foo (e); + checkvi (m, (VI) {-5,-INT_MAX, INT_MAX, INT_MAX - 1 }); + + g = (VI2) { 10, 11, 0, INT_MAX - 2, 1, INT_MIN + 1, 5, INT_MIN / 2 }; + n = -g; + checkvi2 (n, (VI2) {-10,-11, 0,-INT_MAX + 2,-1, INT_MAX, -5, INT_MAX / 2 + 1 }); + return 0; +} --- gcc/testsuite/c-c++-common/ubsan/overflow-vec-2.c.jj 2016-11-14 20:37:20.894032625 +0100 +++ gcc/testsuite/c-c++-common/ubsan/overflow-vec-2.c 2016-11-15 09:15:54.000000000 +0100 @@ -0,0 +1,169 @@ +/* { dg-do run } */ +/* { dg-options "-Wno-psabi -fsanitize=signed-integer-overflow -Wno-unused-variable -fsanitize-recover=signed-integer-overflow" } */ + +#define SCHAR_MAX __SCHAR_MAX__ +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) +#define SHRT_MAX __SHRT_MAX__ +#define SHRT_MIN (-__SHRT_MAX__ - 1) +#define INT_MAX __INT_MAX__ +#define INT_MIN (-__INT_MAX__ - 1) + +typedef signed char VC __attribute__((vector_size (16))); +typedef short VS __attribute__((vector_size (8 * sizeof (short)))); +typedef int VI __attribute__((vector_size (4 * sizeof (int)))); +typedef int VI2 __attribute__((vector_size (16 * sizeof (int)))); + +void __attribute__((noinline,noclone)) +checkvc (VC i, VC j) +{ + if (__builtin_memcmp (&i, &j, sizeof (VC))) + __builtin_abort (); +} + +void __attribute__((noinline,noclone)) +checkvs (VS i, VS j) +{ + if (__builtin_memcmp (&i, &j, sizeof (VS))) + __builtin_abort (); +} + +void __attribute__((noinline,noclone)) +checkvi (VI i, VI j) +{ + if (__builtin_memcmp (&i, &j, sizeof (VI))) + __builtin_abort (); +} + +void __attribute__((noinline,noclone)) +checkvi2 (VI2 i, VI2 j) +{ + if (__builtin_memcmp (&i, &j, sizeof (VI2))) + __builtin_abort (); +} + +VI __attribute__((noinline,noclone)) +foo (VI i) +{ + return -i; +} + +VS __attribute__((noinline,noclone)) +bar (VS i, VS j) +{ + return i + j; +} + +int +main (void) +{ + /* Check that for a vector operation, only the first element with UB is reported. */ + volatile VC a = (VC) { 0, SCHAR_MAX - 2, SCHAR_MAX - 2, 3, 2, 3, 4, 5, 0, 7, 1, 2, 3, 4, SCHAR_MAX - 13, SCHAR_MAX }; + volatile VC b = (VC) { 5, 2, 3, 5, 0, 1, 2, 7, 8, 9, 10, 11, 6, -2, 13, 1 }; + volatile VC k = b + a; + checkvc (k, (VC) { 5, SCHAR_MAX, SCHAR_MIN, 8, 2, 4, 6, 12, 8, 16, 11, 13, 9, 2, SCHAR_MAX, SCHAR_MIN }); + k = a + b; + checkvc (k, (VC) { 5, SCHAR_MAX, SCHAR_MIN, 8, 2, 4, 6, 12, 8, 16, 11, 13, 9, 2, SCHAR_MAX, SCHAR_MIN }); + + volatile VS c = (VS) { 0, SHRT_MAX - 2, SHRT_MAX - 2, 3, 3, 4, SHRT_MAX - 13, SHRT_MAX }; + volatile VS d = (VS) { 5, 2, 3, 5, 6, -2, 13, 1 }; + volatile VS l = d + c; + checkvs (l, (VS) { 5, SHRT_MAX, SHRT_MIN, 8, 9, 2, SHRT_MAX, SHRT_MIN }); + l = bar (c, d); + checkvs (l, (VS) { 5, SHRT_MAX, SHRT_MIN, 8, 9, 2, SHRT_MAX, SHRT_MIN }); + + volatile VI e = (VI) { INT_MAX - 4, INT_MAX - 5, INT_MAX - 13, INT_MAX }; + volatile VI f = (VI) { 4, 6, 13, 1 }; + volatile VI m = f + e; + checkvi (m, (VI) { INT_MAX, INT_MIN, INT_MAX, INT_MIN }); + m = e + f; + checkvi (m, (VI) { INT_MAX, INT_MIN, INT_MAX, INT_MIN }); + + volatile VI2 g = (VI2) { 0, INT_MAX - 2, INT_MAX - 2, 3, 3, 4, INT_MAX - 13, INT_MAX }; + volatile VI2 h = (VI2) { 5, 2, 3, 5, 6, -2, 13, 1 }; + volatile VI2 n = h + g; + checkvi2 (n, (VI2) { 5, INT_MAX, INT_MIN, 8, 9, 2, INT_MAX, INT_MIN }); + n = g + h; + checkvi2 (n, (VI2) { 5, INT_MAX, INT_MIN, 8, 9, 2, INT_MAX, INT_MIN }); + + volatile VC a2 = k - b; + checkvc (a2, a); + volatile VC b2 = k - a; + checkvc (b2, b); + + volatile VS c2 = l - d; + checkvs (c2, c); + volatile VS d2 = l - c; + checkvs (d2, d); + + volatile VI e2 = m - f; + checkvi (e2, e); + volatile VI f2 = m - e; + checkvi (f2, f); + + volatile VI2 g2 = n - h; + checkvi2 (g2, g); + volatile VI2 h2 = n - g; + checkvi2 (h2, h); + + a = (VC) { 0, SCHAR_MAX / 4, SCHAR_MAX / 4, 3, 2, 3, 4, 5, 0, 7, 1, 2, 3, 4, SCHAR_MAX - 13, SCHAR_MAX }; + b = (VC) { SCHAR_MAX, 4, 5, 2, 3, 4, 5, 2, 9, 2, 9, 1, 0, 8, 1, 2 }; + k = a * b; + checkvc (k, (VC) { 0, 124, -101, 6, 6,12,20,10, 0,14, 9, 2, 0,32, SCHAR_MAX - 13, -2 }); + + c = (VS) { 0, SHRT_MAX / 8, SHRT_MAX / 7, 5, 8, 9, SHRT_MAX - 10, SHRT_MAX }; + d = (VS) { SHRT_MAX, 8, 17, 2, 3, 4, 1, 3 }; + l = c * d; + checkvs (l, (VS) { 0, 32760, 14041, 10,24,36, SHRT_MAX - 10, 32765 }); + + e = (VI) { INT_MAX, INT_MAX / 5, INT_MAX / 6, INT_MAX }; + f = (VI) { 0, 5, 7, 2 }; + m = e * f; + checkvi (m, (VI) { 0, 2147483645, -1789569709, -2 }); + + g = (VI2) { INT_MAX, INT_MAX / 9, INT_MAX / 8, 5, 6, 7, 8, INT_MAX }; + h = (VI2) { 0, 10, 8, 2, 3, 4, 5, 1 }; + n = g * h; + checkvi2 (n,(VI2) { 0, -1908874356, 2147483640, 10,18,28,40, INT_MAX }); + + a = (VC) { 5, 7, 8, 9, SCHAR_MAX, SCHAR_MIN, 24, 32, 0, 1, 2, 3, 4, 5, SCHAR_MAX, SCHAR_MIN }; + k = -a; + checkvc (k, (VC) {-5,-7,-8,-9,-SCHAR_MAX, SCHAR_MIN,-24,-32, 0,-1,-2,-3,-4,-5,-SCHAR_MAX, SCHAR_MIN }); + + c = (VS) { 0, 7, 23, SHRT_MIN, SHRT_MIN, SHRT_MAX, 2, 5 }; + l = -c; + checkvs (l, (VS) { 0,-7,-23, SHRT_MIN, SHRT_MIN,-SHRT_MAX,-2,-5 }); + + e = (VI) { 5, INT_MAX, INT_MIN, INT_MIN }; + m = foo (e); + checkvi (m, (VI) {-5,-INT_MAX, INT_MIN, INT_MIN }); + + g = (VI2) { 10, 11, 0, INT_MAX - 2, 1, INT_MIN + 1, 5, INT_MIN }; + n = -g; + checkvi2 (n, (VI2) {-10,-11, 0,-INT_MAX + 2,-1, INT_MAX, -5, INT_MIN }); + return 0; +} + +/* { dg-output "signed integer overflow: 3 \\+ 125 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 125 \\+ 3 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 3 \\+ 32765 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 32765 \\+ 3 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 6 \\+ 2147483642 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 2147483642 \\+ 6 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 3 \\+ 2147483645 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 2147483645 \\+ 3 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: -128 - 3 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: -128 - 125 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: -32768 - 3 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: -32768 - 32765 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 - 6 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 - 2147483642 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 - 3 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 - 2147483645 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 31 \\* 5 cannot be represented in type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 4681 \\* 17 cannot be represented in type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 357913941 \\* 7 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*signed integer overflow: 238609294 \\* 10 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*negation of -128 cannot be represented in type 'signed char'; cast to an unsigned type to negate this value to itself\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*negation of -32768 cannot be represented in type 'short int'; cast to an unsigned type to negate this value to itself\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself" } */