diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 25651f8130a6220bdbe27abf3b5a31a26d4a28e8..6c5d257ec82550e00ca76db8704892abdb7321fe 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,50 @@
+2013-12-04  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.
+	* asan.c: Include predict.h.
+	(PROB_VERY_UNLIKELY, PROB_ALWAYS): Don't define here.
+	* predict.c: Move the PROB_* macros...
+	* predict.h (enum br_predictor): ...here.
+	(PROB_LIKELY, PROB_UNLIKELY): Define.
+	* trans-mem.c: Include predict.h.
+	(PROB_VERY_UNLIKELY, PROB_ALWAYS, PROB_VERY_LIKELY,
+	PROB_LIKELY, PROB_UNLIKELY): Don't define here.
+
 2013-12-04  Jeff Law  <law@redhat.com>
 
 	* expr.c (expand_assignment): Update comments.
diff --git a/gcc/asan.c b/gcc/asan.c
index 2245d6dd807ccb5889fbf8a676b3438a14e821df..74140d65289e608f563521b2a9704f5c61733026 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "gimple-builder.h"
 #include "ubsan.h"
+#include "predict.h"
 
 /* AddressSanitizer finds out-of-bounds and use-after-free bugs
    with <2x slowdown on average.
@@ -1311,9 +1312,6 @@ report_error_func (bool is_store, int size_in_bytes)
   return builtin_decl_implicit (report[is_store][exact_log2 (size_in_bytes)]);
 }
 
-#define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
-#define PROB_ALWAYS		(REG_BR_PROB_BASE)
-
 /* Split the current basic block and create a condition statement
    insertion point right before or after the statement pointed to by
    ITER.  Return an iterator to the point at which the caller might
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 616a74209c04b4ad0956d323ac5e2225510f6f27..35c00035e02783aeca40cccac1dbb62be87b17af 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2013-12-04  Jakub Jelinek  <jakub@redhat.com>  
+	    Marek Polacek  <polacek@redhat.com>
+
+	* c-gimplify.c (c_gimplify_expr): If doing the integer-overflow
+	sanitization, call unsigned_type_for only when !TYPE_OVERFLOW_WRAPS.
+
 2013-11-29   H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR c/59309
diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c
index d047c65b4ee1e05865e0c3466430461ba2927ab1..9f79ccb630d2eb1f92c2d834785e30bc6d257830 100644
--- a/gcc/c-family/c-gimplify.c
+++ b/gcc/c-family/c-gimplify.c
@@ -199,7 +199,9 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED,
 	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);
 	  }
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 0c732c7689f62993faf9fe2fa9c433ba5a9d5302..5ff66ccf1e59e25a7765558cdc217ec5c9f5065c 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -905,8 +905,8 @@
 			   (TI "TARGET_64BIT")])
 
 ;; Double word integer modes as mode attribute.
-(define_mode_attr DWI [(SI "DI") (DI "TI")])
-(define_mode_attr dwi [(SI "di") (DI "ti")])
+(define_mode_attr DWI [(QI "HI") (HI "SI") (SI "DI") (DI "TI")])
+(define_mode_attr dwi [(QI "hi") (HI "si") (SI "di") (DI "ti")])
 
 ;; Half mode for double word integer modes.
 (define_mode_iterator DWIH [(SI "!TARGET_64BIT")
@@ -6160,6 +6160,41 @@
   [(set_attr "type" "alu")
    (set_attr "mode" "QI")])
 
+;; Add with jump on overflow.
+(define_expand "addv<mode>4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+		   (eq:CCO (plus:<DWI>
+			      (sign_extend:<DWI>
+				 (match_operand:SWI 1 "nonimmediate_operand"))
+			      (sign_extend:<DWI>
+				 (match_operand:SWI 2 "<general_operand>")))
+			   (sign_extend:<DWI>
+			      (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)))]
+  ""
+  "ix86_fixup_binary_operands_no_copy (PLUS, <MODE>mode, operands);")
+
+(define_insn "*addv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+	(eq:CCO (plus:<DWI>
+		   (sign_extend:<DWI>
+		      (match_operand:SWI 1 "nonimmediate_operand" "%0,0"))
+		   (sign_extend:<DWI>
+		      (match_operand:SWI 2 "<general_operand>" "<g>,<r><i>")))
+		(sign_extend:<DWI>
+		   (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.
 
@@ -6397,6 +6432,41 @@
   [(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:<DWI>
+			      (sign_extend:<DWI>
+				 (match_operand:SWI 1 "nonimmediate_operand"))
+			      (sign_extend:<DWI>
+				 (match_operand:SWI 2 "<general_operand>")))
+			   (sign_extend:<DWI>
+			      (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)))]
+  ""
+  "ix86_fixup_binary_operands_no_copy (MINUS, <MODE>mode, operands);")
+
+(define_insn "*subv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+	(eq:CCO (minus:<DWI>
+		   (sign_extend:<DWI>
+		      (match_operand:SWI 1 "nonimmediate_operand" "0,0"))
+		   (sign_extend:<DWI>
+		      (match_operand:SWI 2 "<general_operand>" "<r><i>,<r>m")))
+		(sign_extend:<DWI>
+		   (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")
@@ -6711,6 +6781,58 @@
    (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:<DWI>
+			      (sign_extend:<DWI>
+				 (match_operand:SWI48 1 "register_operand"))
+			      (sign_extend:<DWI>
+				 (match_operand:SWI48 2 "<general_operand>")))
+			   (sign_extend:<DWI>
+			      (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:<DWI>
+		   (sign_extend:<DWI>
+		      (match_operand:SWI 1 "nonimmediate_operand" "%rm,rm,0"))
+		   (sign_extend:<DWI>
+		      (match_operand:SWI 2 "<general_operand>" "K,<i>,mr")))
+		(sign_extend:<DWI>
+		   (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>
@@ -8624,6 +8746,36 @@
   [(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")
+			   (match_dup 3)))
+	      (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)))]
+  ""
+{
+  operands[3]
+    = gen_int_mode (HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (<MODE>mode) - 1),
+		    <MODE>mode);
+})
+
+(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"
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 5ba909766fe6c2991b92ec32a420051100a29e7a..bea268f9aba729650c36b2d5d77e6221b5d4c266 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -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. */
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5cf8ed196d75098bf7645051966c59cb3164216b..0781bdb52c8e1e9bdd4776e923c6c21da2b9af85 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -10350,14 +10350,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,
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 7e9ba653f32aeb0142a99102181d53749e9b5404..72893cd4aecdbc8b3a9799ba89adc37ddc77385a 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -2660,8 +2660,37 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree))
 	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
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 9ae917ba0acd528dd10cf4c2db81097bfb3d3f81..527b5ffaf7f8b973e7eadb44983f1ca732ff8e8f 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -31,6 +31,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-expr.h"
 #include "is-a.h"
 #include "gimple.h"
