diff mbox

Add signed integer overflow checking to ubsan

Message ID 20131127081302.GD31608@redhat.com
State New
Headers show

Commit Message

Marek Polacek Nov. 27, 2013, 8:13 a.m. UTC
On Fri, Nov 22, 2013 at 10:54:16AM +0100, Marek Polacek wrote:
> Hi!
> 
> Working virtually out of Pago Pago.
> 
> The following is the implementation of the signed integer overflow
> checking for the UndefinedBehaviorSanitizer.  I wrote some of the
> generic bits; Jakub did the i?86 handlind/optabs as well as VRP/fold
> bits.

I'd like to ping this patch.  Here's a rebased version that contains
a fix for miscompilation with -Os -m32.

2013-11-27  Jakub Jelinek  <jakub@redhat.com>
            Marek Polacek  <polacek@redhat.com>

        * opts.c (common_handle_option): Handle
        -fsanitize=signed-integer-overflow.
        * config/i386/i386.md (addv<mode>4, subv<mode>4, mulv<mode>4,
        negv<mode>3, negv<mode>3_1): Define expands.
        (*addv<mode>4, *subv<mode>4, *mulv<mode>4, *negv<mode>3): Define
        insns.
       	* sanitizer.def (BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW,
        BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW,
        BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW,
        BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW): Define.
        * ubsan.h (PROB_VERY_UNLIKELY, PROB_EVEN, PROB_VERY_LIKELY,
        PROB_ALWAYS): Define.
        (ubsan_build_overflow_builtin): Declare.
       	* gimple-fold.c (gimple_fold_stmt_to_constant_1): Add folding of
        internal functions.
        * ubsan.c (PROB_VERY_UNLIKELY): Don't define here.
        (ubsan_build_overflow_builtin): New function.
        (instrument_si_overflow): Likewise.
        (ubsan_pass): Add signed integer overflow checking.
        (gate_ubsan): Enable the pass also when SANITIZE_SI_OVERFLOW.
        * flag-types.h (enum sanitize_code): Add SANITIZE_SI_OVERFLOW.
        * internal-fn.c: Include ubsan.h and target.h.
        (ubsan_expand_si_overflow_addsub_check): New function.
        (ubsan_expand_si_overflow_neg_check): Likewise.
       	(ubsan_expand_si_overflow_mul_check): Likewise.
        (expand_UBSAN_CHECK_ADD): Likewise.
        (expand_UBSAN_CHECK_SUB): Likewise.
        (expand_UBSAN_CHECK_MUL): Likewise.
        * fold-const.c (fold_binary_loc): Don't fold A + (-B) -> A - B and
        (-A) + B -> B - A when doing the signed integer overflow checking.
        * internal-fn.def (UBSAN_CHECK_ADD, UBSAN_CHECK_SUB, UBSAN_CHECK_MUL):
        Define.
        * tree-vrp.c (extract_range_basic): Handle internal calls.
        * optabs.def (addv4_optab, subv4_optab, mulv4_optab, negv4_optab): New
        optabs.
c-family/
        * c-gimplify.c (c_gimplify_expr): If doing the integer-overflow
        sanitization, call unsigned_type_for only when !TYPE_OVERFLOW_WRAPS.
testsuite/
        * c-c++-common/ubsan/overflow-mul-2.c: New test.
        * c-c++-common/ubsan/overflow-add-1.c: New test.
        * c-c++-common/ubsan/overflow-add-2.c: New test.
        * c-c++-common/ubsan/overflow-mul-1.c: New test.
        * c-c++-common/ubsan/overflow-sub-1.c: New test.
        * c-c++-common/ubsan/overflow-sub-2.c: New test.
        * c-c++-common/ubsan/overflow-negate-1.c: New test.


	Marek

Comments

Jeff Law Dec. 3, 2013, 9:14 p.m. UTC | #1
On 11/27/13 01:13, Marek Polacek wrote:
> On Fri, Nov 22, 2013 at 10:54:16AM +0100, Marek Polacek wrote:
>> Hi!
>>
>> Working virtually out of Pago Pago.
>>
>> The following is the implementation of the signed integer overflow
>> checking for the UndefinedBehaviorSanitizer.  I wrote some of the
>> generic bits; Jakub did the i?86 handlind/optabs as well as VRP/fold
>> bits.
>
> I'd like to ping this patch.  Here's a rebased version that contains
> a fix for miscompilation with -Os -m32.
>
> 2013-11-27  Jakub Jelinek  <jakub@redhat.com>
>              Marek Polacek  <polacek@redhat.com>
>
>          * opts.c (common_handle_option): Handle
>          -fsanitize=signed-integer-overflow.
>          * config/i386/i386.md (addv<mode>4, subv<mode>4, mulv<mode>4,
>          negv<mode>3, negv<mode>3_1): Define expands.
>          (*addv<mode>4, *subv<mode>4, *mulv<mode>4, *negv<mode>3): Define
>          insns.
>         	* sanitizer.def (BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW,
>          BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW,
>          BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW,
>          BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW): Define.
>          * ubsan.h (PROB_VERY_UNLIKELY, PROB_EVEN, PROB_VERY_LIKELY,
>          PROB_ALWAYS): Define.
>          (ubsan_build_overflow_builtin): Declare.
>         	* gimple-fold.c (gimple_fold_stmt_to_constant_1): Add folding of
>          internal functions.
>          * ubsan.c (PROB_VERY_UNLIKELY): Don't define here.
>          (ubsan_build_overflow_builtin): New function.
>          (instrument_si_overflow): Likewise.
>          (ubsan_pass): Add signed integer overflow checking.
>          (gate_ubsan): Enable the pass also when SANITIZE_SI_OVERFLOW.
>          * flag-types.h (enum sanitize_code): Add SANITIZE_SI_OVERFLOW.
>          * internal-fn.c: Include ubsan.h and target.h.
>          (ubsan_expand_si_overflow_addsub_check): New function.
>          (ubsan_expand_si_overflow_neg_check): Likewise.
>         	(ubsan_expand_si_overflow_mul_check): Likewise.
>          (expand_UBSAN_CHECK_ADD): Likewise.
>          (expand_UBSAN_CHECK_SUB): Likewise.
>          (expand_UBSAN_CHECK_MUL): Likewise.
>          * fold-const.c (fold_binary_loc): Don't fold A + (-B) -> A - B and
>          (-A) + B -> B - A when doing the signed integer overflow checking.
>          * internal-fn.def (UBSAN_CHECK_ADD, UBSAN_CHECK_SUB, UBSAN_CHECK_MUL):
>          Define.
>          * tree-vrp.c (extract_range_basic): Handle internal calls.
>          * optabs.def (addv4_optab, subv4_optab, mulv4_optab, negv4_optab): New
>          optabs.
> c-family/
>          * c-gimplify.c (c_gimplify_expr): If doing the integer-overflow
>          sanitization, call unsigned_type_for only when !TYPE_OVERFLOW_WRAPS.
> testsuite/
>          * c-c++-common/ubsan/overflow-mul-2.c: New test.
>          * c-c++-common/ubsan/overflow-add-1.c: New test.
>          * c-c++-common/ubsan/overflow-add-2.c: New test.
>          * c-c++-common/ubsan/overflow-mul-1.c: New test.
>          * c-c++-common/ubsan/overflow-sub-1.c: New test.
>          * c-c++-common/ubsan/overflow-sub-2.c: New test.
>          * c-c++-common/ubsan/overflow-negate-1.c: New test.
Perhaps split this patch into two parts which can be reviewed 
independently, but go into the tree at the same time.  The obvious hope 
would be that Uros or one of the other x86 backend folks could chime in 
on that part.




> --- gcc/ubsan.h.mp	2013-11-27 08:46:28.046629473 +0100
> +++ gcc/ubsan.h	2013-11-27 08:46:57.578753342 +0100
> @@ -21,6 +21,12 @@ along with GCC; see the file COPYING3.
>   #ifndef GCC_UBSAN_H
>   #define GCC_UBSAN_H
>
> +/* From predict.c.  */
> +#define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
> +#define PROB_EVEN		(REG_BR_PROB_BASE / 2)
> +#define PROB_VERY_LIKELY	(REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
> +#define PROB_ALWAYS		(REG_BR_PROB_BASE)
Seems like this should factor out rather than get duplicated.


