diff mbox

Support -fsanitize=integer-arith-overflow even for vectors (PR sanitizer/77823)

Message ID 20161115140313.GE3541@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Nov. 15, 2016, 2:03 p.m. UTC
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.



	Jakub

Comments

Jeff Law Nov. 15, 2016, 3:39 p.m. UTC | #1
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
Richard Biener Nov. 16, 2016, 8:22 a.m. UTC | #2
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
> 
>
diff mbox

Patch

--- 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" } */