diff mbox

[1/2] Implement -fsanitize=signed-integer-overflow (generic parts)

Message ID 20131204134407.GC32420@redhat.com
State New
Headers show

Commit Message

Marek Polacek Dec. 4, 2013, 1:44 p.m. UTC
This is a repost of rebased version of the signed-integer-overflow
patch, split into generic parts and i?86 parts.  By i?86 parts I mean
the stuff that resides in config/i386, I haven't really tried to
untangle it more.
Except the two formatting fixes I also moved various PROB_ macros into
predict.h and made the users include it, rather than duplicating
the defines everywhere.

Regtested/bootstrapped on x86_64-linux.  Ok for trunk?

There are still things to do, but I'd like to get this in first.

2013-12-04  Jakub Jelinek  <jakub@redhat.com>  
	    Marek Polacek  <polacek@redhat.com>

	* opts.c (common_handle_option): Handle
	-fsanitize=signed-integer-overflow.
	* 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.
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. 4, 2013, 5:14 p.m. UTC | #1
On 12/04/13 06:44, Marek Polacek wrote:
> This is a repost of rebased version of the signed-integer-overflow
> patch, split into generic parts and i?86 parts.  By i?86 parts I mean
> the stuff that resides in config/i386, I haven't really tried to
> untangle it more.
> Except the two formatting fixes I also moved various PROB_ macros into
> predict.h and made the users include it, rather than duplicating
> the defines everywhere.
>
> Regtested/bootstrapped on x86_64-linux.  Ok for trunk?
Yes, it's OK.  If it works without the x86 backend changes, you can 
install it now.  If it requires the x86 backend changes, wait until 
those are approved and check in both together.

jeff
diff mbox

Patch

--- gcc/opts.c.mp	2013-12-04 12:15:33.517905987 +0100
+++ gcc/opts.c	2013-12-04 12:15:39.640929478 +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/predict.h.mp	2013-12-04 12:15:33.520905999 +0100
+++ gcc/predict.h	2013-12-04 12:15:39.645929498 +0100
@@ -20,6 +20,16 @@  along with GCC; see the file COPYING3.
 #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
 {
--- gcc/c-family/c-gimplify.c.mp	2013-12-04 12:15:33.506905939 +0100
+++ gcc/c-family/c-gimplify.c	2013-12-04 12:15:39.598929297 +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/trans-mem.c.mp	2013-12-04 12:15:33.522906007 +0100
+++ gcc/trans-mem.c	2013-12-04 12:15:39.649929516 +0100
@@ -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
--- gcc/sanitizer.def.mp	2013-12-04 12:15:33.521906003 +0100
+++ gcc/sanitizer.def	2013-12-04 12:15:39.645929498 +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-12-04 12:15:33.526906026 +0100
+++ gcc/ubsan.h	2013-12-04 12:15:39.658929555 +0100
@@ -43,6 +43,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-12-04 12:15:33.513905967 +0100
+++ gcc/gimple-fold.c	2013-12-04 12:15:39.635929455 +0100
@@ -2660,8 +2660,37 @@  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-12-04 12:15:33.525906021 +0100
+++ gcc/ubsan.c	2013-12-04 12:15:39.657929551 +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 {
@@ -632,6 +629,98 @@  instrument_null (gimple_stmt_iterator gs
     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 {
--- gcc/flag-types.h.mp	2013-12-04 12:15:33.510905955 +0100
+++ gcc/flag-types.h	2013-12-04 12:15:39.620929390 +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-12-04 12:15:33.514905972 +0100
+++ gcc/internal-fn.c	2013-12-04 12:15:39.638929470 +0100
@@ -31,6 +31,9 @@  along with GCC; see the file COPYING3.
 #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,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/predict.c.mp	2013-12-04 12:15:33.519905995 +0100
+++ gcc/predict.c	2013-12-04 12:15:39.643929490 +0100
@@ -74,14 +74,6 @@  along with GCC; see the file COPYING3.
 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);
--- gcc/fold-const.c.mp	2013-12-04 12:15:33.511905959 +0100
+++ gcc/fold-const.c	2013-12-04 12:15:39.624929406 +0100
@@ -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,
--- gcc/internal-fn.def.mp	2013-12-04 12:15:33.515905977 +0100
+++ gcc/internal-fn.def	2013-12-04 12:15:39.639929474 +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-12-04 12:15:33.524906016 +0100
+++ gcc/tree-vrp.c	2013-12-04 12:15:39.653929535 +0100
@@ -3757,6 +3757,47 @@  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/asan.c.mp	2013-12-04 12:15:33.505905935 +0100
+++ gcc/asan.c	2013-12-04 12:15:39.597929293 +0100
@@ -52,6 +52,7 @@  along with GCC; see the file COPYING3.
 #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 si
   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
--- gcc/optabs.def.mp	2013-12-04 12:15:33.516905982 +0100
+++ gcc/optabs.def	2013-12-04 12:15:39.639929474 +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")