> --- gcc/gimple-fold.c.mp	2013-11-27 08:46:27.979629191 +0100
> +++ gcc/gimple-fold.c	2013-11-27 08:46:57.556753251 +0100
> @@ -2660,8 +2660,30 @@ gimple_fold_stmt_to_constant_1 (gimple s
>   	tree fn;
>
>   	if (gimple_call_internal_p (stmt))
> -	  /* No folding yet for these functions.  */
> -	  return NULL_TREE;
> +	  {
> +	    enum tree_code subcode = ERROR_MARK;
> +	    switch (gimple_call_internal_fn (stmt))
> +	      {
> +	      case IFN_UBSAN_CHECK_ADD: subcode = PLUS_EXPR; break;
> +	      case IFN_UBSAN_CHECK_SUB: subcode = MINUS_EXPR; break;
> +	      case IFN_UBSAN_CHECK_MUL: subcode = MULT_EXPR; break;
Minor detail, put the case value and associated codes on separate lines.

   case FU:
     code;
     more code
     break;
   case BAR
     blah;
     break;

> --- gcc/internal-fn.c.mp	2013-11-27 08:46:28.014629338 +0100
> +++ gcc/internal-fn.c	2013-11-27 08:46:57.559753263 +0100
> @@ -31,6 +31,8 @@ along with GCC; see the file COPYING3.
>   #include "gimple-expr.h"
>   #include "is-a.h"
>   #include "gimple.h"
> +#include "ubsan.h"
> +#include "target.h"
>
>   /* The names of each internal function, indexed by function number.  */
>   const char *const internal_fn_name_array[] = {
> @@ -153,6 +155,306 @@ expand_UBSAN_NULL (gimple stmt ATTRIBUTE
>     gcc_unreachable ();
>   }
>
> +/* Add sub/add overflow checking to the statement STMT.
> +   CODE says whether the operation is +, or -.  */
> +
> +void
> +ubsan_expand_si_overflow_addsub_check (tree_code code, gimple stmt)
Does this need to use Jakub's recent changes for pr58864 (pending stack 
adjustment stuff).  The code seems to have the same kind of structure 
Jakub was cleaning up already.


> +
> +/* Add negate overflow checking to the statement STMT.  */
> +
> +void
> +ubsan_expand_si_overflow_neg_check (gimple stmt)
Similarly.



> +/* Add mul overflow checking to the statement STMT.  */
> +
> +void
> +ubsan_expand_si_overflow_mul_check (gimple stmt)
Similarly.


> --- gcc/fold-const.c.mp	2013-11-27 08:46:27.941629031 +0100
> +++ gcc/fold-const.c	2013-11-27 08:46:57.548753215 +0100
> @@ -10335,14 +10335,16 @@ fold_binary_loc (location_t loc,
>
>       case PLUS_EXPR:
>         /* A + (-B) -> A - B */
> -      if (TREE_CODE (arg1) == NEGATE_EXPR)
> +      if (TREE_CODE (arg1) == NEGATE_EXPR
> +	  && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
>   	return fold_build2_loc (loc, MINUS_EXPR, type,
>   			    fold_convert_loc (loc, type, arg0),
>   			    fold_convert_loc (loc, type,
>   					      TREE_OPERAND (arg1, 0)));
>         /* (-A) + B -> B - A */
>         if (TREE_CODE (arg0) == NEGATE_EXPR
> -	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
> +	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1)
> +	  && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
>   	return fold_build2_loc (loc, MINUS_EXPR, type,
>   			    fold_convert_loc (loc, type, arg1),
>   			    fold_convert_loc (loc, type,
Presumably because you want to see the original arithmetic to instrument 
it?

> --- gcc/tree-vrp.c.mp	2013-11-27 08:46:28.043629459 +0100
> +++ gcc/tree-vrp.c	2013-11-27 08:46:57.570753307 +0100
> @@ -3757,6 +3757,40 @@ extract_range_basic (value_range_t *vr,
>   	  break;
>   	}
>       }
> +  else if (is_gimple_call (stmt)
> +	   && gimple_call_internal_p (stmt))
> +    {
> +      enum tree_code subcode = ERROR_MARK;
> +      switch (gimple_call_internal_fn (stmt))
> +	{
> +	case IFN_UBSAN_CHECK_ADD: subcode = PLUS_EXPR; break;
> +	case IFN_UBSAN_CHECK_SUB: subcode = MINUS_EXPR; break;
> +	case IFN_UBSAN_CHECK_MUL: subcode = MULT_EXPR; break;
> +	default: break;
Formatting again.


Overall the stuff outside the i386 directory looks pretty good, though 
it needs some minor updates.  I'd suggest extracting the i386 bits and 
pinging them as a separate patch in the hope that we'll get Uros's 
attention.

Jeff
Jakub Jelinek Dec. 3, 2013, 10:05 p.m. UTC | #2
On Tue, Dec 03, 2013 at 02:14:17PM -0700, Jeff Law wrote:
> >--- gcc/ubsan.h.mp	2013-11-27 08:46:28.046629473 +0100
> >+++ gcc/ubsan.h	2013-11-27 08:46:57.578753342 +0100
> >@@ -21,6 +21,12 @@ along with GCC; see the file COPYING3.
> >  #ifndef GCC_UBSAN_H
> >  #define GCC_UBSAN_H
> >
> >+/* From predict.c.  */
> >+#define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
> >+#define PROB_EVEN		(REG_BR_PROB_BASE / 2)
> >+#define PROB_VERY_LIKELY	(REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
> >+#define PROB_ALWAYS		(REG_BR_PROB_BASE)
> Seems like this should factor out rather than get duplicated.

Yeah, the question is where, predict.h?

> >+/* Add sub/add overflow checking to the statement STMT.
> >+   CODE says whether the operation is +, or -.  */
> >+
> >+void
> >+ubsan_expand_si_overflow_addsub_check (tree_code code, gimple stmt)
> Does this need to use Jakub's recent changes for pr58864 (pending
> stack adjustment stuff).  The code seems to have the same kind of
> structure Jakub was cleaning up already.

No, the code always emits conditional jumps and one of the branches
will do a call, so we always want no pending stack adjustment
before the conditional jump and again no pending stack adjustment
after the library call, so that we don't make the stack pointer
inconsistent.

> >--- gcc/fold-const.c.mp	2013-11-27 08:46:27.941629031 +0100
> >+++ gcc/fold-const.c	2013-11-27 08:46:57.548753215 +0100
> >@@ -10335,14 +10335,16 @@ fold_binary_loc (location_t loc,
> >
> >      case PLUS_EXPR:
> >        /* A + (-B) -> A - B */
> >-      if (TREE_CODE (arg1) == NEGATE_EXPR)
> >+      if (TREE_CODE (arg1) == NEGATE_EXPR
> >+	  && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
> >  	return fold_build2_loc (loc, MINUS_EXPR, type,
> >  			    fold_convert_loc (loc, type, arg0),
> >  			    fold_convert_loc (loc, type,
> >  					      TREE_OPERAND (arg1, 0)));
> >        /* (-A) + B -> B - A */
> >        if (TREE_CODE (arg0) == NEGATE_EXPR
> >-	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
> >+	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1)
> >+	  && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
> >  	return fold_build2_loc (loc, MINUS_EXPR, type,
> >  			    fold_convert_loc (loc, type, arg1),
> >  			    fold_convert_loc (loc, type,
> Presumably because you want to see the original arithmetic to
> instrument it?

Yes.  Dunno if Marek has added testcase for it, but if we have say:
  int a = -10, b = INT_MIN;
then
  int c = a - b;
isn't supposed to overflow, while
  int d = a + (-b);
is.  The signed integer overflow is in the latter case already
on the negation.  Without -fsanitize=undefined we just assume
that it is undefined behavior and therefore ignore that case,
but with -fsanitize=undefined we actually want to diagnose it at runtime to
the user.

	Jakub
Jeff Law Dec. 4, 2013, 4:33 a.m. UTC | #3
On 12/03/13 15:05, Jakub Jelinek wrote:
> On Tue, Dec 03, 2013 at 02:14:17PM -0700, Jeff Law wrote:
>>> --- gcc/ubsan.h.mp	2013-11-27 08:46:28.046629473 +0100
>>> +++ gcc/ubsan.h	2013-11-27 08:46:57.578753342 +0100
>>> @@ -21,6 +21,12 @@ along with GCC; see the file COPYING3.
>>>   #ifndef GCC_UBSAN_H
>>>   #define GCC_UBSAN_H
>>>
>>> +/* From predict.c.  */
>>> +#define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
>>> +#define PROB_EVEN		(REG_BR_PROB_BASE / 2)
>>> +#define PROB_VERY_LIKELY	(REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
>>> +#define PROB_ALWAYS		(REG_BR_PROB_BASE)
>> Seems like this should factor out rather than get duplicated.
>
> Yeah, the question is where, predict.h?
I'd think that'd be a fine place for them ;-)


>
>>> +/* Add sub/add overflow checking to the statement STMT.
>>> +   CODE says whether the operation is +, or -.  */
>>> +
>>> +void
>>> +ubsan_expand_si_overflow_addsub_check (tree_code code, gimple stmt)
>> Does this need to use Jakub's recent changes for pr58864 (pending
>> stack adjustment stuff).  The code seems to have the same kind of
>> structure Jakub was cleaning up already.
>
> No, the code always emits conditional jumps and one of the branches
> will do a call, so we always want no pending stack adjustment
> before the conditional jump and again no pending stack adjustment
> after the library call, so that we don't make the stack pointer
> inconsistent.
OK.  Just making sure.

>
>>> --- gcc/fold-const.c.mp	2013-11-27 08:46:27.941629031 +0100
>>> +++ gcc/fold-const.c	2013-11-27 08:46:57.548753215 +0100
>>> @@ -10335,14 +10335,16 @@ fold_binary_loc (location_t loc,
>>>
>>>       case PLUS_EXPR:
>>>         /* A + (-B) -> A - B */
>>> -      if (TREE_CODE (arg1) == NEGATE_EXPR)
>>> +      if (TREE_CODE (arg1) == NEGATE_EXPR
>>> +	  && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
>>>   	return fold_build2_loc (loc, MINUS_EXPR, type,
>>>   			    fold_convert_loc (loc, type, arg0),
>>>   			    fold_convert_loc (loc, type,
>>>   					      TREE_OPERAND (arg1, 0)));
>>>         /* (-A) + B -> B - A */
>>>         if (TREE_CODE (arg0) == NEGATE_EXPR
>>> -	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
>>> +	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1)
>>> +	  && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
>>>   	return fold_build2_loc (loc, MINUS_EXPR, type,
>>>   			    fold_convert_loc (loc, type, arg1),
>>>   			    fold_convert_loc (loc, type,
>> Presumably because you want to see the original arithmetic to
>> instrument it?
>
> Yes.  Dunno if Marek has added testcase for it, but if we have say:
>    int a = -10, b = INT_MIN;
> then
>    int c = a - b;
> isn't supposed to overflow, while
>    int d = a + (-b);
> is.  The signed integer overflow is in the latter case already
> on the negation.  Without -fsanitize=undefined we just assume
> that it is undefined behavior and therefore ignore that case,
> but with -fsanitize=undefined we actually want to diagnose it at runtime to
> the user.
OK, that's basically what I figured.

So just a couple trivial issues for Marek to run down.  Final review of 
the stuff outside the x86 port ought to be trivial.

jeff
Marek Polacek Dec. 4, 2013, 2:15 p.m. UTC | #4
On Tue, Dec 03, 2013 at 02:14:17PM -0700, Jeff Law wrote:
> Perhaps split this patch into two parts which can be reviewed
> independently, but go into the tree at the same time.  The obvious
> hope would be that Uros or one of the other x86 backend folks could
> chime in on that part.

I posted the i?86 bits separately.

> >--- gcc/ubsan.h.mp	2013-11-27 08:46:28.046629473 +0100
> >+++ gcc/ubsan.h	2013-11-27 08:46:57.578753342 +0100
> >@@ -21,6 +21,12 @@ along with GCC; see the file COPYING3.
> >  #ifndef GCC_UBSAN_H
> >  #define GCC_UBSAN_H
> >
> >+/* From predict.c.  */
> >+#define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
> >+#define PROB_EVEN		(REG_BR_PROB_BASE / 2)
> >+#define PROB_VERY_LIKELY	(REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
> >+#define PROB_ALWAYS		(REG_BR_PROB_BASE)
> Seems like this should factor out rather than get duplicated.

I moved all the into predict.h, the users now include predict.h.

> >--- gcc/gimple-fold.c.mp	2013-11-27 08:46:27.979629191 +0100
> >+++ gcc/gimple-fold.c	2013-11-27 08:46:57.556753251 +0100
> >@@ -2660,8 +2660,30 @@ gimple_fold_stmt_to_constant_1 (gimple s
> >  	tree fn;
> >
> >  	if (gimple_call_internal_p (stmt))
> >-	  /* No folding yet for these functions.  */
> >-	  return NULL_TREE;
> >+	  {
> >+	    enum tree_code subcode = ERROR_MARK;
> >+	    switch (gimple_call_internal_fn (stmt))
> >+	      {
> >+	      case IFN_UBSAN_CHECK_ADD: subcode = PLUS_EXPR; break;
> >+	      case IFN_UBSAN_CHECK_SUB: subcode = MINUS_EXPR; break;
> >+	      case IFN_UBSAN_CHECK_MUL: subcode = MULT_EXPR; break;
> Minor detail, put the case value and associated codes on separate lines.
> 
>   case FU:
>     code;
>     more code
>     break;
>   case BAR
>     blah;
>     break;

Done.
 
> >--- gcc/tree-vrp.c.mp	2013-11-27 08:46:28.043629459 +0100
> >+++ gcc/tree-vrp.c	2013-11-27 08:46:57.570753307 +0100
> >@@ -3757,6 +3757,40 @@ extract_range_basic (value_range_t *vr,
> >  	  break;
> >  	}
> >      }
> >+  else if (is_gimple_call (stmt)
> >+	   && gimple_call_internal_p (stmt))
> >+    {
> >+      enum tree_code subcode = ERROR_MARK;
> >+      switch (gimple_call_internal_fn (stmt))
> >+	{
> >+	case IFN_UBSAN_CHECK_ADD: subcode = PLUS_EXPR; break;
> >+	case IFN_UBSAN_CHECK_SUB: subcode = MINUS_EXPR; break;
> >+	case IFN_UBSAN_CHECK_MUL: subcode = MULT_EXPR; break;
> >+	default: break;
> Formatting again.
 
Done.
 
> Overall the stuff outside the i386 directory looks pretty good,
> though it needs some minor updates.  I'd suggest extracting the i386
> bits and pinging them as a separate patch in the hope that we'll get
> Uros's attention.

Done, I posted splitted version of the patch.  Thanks for the review.

	Marek
diff mbox

Patch

--- gcc/opts.c.mp	2013-11-27 08:46:28.032629413 +0100
+++ gcc/opts.c	2013-11-27 08:46:57.566753291 +0100
@@ -1460,6 +1460,8 @@  common_handle_option (struct gcc_options
 	      { "vla-bound", SANITIZE_VLA, sizeof "vla-bound" - 1 },
 	      { "return", SANITIZE_RETURN, sizeof "return" - 1 },
 	      { "null", SANITIZE_NULL, sizeof "null" - 1 },
+	      { "signed-integer-overflow", SANITIZE_SI_OVERFLOW,
+		sizeof "signed-integer-overflow" -1 },
 	      { NULL, 0, 0 }
 	    };
 	    const char *comma;
--- gcc/config/i386/i386.md.mp	2013-11-27 08:46:27.890628818 +0100
+++ gcc/config/i386/i386.md	2013-11-27 08:46:57.491752976 +0100
@@ -6198,6 +6198,42 @@ 
   [(set_attr "type" "alu")
    (set_attr "mode" "QI")])
 
+(define_mode_attr widerintmode [(QI "HI") (HI "SI") (SI "DI") (DI "TI")])
+
+;; Add with jump on overflow.
+(define_expand "addv<mode>4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+		   (eq:CCO (plus:<widerintmode>
+			      (sign_extend:<widerintmode>
+				 (match_operand:SWI 1 "register_operand"))
+			      (sign_extend:<widerintmode>
+				 (match_operand:SWI 2 "<general_operand>")))
+			   (sign_extend:<widerintmode>
+			      (plus:SWI (match_dup 1) (match_dup 2)))))
+	      (set (match_operand:SWI 0 "register_operand")
+		   (plus:SWI (match_dup 1) (match_dup 2)))])
+   (set (pc) (if_then_else
+	       (eq (reg:CCO FLAGS_REG) (const_int 0))
+	       (label_ref (match_operand 3))
+	       (pc)))]
+  "")
+
+(define_insn "*addv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+	(eq:CCO (plus:<widerintmode>
+		   (sign_extend:<widerintmode>
+		      (match_operand:SWI 1 "nonimmediate_operand" "%0,0"))
+		   (sign_extend:<widerintmode>
+		      (match_operand:SWI 2 "<general_operand>" "<g>,<r><i>")))
+		(sign_extend:<widerintmode>
+		   (plus:SWI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>,<r>m")
+	(plus:SWI (match_dup 1) (match_dup 2)))]
+  "ix86_binary_operator_ok (PLUS, <MODE>mode, operands)"
+  "add{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
+
 ;; The lea patterns for modes less than 32 bits need to be matched by
 ;; several insns converted to real lea by splitters.
 
@@ -6435,6 +6471,40 @@ 
   [(set_attr "type" "alu")
    (set_attr "mode" "SI")])
 
+;; Subtract with jump on overflow.
+(define_expand "subv<mode>4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+		   (eq:CCO (minus:<widerintmode>
+			      (sign_extend:<widerintmode>
+				 (match_operand:SWI 1 "register_operand"))
+			      (sign_extend:<widerintmode>
+				 (match_operand:SWI 2 "<general_operand>")))
+			   (sign_extend:<widerintmode>
+			      (minus:SWI (match_dup 1) (match_dup 2)))))
+	      (set (match_operand:SWI 0 "register_operand")
+		   (minus:SWI (match_dup 1) (match_dup 2)))])
+   (set (pc) (if_then_else
+	       (eq (reg:CCO FLAGS_REG) (const_int 0))
+	       (label_ref (match_operand 3))
+	       (pc)))]
+  "")
+
+(define_insn "*subv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+	(eq:CCO (minus:<widerintmode>
+		   (sign_extend:<widerintmode>
+		      (match_operand:SWI 1 "nonimmediate_operand" "0,0"))
+		   (sign_extend:<widerintmode>
+		      (match_operand:SWI 2 "<general_operand>" "<r><i>,<r>m")))
+		(sign_extend:<widerintmode>
+		   (minus:SWI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m,<r>")
+	(minus:SWI (match_dup 1) (match_dup 2)))]
+  "ix86_binary_operator_ok (MINUS, <MODE>mode, operands)"
+  "sub{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*sub<mode>_3"
   [(set (reg FLAGS_REG)
 	(compare (match_operand:SWI 1 "nonimmediate_operand" "0,0")
@@ -6749,6 +6819,59 @@ 
    (set_attr "bdver1_decode" "direct")
    (set_attr "mode" "QI")])
 
+;; Multiply with jump on overflow.
+(define_expand "mulv<mode>4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+		   (eq:CCO (mult:<widerintmode>
+			      (sign_extend:<widerintmode>
+				 (match_operand:SWI48 1 "register_operand"))
+			      (sign_extend:<widerintmode>
+				 (match_operand:SWI48 2 "<general_operand>")))
+			   (sign_extend:<widerintmode>
+			      (mult:SWI48 (match_dup 1) (match_dup 2)))))
+	      (set (match_operand:SWI48 0 "register_operand")
+		   (mult:SWI48 (match_dup 1) (match_dup 2)))])
+   (set (pc) (if_then_else
+	       (eq (reg:CCO FLAGS_REG) (const_int 0))
+	       (label_ref (match_operand 3))
+	       (pc)))]
+  "")
+
+(define_insn "*mulv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+	(eq:CCO (mult:<widerintmode>
+		   (sign_extend:<widerintmode>
+		      (match_operand:SWI 1 "nonimmediate_operand" "%rm,rm,0"))
+		   (sign_extend:<widerintmode>
+		      (match_operand:SWI 2 "<general_operand>" "K,<i>,mr")))
+		(sign_extend:<widerintmode>
+		   (mult:SWI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SWI 0 "register_operand" "=r,r,r")
+	(mult:SWI (match_dup 1) (match_dup 2)))]
+  "!(MEM_P (operands[1]) && MEM_P (operands[2]))"
+  "@
+   imul{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}
+   imul{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}
+   imul{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "imul")
+   (set_attr "prefix_0f" "0,0,1")
+   (set (attr "athlon_decode")
+	(cond [(eq_attr "cpu" "athlon")
+		  (const_string "vector")
+	       (eq_attr "alternative" "1")
+		  (const_string "vector")
+	       (and (eq_attr "alternative" "2")
+		    (match_operand 1 "memory_operand"))
+		  (const_string "vector")]
+	      (const_string "direct")))
+   (set (attr "amdfam10_decode")
+	(cond [(and (eq_attr "alternative" "0,1")
+		    (match_operand 1 "memory_operand"))
+		  (const_string "vector")]
+	      (const_string "direct")))
+   (set_attr "bdver1_decode" "direct")
+   (set_attr "mode" "<MODE>")])
+
 (define_expand "<u>mul<mode><dwi>3"
   [(parallel [(set (match_operand:<DWI> 0 "register_operand")
 		   (mult:<DWI>
@@ -8662,6 +8785,49 @@ 
   [(set_attr "type" "negnot")
    (set_attr "mode" "SI")])
 
+;; Negate with jump on overflow.
+(define_expand "negv<mode>3"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+		   (ne:CCO (match_operand:SWI 1 "register_operand")
+			   (const_int 0)))
+	      (set (match_operand:SWI 0 "register_operand")
+		   (neg:SWI (match_dup 1)))])
+   (set (pc) (if_then_else
+	       (eq (reg:CCO FLAGS_REG) (const_int 0))
+	       (label_ref (match_operand 2))
+	       (pc)))]
+  ""
+{
+  rtx minv = GEN_INT (HOST_WIDE_INT_M1U
+		      << (GET_MODE_BITSIZE (<MODE>mode) - 1));
+  emit_insn (gen_negv<mode>3_1 (operands[0], operands[1], minv, operands[2]));
+  DONE;
+})
+
+(define_expand "negv<mode>3_1"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+		   (ne:CCO (match_operand:SWI 1 "nonimmediate_operand")
+			   (match_operand:SWI 2 "const_int_operand")))
+	      (set (match_operand:SWI 0 "nonimmediate_operand")
+		   (neg:SWI (match_dup 1)))])
+   (set (pc) (if_then_else
+	       (eq (reg:CCO FLAGS_REG) (const_int 0))
+	       (label_ref (match_operand 3))
+	       (pc)))]
+  "")
+
+(define_insn "*negv<mode>3"
+  [(set (reg:CCO FLAGS_REG)
+	(ne:CCO (match_operand:SWI 1 "nonimmediate_operand" "0")
+		(match_operand:SWI 2 "const_int_operand")))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
+	(neg:SWI (match_dup 1)))]
+  "ix86_unary_operator_ok (NEG, <MODE>mode, operands)
+   && mode_signbit_p (<MODE>mode, operands[2])"
+  "neg{<imodesuffix>}\t%0"
+  [(set_attr "type" "negnot")
+   (set_attr "mode" "<MODE>")])
+
 ;; Changing of sign for FP values is doable using integer unit too.
 
 (define_expand "<code><mode>2"
--- gcc/c-family/c-gimplify.c.mp	2013-11-27 08:46:27.866628717 +0100
+++ gcc/c-family/c-gimplify.c	2013-11-27 08:46:57.455752825 +0100
@@ -199,7 +199,9 @@  c_gimplify_expr (tree *expr_p, gimple_se
 	tree type = TREE_TYPE (TREE_OPERAND (*expr_p, 0));
 	if (INTEGRAL_TYPE_P (type) && c_promoting_integer_type_p (type))
 	  {
-	    if (TYPE_OVERFLOW_UNDEFINED (type))
+	    if (TYPE_OVERFLOW_UNDEFINED (type)
+		|| ((flag_sanitize & SANITIZE_SI_OVERFLOW)
+		    && !TYPE_OVERFLOW_WRAPS (type)))
 	      type = unsigned_type_for (type);
 	    return gimplify_self_mod_expr (expr_p, pre_p, post_p, 1, type);
 	  }
--- gcc/sanitizer.def.mp	2013-11-27 08:46:28.034629422 +0100
+++ gcc/sanitizer.def	2013-11-27 08:46:57.568753299 +0100
@@ -315,3 +315,19 @@  DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HAN
 		      "__ubsan_handle_type_mismatch",
 		      BT_FN_VOID_PTR_PTR,
 		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW,
+		      "__ubsan_handle_add_overflow",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW,
+		      "__ubsan_handle_sub_overflow",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW,
+		      "__ubsan_handle_mul_overflow",
+		      BT_FN_VOID_PTR_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW,
+		      "__ubsan_handle_negate_overflow",
+		      BT_FN_VOID_PTR_PTR,
+		      ATTR_COLD_NOTHROW_LEAF_LIST)
--- gcc/ubsan.h.mp	2013-11-27 08:46:28.046629473 +0100
+++ gcc/ubsan.h	2013-11-27 08:46:57.578753342 +0100
@@ -21,6 +21,12 @@  along with GCC; see the file COPYING3.
 #ifndef GCC_UBSAN_H
 #define GCC_UBSAN_H
 
+/* From predict.c.  */
+#define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
+#define PROB_EVEN		(REG_BR_PROB_BASE / 2)
+#define PROB_VERY_LIKELY	(REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
+#define PROB_ALWAYS		(REG_BR_PROB_BASE)
+
 /* The various kinds of NULL pointer checks.  */
 enum ubsan_null_ckind {
   UBSAN_LOAD_OF,
@@ -43,6 +49,7 @@  extern tree ubsan_create_data (const cha
 extern tree ubsan_type_descriptor (tree, bool);
 extern tree ubsan_encode_value (tree);
 extern bool is_ubsan_builtin_p (tree);
+extern tree ubsan_build_overflow_builtin (tree_code, location_t, tree, tree, tree);
 
 #endif  /* GCC_UBSAN_H  */
 
--- gcc/gimple-fold.c.mp	2013-11-27 08:46:27.979629191 +0100
+++ gcc/gimple-fold.c	2013-11-27 08:46:57.556753251 +0100
@@ -2660,8 +2660,30 @@  gimple_fold_stmt_to_constant_1 (gimple s
 	tree fn;
 
 	if (gimple_call_internal_p (stmt))
-	  /* No folding yet for these functions.  */
-	  return NULL_TREE;
+	  {
+	    enum tree_code subcode = ERROR_MARK;
+	    switch (gimple_call_internal_fn (stmt))
+	      {
+	      case IFN_UBSAN_CHECK_ADD: subcode = PLUS_EXPR; break;
+	      case IFN_UBSAN_CHECK_SUB: subcode = MINUS_EXPR; break;
+	      case IFN_UBSAN_CHECK_MUL: subcode = MULT_EXPR; break;
+	      default: return NULL_TREE;
+	      }
+	    tree op0 = (*valueize) (gimple_call_arg (stmt, 0));
+	    tree op1 = (*valueize) (gimple_call_arg (stmt, 1));
+
+	    if (TREE_CODE (op0) != INTEGER_CST
+		|| TREE_CODE (op1) != INTEGER_CST)
+	      return NULL_TREE;
+	    tree res = fold_binary_loc (loc, subcode,
+					TREE_TYPE (gimple_call_arg (stmt, 0)),
+					op0, op1);
+	    if (res
+		&& TREE_CODE (res) == INTEGER_CST
+		&& !TREE_OVERFLOW (res))
+	      return res;
+	    return NULL_TREE;
+	  }
 
 	fn = (*valueize) (gimple_call_fn (stmt));
 	if (TREE_CODE (fn) == ADDR_EXPR
--- gcc/ubsan.c.mp	2013-11-27 08:46:28.045629469 +0100
+++ gcc/ubsan.c	2013-11-27 08:46:57.578753342 +0100
@@ -41,9 +41,6 @@  along with GCC; see the file COPYING3.
 #include "ubsan.h"
 #include "c-family/c-common.h"
 
-/* From trans-mem.c.  */
-#define PROB_VERY_UNLIKELY      (REG_BR_PROB_BASE / 2000 - 1)
-
 /* Map from a tree to a VAR_DECL tree.  */
 
 struct GTY(()) tree_type_map {
@@ -631,6 +631,98 @@  instrument_null (tree *tp, int * /*walk_
   return NULL_TREE;
 }
 
+/* Build an ubsan builtin call for the signed-integer-overflow
+   sanitization.  CODE says what kind of builtin are we building,
+   LOC is a location, LHSTYPE is the type of LHS, OP0 and OP1
+   are operands of the binary operation.  */
+
+tree
+ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype,
+			      tree op0, tree op1)
+{
+  tree data = ubsan_create_data ("__ubsan_overflow_data", loc, NULL,
+				 ubsan_type_descriptor (lhstype, false),
+				 NULL_TREE);
+  enum built_in_function fn_code;
+
+  switch (code)
+    {
+    case PLUS_EXPR:
+      fn_code = BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW;
+      break;
+    case MINUS_EXPR:
+      fn_code = BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW;
+      break;
+    case MULT_EXPR:
+      fn_code = BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW;
+      break;
+    case NEGATE_EXPR:
+      fn_code = BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  tree fn = builtin_decl_explicit (fn_code);
+  return build_call_expr_loc (loc, fn, 2 + (code != NEGATE_EXPR),
+			      build_fold_addr_expr_loc (loc, data),
+			      ubsan_encode_value (op0),
+			      op1 ? ubsan_encode_value (op1) : NULL_TREE);
+}
+
+/* Perform the signed integer instrumentation.  GSI is the iterator
+   pointing at statement we are trying to instrument.  */
+
+static void
+instrument_si_overflow (gimple_stmt_iterator gsi)
+{
+  gimple stmt = gsi_stmt (gsi);
+  tree_code code = gimple_assign_rhs_code (stmt);
+  tree lhs = gimple_assign_lhs (stmt);
+  tree lhstype = TREE_TYPE (lhs);
+  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))
+    return;
+
+  switch (code)
+    {
+    case MINUS_EXPR:
+    case PLUS_EXPR:
+    case MULT_EXPR:
+      /* Transform
+	 i = u {+,-,*} 5;
+	 into
+	 i = UBSAN_CHECK_{ADD,SUB,MUL} (u, 5);  */
+      a = gimple_assign_rhs1 (stmt);
+      b = gimple_assign_rhs2 (stmt);
+      g = gimple_build_call_internal (code == PLUS_EXPR
+				      ? IFN_UBSAN_CHECK_ADD
+				      : code == MINUS_EXPR
+				      ? IFN_UBSAN_CHECK_SUB
+				      : IFN_UBSAN_CHECK_MUL, 2, a, b);
+      gimple_call_set_lhs (g, lhs);
+      gsi_replace (&gsi, g, false);
+      break;
+    case NEGATE_EXPR:
+      /* Represent i = -u;
+	 as
+	 i = UBSAN_CHECK_SUB (0, u);  */
+      a = build_int_cst (lhstype, 0);
+      b = gimple_assign_rhs1 (stmt);
+      g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b);
+      gimple_call_set_lhs (g, lhs);
+      gsi_replace (&gsi, g, false);
+      break;
+    default:
+      break;
+    }
+}
+
 /* Gate and execute functions for ubsan pass.  */
 
 static unsigned int
@@ -643,7 +735,6 @@  ubsan_pass (void)
     {
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
 	{
-	  struct walk_stmt_info wi;
 	  gimple stmt = gsi_stmt (gsi);
 	  if (is_gimple_debug (stmt) || gimple_clobber_p (stmt))
 	    {
@@ -651,9 +742,18 @@  ubsan_pass (void)
 	      continue;
 	    }
 
-	  memset (&wi, 0, sizeof (wi));
-	  wi.gsi = gsi;
-	  walk_gimple_op (stmt, instrument_null, &wi);
+	  if (flag_sanitize & SANITIZE_SI_OVERFLOW
+	      && is_gimple_assign (stmt))
+	    instrument_si_overflow (gsi);
+
+	  if (flag_sanitize & SANITIZE_NULL)
+	    {
+	      struct walk_stmt_info wi;
+	      memset (&wi, 0, sizeof (wi));
+	      wi.gsi = gsi;
+	      walk_gimple_op (stmt, instrument_null, &wi);
+	    }
+
 	  gsi_next (&gsi);
 	}
     }
@@ -663,7 +763,7 @@  ubsan_pass (void)
 static bool
 gate_ubsan (void)
 {
-  return flag_sanitize & SANITIZE_NULL;
+  return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW);
 }
 
 namespace {
--- gcc/flag-types.h.mp	2013-11-27 08:46:27.892628826 +0100
+++ gcc/flag-types.h	2013-11-27 08:46:57.504753032 +0100
@@ -215,8 +215,10 @@  enum sanitize_code {
   SANITIZE_VLA = 1 << 6,
   SANITIZE_NULL = 1 << 7,
   SANITIZE_RETURN = 1 << 8,
+  SANITIZE_SI_OVERFLOW = 1 << 9,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
 		       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
+		       | SANITIZE_SI_OVERFLOW
 };
 
 /* flag_vtable_verify initialization levels. */
--- gcc/internal-fn.c.mp	2013-11-27 08:46:28.014629338 +0100
+++ gcc/internal-fn.c	2013-11-27 08:46:57.559753263 +0100
@@ -31,6 +31,8 @@  along with GCC; see the file COPYING3.
 #include "gimple-expr.h"
 #include "is-a.h"
 #include "gimple.h"
+#include "ubsan.h"
+#include "target.h"
 
 /* The names of each internal function, indexed by function number.  */
 const char *const internal_fn_name_array[] = {
@@ -153,6 +155,306 @@  expand_UBSAN_NULL (gimple stmt ATTRIBUTE
   gcc_unreachable ();
 }
 
+/* Add sub/add overflow checking to the statement STMT.
+   CODE says whether the operation is +, or -.  */
+
+void
+ubsan_expand_si_overflow_addsub_check (tree_code code, gimple stmt)
+{
+  rtx res, op0, op1;
+  tree lhs, fn, arg0, arg1;
+  rtx done_label, do_error, target = NULL_RTX;
+
+  lhs = gimple_call_lhs (stmt);
+  arg0 = gimple_call_arg (stmt, 0);
+  arg1 = gimple_call_arg (stmt, 1);
+  done_label = gen_label_rtx ();
+  do_error = gen_label_rtx ();
+  fn = ubsan_build_overflow_builtin (code, gimple_location (stmt),
+				     TREE_TYPE (arg0), arg0, arg1);
+  do_pending_stack_adjust ();
+  op0 = expand_normal (arg0);
+  op1 = expand_normal (arg1);
+
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
+  if (lhs)
+    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+
+  enum insn_code icode
+    = optab_handler (code == PLUS_EXPR ? addv4_optab : subv4_optab, mode);
+  if (icode != CODE_FOR_nothing)
+    {
+      struct expand_operand ops[4];
+      rtx last = get_last_insn ();
+
+      res = gen_reg_rtx (mode);
+      create_output_operand (&ops[0], res, mode);
+      create_input_operand (&ops[1], op0, mode);
+      create_input_operand (&ops[2], op1, mode);
+      create_fixed_operand (&ops[3], do_error);
+      if (maybe_expand_insn (icode, 4, ops))
+	{
+	  last = get_last_insn ();
+	  if (profile_status != PROFILE_ABSENT
+	      && JUMP_P (last)
+	      && any_condjump_p (last)
+	      && !find_reg_note (last, REG_BR_PROB, 0))
+	    add_int_reg_note (last, REG_BR_PROB, PROB_VERY_UNLIKELY);
+	  emit_jump (done_label);
+        }
+      else
+	{
+	  delete_insns_since (last);
+	  icode = CODE_FOR_nothing;
+	}
+    }
+
+  if (icode == CODE_FOR_nothing)
+    {
+      rtx sub_check = gen_label_rtx ();
+
+      /* Compute the operation.  On RTL level, the addition is always
+	 unsigned.  */
+      res = expand_binop (mode, add_optab, op0, op1,
+			  NULL_RTX, false, OPTAB_LIB_WIDEN);
+
+      /* If the op1 is negative, we have to use a different check.  */
+      emit_cmp_and_jump_insns (op1, const0_rtx, LT, NULL_RTX, mode,
+			       false, sub_check, PROB_EVEN);
+
+      /* Compare the result of the addition with one of the operands.  */
+      emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? GE : LE,
+			       NULL_RTX, mode, false, done_label,
+			       PROB_VERY_LIKELY);
+      /* If we get here, we have to print the error.  */
+      emit_jump (do_error);
+
+      emit_label (sub_check);
+      /* We have k = a + b for b < 0 here.  k <= a must hold.  */
+      emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? LE : GE,
+			       NULL_RTX, mode, false, done_label,
+			       PROB_VERY_LIKELY);
+    }
+
+   emit_label (do_error);
+   /* Expand the ubsan builtin call.  */
+   expand_normal (fn);
+   do_pending_stack_adjust ();
+
+   /* We're done.  */
+   emit_label (done_label);
+
+  if (lhs)
+    emit_move_insn (target, res);
+}
+
+/* Add negate overflow checking to the statement STMT.  */
+
+void
+ubsan_expand_si_overflow_neg_check (gimple stmt)
+{
+  rtx res, op1;
+  tree lhs, fn, arg1;
+  rtx done_label, do_error, target = NULL_RTX;
+
+  lhs = gimple_call_lhs (stmt);
+  arg1 = gimple_call_arg (stmt, 1);
+  done_label = gen_label_rtx ();
+  do_error = gen_label_rtx ();
+  fn = ubsan_build_overflow_builtin (NEGATE_EXPR, gimple_location (stmt),
+				     TREE_TYPE (arg1), arg1, NULL_TREE);
+
+  do_pending_stack_adjust ();
+  op1 = expand_normal (arg1);
+
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg1));
+  if (lhs)
+    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+
+  enum insn_code icode = optab_handler (negv3_optab, mode);
+  if (icode != CODE_FOR_nothing)
+    {
+      struct expand_operand ops[3];
+      rtx last = get_last_insn ();
+
+      res = gen_reg_rtx (mode);
+      create_output_operand (&ops[0], res, mode);
+      create_input_operand (&ops[1], op1, mode);
+      create_fixed_operand (&ops[2], do_error);
+      if (maybe_expand_insn (icode, 3, ops))
+	{
+	  last = get_last_insn ();
+	  if (profile_status != PROFILE_ABSENT
+	      && JUMP_P (last)
+	      && any_condjump_p (last)
+	      && !find_reg_note (last, REG_BR_PROB, 0))
+	    add_int_reg_note (last, REG_BR_PROB, PROB_VERY_UNLIKELY);
+	  emit_jump (done_label);
+	  res = target;
+        }
+      else
+	{
+	  delete_insns_since (last);
+	  icode = CODE_FOR_nothing;
+	}
+    }
+
+  if (icode == CODE_FOR_nothing)
+    {
+      /* Compute the operation.  On RTL level, the addition is always
+	 unsigned.  */
+      res = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
+
+      /* Compare the operand with the most negative value.  */
+      rtx minv = expand_normal (TYPE_MIN_VALUE (TREE_TYPE (arg1)));
+      emit_cmp_and_jump_insns (op1, minv, NE, NULL_RTX, mode, false,
+			       done_label, PROB_VERY_LIKELY);
+    }
+
+  emit_label (do_error);
+  /* Expand the ubsan builtin call.  */
+  expand_normal (fn);
+  do_pending_stack_adjust ();
+
+  /* We're done.  */
+  emit_label (done_label);
+
+  if (lhs)
+    emit_move_insn (target, res);
+}
+
+/* Add mul overflow checking to the statement STMT.  */
+
+void
+ubsan_expand_si_overflow_mul_check (gimple stmt)
+{
+  rtx res, op0, op1;
+  tree lhs, fn, arg0, arg1;
+  rtx done_label, do_error, target = NULL_RTX;
+
+  lhs = gimple_call_lhs (stmt);
+  arg0 = gimple_call_arg (stmt, 0);
+  arg1 = gimple_call_arg (stmt, 1);
+  done_label = gen_label_rtx ();
+  do_error = gen_label_rtx ();
+  fn = ubsan_build_overflow_builtin (MULT_EXPR, gimple_location (stmt),
+				     TREE_TYPE (arg0), arg0, arg1);
+
+  do_pending_stack_adjust ();
+  op0 = expand_normal (arg0);
+  op1 = expand_normal (arg1);
+
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
+  if (lhs)
+    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+
+  enum insn_code icode = optab_handler (mulv4_optab, mode);
+  if (icode != CODE_FOR_nothing)
+    {
+      struct expand_operand ops[4];
+      rtx last = get_last_insn ();
+
+      res = gen_reg_rtx (mode);
+      create_output_operand (&ops[0], res, mode);
+      create_input_operand (&ops[1], op0, mode);
+      create_input_operand (&ops[2], op1, mode);
+      create_fixed_operand (&ops[3], do_error);
+      if (maybe_expand_insn (icode, 4, ops))
+	{
+	  last = get_last_insn ();
+	  if (profile_status != PROFILE_ABSENT
+	      && JUMP_P (last)
+	      && any_condjump_p (last)
+	      && !find_reg_note (last, REG_BR_PROB, 0))
+	    add_int_reg_note (last, REG_BR_PROB, PROB_VERY_UNLIKELY);
+	  emit_jump (done_label);
+        }
+      else
+	{
+	  delete_insns_since (last);
+	  icode = CODE_FOR_nothing;
+	}
+    }
+
+  if (icode == CODE_FOR_nothing)
+    {
+      struct separate_ops ops;
+      ops.op0 = arg0;
+      ops.op1 = arg1;
+      ops.op2 = NULL_TREE;
+      ops.location = gimple_location (stmt);
+      if (GET_MODE_2XWIDER_MODE (mode) != VOIDmode
+	  && targetm.scalar_mode_supported_p (GET_MODE_2XWIDER_MODE (mode)))
+	{
+	  enum machine_mode wmode = GET_MODE_2XWIDER_MODE (mode);
+	  ops.code = WIDEN_MULT_EXPR;
+	  ops.type
+	    = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), 0);
+
+	  res = expand_expr_real_2 (&ops, NULL_RTX, wmode, EXPAND_NORMAL);
+	  rtx hipart = expand_shift (RSHIFT_EXPR, wmode, res,
+				     GET_MODE_PRECISION (mode), NULL_RTX, 0);
+	  hipart = gen_lowpart (mode, hipart);
+	  res = gen_lowpart (mode, res);
+	  rtx signbit = expand_shift (RSHIFT_EXPR, mode, res,
+				      GET_MODE_PRECISION (mode) - 1,
+				      NULL_RTX, 0);
+	  /* RES is low half of the double width result, HIPART
+	     the high half.  There was overflow if
+	     HIPART is different from RES < 0 ? -1 : 0.  */
+	  emit_cmp_and_jump_insns (signbit, hipart, EQ, NULL_RTX, mode,
+				   false, done_label, PROB_VERY_LIKELY);
+	}
+      else
+	{
+	  /* For now we don't instrument this.  See __mulvDI3 in libgcc2.c
+	     for what could be done.  */
+	  ops.code = MULT_EXPR;
+	  ops.type = TREE_TYPE (arg0);
+	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
+	  emit_jump (done_label);
+	}
+    }
+
+  emit_label (do_error);
+  /* Expand the ubsan builtin call.  */
+  expand_normal (fn);
+  do_pending_stack_adjust ();
+
+  /* We're done.  */
+  emit_label (done_label);
+
+  if (lhs)
+    emit_move_insn (target, res);
+}
+
+/* Expand UBSAN_CHECK_ADD call STMT.  */
+
+static void
+expand_UBSAN_CHECK_ADD (gimple stmt)
+{
+  ubsan_expand_si_overflow_addsub_check (PLUS_EXPR, stmt);
+}
+
+/* Expand UBSAN_CHECK_SUB call STMT.  */
+
+static void
+expand_UBSAN_CHECK_SUB (gimple stmt)
+{
+  if (integer_zerop (gimple_call_arg (stmt, 0)))
+    ubsan_expand_si_overflow_neg_check (stmt);
+  else
+    ubsan_expand_si_overflow_addsub_check (MINUS_EXPR, stmt);
+}
+
+/* Expand UBSAN_CHECK_MUL call STMT.  */
+
+static void
+expand_UBSAN_CHECK_MUL (gimple stmt)
+{
+  ubsan_expand_si_overflow_mul_check (stmt);
+}
+
 /* Routines to expand each internal function, indexed by function number.
    Each routine has the prototype:
 
--- gcc/fold-const.c.mp	2013-11-27 08:46:27.941629031 +0100
+++ gcc/fold-const.c	2013-11-27 08:46:57.548753215 +0100
@@ -10335,14 +10335,16 @@  fold_binary_loc (location_t loc,
 
     case PLUS_EXPR:
       /* A + (-B) -> A - B */