+#include "ubsan.h"
+#include "target.h"
+#include "predict.h"
 
 /* The names of each internal function, indexed by function number.  */
 const char *const internal_fn_name_array[] = {
@@ -153,6 +156,305 @@ expand_UBSAN_NULL (gimple stmt ATTRIBUTE_UNUSED)
   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);
+        }
+      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:
 
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 7193874c811b94e44a0a5bdd440572ffb25d41f6..08a514eeec2135d9ed87a7b3a91a8b05288a0c33 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -45,3 +45,6 @@ DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
 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)
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 6b924acf8cdd5917f3b4d67568807b0a1e02c911..cad96d2aea5b3bbfdfa2b610776516050b15e7ab 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -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")
diff --git a/gcc/opts.c b/gcc/opts.c
index a0a6c53128c8c0919598e4a695b8353f930a8424..7e61cbce7f86fd3556c7b4931fb71ecfb3add8c2 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1460,6 +1460,8 @@ common_handle_option (struct gcc_options *opts,
 	      { "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;
diff --git a/gcc/predict.c b/gcc/predict.c
index 822343b1295ad6e187f133ca25461b61791037b5..1cd3fa621ea5103f3d16761b23b8a9cd81a96b6c 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -74,14 +74,6 @@ along with GCC; see the file COPYING3.  If not see
 static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
 	     real_inv_br_prob_base, real_one_half, real_bb_freq_max;
 
-/* Random guesstimation given names.
-   PROV_VERY_UNLIKELY should be small enough so basic block predicted
-   by it gets below HOT_BB_FREQUENCY_FRACTION.  */
-#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)
-
 static void combine_predictions_for_insn (rtx, basic_block);
 static void dump_prediction (FILE *, enum br_predictor, int, basic_block, int);
 static void predict_paths_leading_to (basic_block, enum br_predictor, enum prediction);
diff --git a/gcc/predict.h b/gcc/predict.h
index 83b1695c65eaebb3ed975e5d57b43fbb6c302494..23435dc2c99d0ebf068a47e870cbb13a2306a2f6 100644
--- a/gcc/predict.h
+++ b/gcc/predict.h
@@ -20,6 +20,16 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_PREDICT_H
 #define GCC_PREDICT_H
 
+/* Random guesstimation given names.
+   PROB_VERY_UNLIKELY should be small enough so basic block predicted
+   by it gets below HOT_BB_FREQUENCY_FRACTION.  */
+#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)
+#define PROB_UNLIKELY           (REG_BR_PROB_BASE / 5 - 1)
+#define PROB_LIKELY             (PROB_ALWAYS - PROB_VERY_LIKELY)
+
 #define DEF_PREDICTOR(ENUM, NAME, HITRATE, FLAGS) ENUM,
 enum br_predictor
 {
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 5bf1e3cebe6215d64e52ea299b436b645cd44442..9c94650321ee6df77f6ad46dbfff74a43d72639e 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -315,3 +315,19 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH,
 		      "__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)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f05612efb7240b3d0fc1d76bfeb653b93818b2de..6703e6a87ddfd216cf3c20b7135816466263f80b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2013-12-04  Marek Polacek  <polacek@redhat.com>
+
+	* 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.
+
 2013-12-04  Marek Polacek  <polacek@redhat.com>
 
 	PR c/54113
diff --git a/gcc/testsuite/c-c++-common/ubsan/overflow-add-1.c b/gcc/testsuite/c-c++-common/ubsan/overflow-add-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..436082d21d95b7799fbeac5194d8c6f2d0160671
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/overflow-add-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/overflow-add-2.c b/gcc/testsuite/c-c++-common/ubsan/overflow-add-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..de2cd2d0f88f634a55a12df9ad085ccb3b2fbf1f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/overflow-add-2.c
@@ -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)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/overflow-mul-1.c b/gcc/testsuite/c-c++-common/ubsan/overflow-mul-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..0f2ea59df491ac4692dbe7c5c4d9c41135d50922
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/overflow-mul-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/overflow-mul-2.c b/gcc/testsuite/c-c++-common/ubsan/overflow-mul-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..adcbfe1a76196e40ee7975c9adef0f9f8e969b04
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/overflow-mul-2.c
@@ -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)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/overflow-negate-1.c b/gcc/testsuite/c-c++-common/ubsan/overflow-negate-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..9baada41007deded1ebe9e3848ffc3e4a2844552
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/overflow-negate-1.c
@@ -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)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/overflow-sub-1.c b/gcc/testsuite/c-c++-common/ubsan/overflow-sub-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..3b955279ba79bd18ffcdbb60142eb90c5836b18b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/overflow-sub-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/overflow-sub-2.c b/gcc/testsuite/c-c++-common/ubsan/overflow-sub-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e06e3f6e891ae3e31abf6aac01507b69fa70dd30
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/overflow-sub-2.c
@@ -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)" } */
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index 31dee7678d28e5db170a264598c60479013dc349..b2adc3d03e9b31bba1ae25263797933d6756a17d 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -55,14 +55,9 @@
 #include "gimple-pretty-print.h"
 #include "cfgloop.h"
 #include "tree-ssa-address.h"
