This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 1/2] Implement -fsanitize=signed-integer-overflow (generic parts)
- From: Marek Polacek <polacek at redhat dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Jeff Law <law at redhat dot com>, Jakub Jelinek <jakub at redhat dot com>
- Date: Wed, 4 Dec 2013 14:44:07 +0100
- Subject: [PATCH 1/2] Implement -fsanitize=signed-integer-overflow (generic parts)
- Authentication-results: sourceware.org; auth=none
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.
--- 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")
Marek