-      if (TREE_CODE (arg1) == NEGATE_EXPR)
+      if (TREE_CODE (arg1) == NEGATE_EXPR
+	  && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
 	return fold_build2_loc (loc, MINUS_EXPR, type,
 			    fold_convert_loc (loc, type, arg0),
 			    fold_convert_loc (loc, type,
 					      TREE_OPERAND (arg1, 0)));
       /* (-A) + B -> B - A */
       if (TREE_CODE (arg0) == NEGATE_EXPR
-	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
+	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1)
+	  && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
 	return fold_build2_loc (loc, MINUS_EXPR, type,
 			    fold_convert_loc (loc, type, arg1),
 			    fold_convert_loc (loc, type,
--- gcc/internal-fn.def.mp	2013-11-27 08:46:28.016629347 +0100
+++ gcc/internal-fn.def	2013-11-27 08:46:57.559753263 +0100
@@ -45,3 +45,6 @@  DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST
 DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
 DEF_INTERNAL_FN (ANNOTATE,  ECF_CONST | ECF_LEAF | ECF_NOTHROW)
 DEF_INTERNAL_FN (UBSAN_NULL, ECF_LEAF | ECF_NOTHROW)
+DEF_INTERNAL_FN (UBSAN_CHECK_ADD, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
+DEF_INTERNAL_FN (UBSAN_CHECK_SUB, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
+DEF_INTERNAL_FN (UBSAN_CHECK_MUL, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
--- gcc/tree-vrp.c.mp	2013-11-27 08:46:28.043629459 +0100
+++ gcc/tree-vrp.c	2013-11-27 08:46:57.570753307 +0100
@@ -3757,6 +3757,40 @@  extract_range_basic (value_range_t *vr,
 	  break;
 	}
     }
+  else if (is_gimple_call (stmt)
+	   && gimple_call_internal_p (stmt))
+    {
+      enum tree_code subcode = ERROR_MARK;
+      switch (gimple_call_internal_fn (stmt))
+	{
+	case IFN_UBSAN_CHECK_ADD: subcode = PLUS_EXPR; break;
+	case IFN_UBSAN_CHECK_SUB: subcode = MINUS_EXPR; break;
+	case IFN_UBSAN_CHECK_MUL: subcode = MULT_EXPR; break;
+	default: break;
+	}
+      if (subcode != ERROR_MARK)
+	{
+	  bool saved_flag_wrapv = flag_wrapv;
+	  /* Pretend the arithmetics is wrapping.  If there is
+	     any overflow, we'll complain, but will actually do
+	     wrapping operation.  */
+	  flag_wrapv = 1;
+	  extract_range_from_binary_expr (vr, subcode, type,
+					  gimple_call_arg (stmt, 0),
+					  gimple_call_arg (stmt, 1));
+	  flag_wrapv = saved_flag_wrapv;
+
+	  /* If for both arguments vrp_valueize returned non-NULL,
+	     this should have been already folded and if not, it
+	     wasn't folded because of overflow.  Avoid removing the
+	     UBSAN_CHECK_* calls in that case.  */
+	  if (vr->type == VR_RANGE
+	      && (vr->min == vr->max
+		  || operand_equal_p (vr->min, vr->max, 0)))
+	    set_value_range_to_varying (vr);
+	  return;
+	}
+    }
   if (INTEGRAL_TYPE_P (type)
       && gimple_stmt_nonnegative_warnv_p (stmt, &sop))
     set_value_range_to_nonnegative (vr, type,
--- gcc/testsuite/c-c++-common/ubsan/overflow-mul-2.c.mp	2013-11-22 00:58:49.911784181 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-mul-2.c	2013-11-22 01:35:31.796587252 +0100
@@ -0,0 +1,27 @@ 
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
+
+#define INT_MAX __INT_MAX__
+#define LONG_MAX __LONG_MAX__
+
+int
+main (void)
+{
+  volatile int j = INT_MAX;
+  volatile int i = 2;
+  volatile int k = j * i;
+  k = i * j;
+
+  volatile long int m = LONG_MAX;
+  volatile long int n = 2;
+  volatile long int o = m * n;
+  o = n * m;
+
+  return 0;
+}
+
+/* { dg-output "signed integer overflow: 2147483647 \\* 2 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: 2 \\* 2147483647 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: \[^\n\r]* \\* 2 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: 2 \\* \[^\n\r]* cannot be represented in type 'long int'(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-add-1.c.mp	2013-11-21 14:36:31.997032821 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-add-1.c	2013-11-22 15:14:53.409081665 +0100
@@ -0,0 +1,61 @@ 
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
+
+#define SCHAR_MAX __SCHAR_MAX__
+#define SHRT_MAX __SHRT_MAX__
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-__INT_MAX__ - 1)
+
+void __attribute__((noinline,noclone))
+check (int i, int j)
+{
+  if (i != j)
+    __builtin_abort ();
+}
+
+int
+main (void)
+{
+#if __INT_MAX__ == 2147483647
+  /* Here, nothing should fail.  */
+  volatile int j = INT_MAX;
+  volatile int i = -1;
+  volatile int k = j + i;
+  check (k, 2147483646);
+  k = i + j;
+  check (k, 2147483646);
+  j--;
+  check (j, 2147483646);
+
+  i = 1;
+  j = INT_MIN;
+  k = i + j;
+  check (k, -2147483647);
+  k = j + i;
+  check (k, -2147483647);
+  j++;
+  check (j, -2147483647);
+#endif
+
+  /* Test integer promotion.  */
+#if __SCHAR_MAX__ == 127
+  volatile signed char a = SCHAR_MAX;
+  volatile signed char b = 1;
+  volatile signed char c = a + b;
+  check (c, -128);
+  a++;
+  check (a, -128);
+#endif
+
+#if __SHRT_MAX__ == 32767
+  volatile short d = SHRT_MAX;
+  volatile short e = 1;
+  volatile short f = d + e;
+  check (f, -32768);
+  d++;
+  check (d, -32768);
+#endif
+
+  return 0;
+}
--- gcc/testsuite/c-c++-common/ubsan/overflow-add-2.c.mp	2013-11-21 15:20:22.148184380 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-add-2.c	2013-11-21 18:11:09.883041430 +0100
@@ -0,0 +1,61 @@ 
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
+
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-__INT_MAX__ - 1)
+#define LONG_MAX __LONG_MAX__
+#define LONG_MIN (-__LONG_MAX__ - 1L)
+#define LLONG_MAX __LONG_LONG_MAX__
+#define LLONG_MIN (-__LONG_LONG_MAX__ - 1L)
+
+int
+main (void)
+{
+  volatile int j = INT_MAX;
+  volatile int i = 1;
+  volatile int k = j + i;
+  k = i + j;
+  j++;
+  j = INT_MAX - 100;
+  j += (1 << 10);
+
+  j = INT_MIN;
+  i = -1;
+  k = i + j;
+  k = j + i;
+  j = INT_MIN + 100;
+  j += -(1 << 10);
+
+  volatile long int m = LONG_MAX;
+  volatile long int n = 1;
+  volatile long int o = m + n;
+  o = n + m;
+  m++;
+  m = LONG_MAX - 100;
+  m += (1 << 10);
+
+  m = LONG_MIN;
+  n = -1;
+  o = m + n;
+  o = n + m;
+  m = LONG_MIN + 100;
+  m += -(1 << 10);
+
+  return 0;
+}
+
+/* { dg-output "signed integer overflow: 2147483647 \\+ 1 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: 1 \\+ 2147483647 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: 2147483647 \\+ 1 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: 2147483547 \\+ 1024 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -1 \\+ -2147483648 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 \\+ -1 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -2147483548 \\+ -1024 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: \[^\n\r]* \\+ 1 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: 1 \\+ \[^\n\r]* cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: \[^\n\r]* \\+ 1 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: \[^\n\r]* \\+ 1024 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -\[^\n\r]* \\+ -1 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -1 \\+ -\[^\n\r]* cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -\[^\n\r]* \\+ -1024 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-mul-1.c.mp	2013-11-21 23:57:24.320188104 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-mul-1.c	2013-11-22 15:15:22.932196728 +0100
@@ -0,0 +1,47 @@ 
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
+
+#define SCHAR_MAX __SCHAR_MAX__
+#define SHRT_MAX __SHRT_MAX__
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-__INT_MAX__ - 1)
+
+void __attribute__((noinline,noclone))
+check (int i, int j)
+{
+  if (i != j)
+    __builtin_abort ();
+}
+
+int
+main (void)
+{
+  /* Test integer promotion.  */
+#if __SCHAR_MAX__ == 127
+  volatile signed char a = -2;
+  volatile signed char b = SCHAR_MAX;
+  volatile signed char c = a * b;
+  check (c, 2);
+#endif
+
+#if __SHRT_MAX__ == 32767
+  volatile short d = SHRT_MAX;
+  volatile short e = 2;
+  volatile short f = d * e;
+  check (f, -2);
+#endif
+
+#if __INT_MAX__ == 2147483647
+  volatile int m = INT_MAX;
+  volatile int n = 1;
+  volatile int o = m * n;
+  check (o, INT_MAX);
+
+  m = INT_MIN;
+  o = m * n;
+  check (o, INT_MIN);
+#endif
+
+  return 0;
+}
--- gcc/testsuite/c-c++-common/ubsan/overflow-sub-1.c.mp	2013-11-21 18:11:45.957184230 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-sub-1.c	2013-11-22 15:15:43.490276963 +0100
@@ -0,0 +1,63 @@ 
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
+
+#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)
+
+void __attribute__((noinline,noclone))
+check (int i, int j)
+{
+  if (i != j)
+    __builtin_abort ();
+}
+
+int
+main (void)
+{
+#if __INT_MAX__ == 2147483647
+  /* Here, nothing should fail.  */
+  volatile int i = -1;
+  volatile int j = INT_MIN;
+  volatile int k = j - i;
+  check (k, -2147483647);
+  k = i - j;
+  check (k, 2147483647);
+  j++;
+  check (j, -2147483647);
+
+  i = 1;
+  j = INT_MAX;
+  k = i - j;
+  check (k, -2147483646);
+  k = j - i;
+  check (k, 2147483646);
+  j--;
+  check (k, 2147483646);
+#endif
+
+  /* Test integer promotion.  */
+#if __SCHAR_MAX__ == 127
+  volatile signed char a = SCHAR_MIN;
+  volatile signed char b = 1;
+  volatile signed char c = a - b;
+  check (c, 127);
+  a--;
+  check (a, 127);
+#endif
+
+#if __SHRT_MAX__ == 32767
+  volatile short d = SHRT_MIN;
+  volatile short e = 1;
+  volatile short f = d - e;
+  check (f, 32767);
+  d--;
+  check (d, 32767);
+#endif
+
+  return 0;
+}
--- gcc/testsuite/c-c++-common/ubsan/overflow-sub-2.c.mp	2013-11-21 18:16:18.730175229 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-sub-2.c	2013-11-21 18:48:29.099778507 +0100
@@ -0,0 +1,55 @@ 
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
+
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-__INT_MAX__ - 1)
+#define LONG_MAX __LONG_MAX__
+#define LONG_MIN (-__LONG_MAX__ - 1L)
+#define LLONG_MAX __LONG_LONG_MAX__
+#define LLONG_MIN (-__LONG_LONG_MAX__ - 1L)
+
+int
+main (void)
+{
+  volatile int j = INT_MIN;
+  volatile int i = 1;
+  volatile int k = j - i;
+  j--;
+  j = INT_MIN + 100;
+  j -= (1 << 10);
+
+  j = INT_MIN;
+  i = -1;
+  k = j - -i;
+
+  i = INT_MIN + 1000;
+  i -= (1 << 20);
+
+  volatile long int l = LONG_MIN;
+  volatile long int m = 1;
+  volatile long int n = l - m;
+  l--;
+  l = LONG_MIN + 100;
+  l -= (1 << 10);
+
+  l = LONG_MIN;
+  m = -1;
+  n = l - -m;
+
+  m = LONG_MIN + 1000;
+  m -= (1 << 20);
+
+  return 0;
+}
+
+/* { dg-output "signed integer overflow: -2147483648 - 1 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 \\+ -1 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -2147483548 \\+ -1024 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -2147483648 \\+ -1 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -2147482648 \\+ -1048576 cannot be represented in type 'int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -\[^\n\r]* - 1 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -\[^\n\r]* \\+ -1 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -\[^\n\r]* \\+ -1024 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -\[^\n\r]* \\+ -1 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*signed integer overflow: -\[^\n\r]* \\+ -1048576 cannot be represented in type 'long int'(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/ubsan/overflow-negate-1.c.mp	2013-11-22 01:44:01.284928783 +0100
+++ gcc/testsuite/c-c++-common/ubsan/overflow-negate-1.c	2013-11-22 01:45:21.526246391 +0100
@@ -0,0 +1,14 @@ 
+/* { dg-do run { target int128 } } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
+
+#define INT_MIN (-__INT_MAX__ - 1)
+
+int
+main (void)
+{
+  int j = INT_MIN;
+  return -j;
+}
+
+/* { dg-output "negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself(\n|\r\n|\r)" } */
--- gcc/optabs.def.mp	2013-11-27 08:46:28.020629363 +0100
+++ gcc/optabs.def	2013-11-27 08:46:57.564753283 +0100
@@ -187,6 +187,10 @@  OPTAB_D (movcc_optab, "mov$acc")
 OPTAB_D (cmov_optab, "cmov$a6")
 OPTAB_D (cstore_optab, "cstore$a4")
 OPTAB_D (ctrap_optab, "ctrap$a4")
+OPTAB_D (addv4_optab, "addv$I$a4")
+OPTAB_D (subv4_optab, "subv$I$a4")
+OPTAB_D (mulv4_optab, "mulv$I$a4")
+OPTAB_D (negv3_optab, "negv$I$a3")
 
 OPTAB_D (smul_highpart_optab, "smul$a3_highpart")
 OPTAB_D (umul_highpart_optab, "umul$a3_highpart")