+#include "predict.h"
 
 
-#define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
-#define PROB_VERY_LIKELY	(PROB_ALWAYS - PROB_VERY_UNLIKELY)
-#define PROB_UNLIKELY		(REG_BR_PROB_BASE / 5 - 1)
-#define PROB_LIKELY		(PROB_ALWAYS - PROB_VERY_LIKELY)
-#define PROB_ALWAYS		(REG_BR_PROB_BASE)
-
 #define A_RUNINSTRUMENTEDCODE	0x0001
 #define A_RUNUNINSTRUMENTEDCODE	0x0002
 #define A_SAVELIVEVARIABLES	0x0004
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 89f2ffd111ce41b9deefcc4f323a1fff75445f84..d98b7764b400c9c9e4e3aa0b5b7cdd8ee91d08dd 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -3757,6 +3757,47 @@ extract_range_basic (value_range_t *vr, gimple stmt)
 	  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,
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index e33e62a028ae25dfaa6486171127c594df765d9c..aaf74acb546e3bb6ea9198d5bbecf6f978853353 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -41,9 +41,6 @@ along with GCC; see the file COPYING3.  If not see
 #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 {
@@ -632,6 +629,98 @@ instrument_null (gimple_stmt_iterator gsi, bool is_lhs)
     instrument_member_call (&gsi);
 }
 
+/* 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
@@ -651,6 +740,10 @@ ubsan_pass (void)
 	      continue;
 	    }
 
+	  if ((flag_sanitize & SANITIZE_SI_OVERFLOW)
+	      && is_gimple_assign (stmt))
+	    instrument_si_overflow (gsi);
+
 	  if (flag_sanitize & SANITIZE_NULL)
 	    {
 	      if (gimple_store_p (stmt))
@@ -668,7 +761,7 @@ ubsan_pass (void)
 static bool
 gate_ubsan (void)
 {
-  return flag_sanitize & SANITIZE_NULL;
+  return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW);
 }
 
 namespace {
diff --git a/gcc/ubsan.h b/gcc/ubsan.h
index 666e5fe15abffb84b1c19c24d60df37aa212b3d2..0aced4aac67e86a80329e06da433813b8440a92f 100644
--- a/gcc/ubsan.h
+++ b/gcc/ubsan.h
@@ -43,6 +43,7 @@ extern tree ubsan_create_data (const char *, location_t,
 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  */