diff mbox

__builtin_*_overflow builtins (PR c/59708)

Message ID 20141110205939.GQ5026@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Nov. 10, 2014, 8:59 p.m. UTC
Hi!

This patch implements what I understood from Joseph's
https://gcc.gnu.org/ml/gcc/2013-10/msg00280.html
and also adds clang compatible builtins (which implement
small subset of the typegeneric ones).

Besides the clang compatibility builtins, there are 3 new
type-generic builtins, __builtin_{add,sub,mul}_overflow, which
have 3 arguments, two arbitrary integral arguments, and pointer
to some integer type.  These builtins extend both arguments
to infinite precision signed arguments, perform {+,-,*} operations
in the infinite precision and finally cast the result to the type
pointed by the third argument and store the result there (modulo
2^precision of the type).  If the infinite precision result is equal
to the stored value, the built-ins return false (no overflow), otherwise
they return true.

The built-ins are folded immediately into internal functions that return
both results (integer result and boolean overflow flag) as _Complex integer
result, so that the integer result doesn't have to be addressable.
It partly reuses code to emit -fsanitize=signed-integer-overflow internal
functions, for signed overflows on e.g. i?86 will use jo/jno/seto/setno
instructions after the arithmetic instructions; for imsogmed arithmetic
overflow, combiner manages to transform what is emitted into
jc/jnc/setc/setnc where possible.

After discussions with Richard on IRC, the internal functions have
arbitrary integral arguments, which can have different or same signs,
different or same precisions, and the result type is _Complex integer
derived from the call's third argument.  gimple-fold.c and tree-vrp.c
is tought to perform some optimizations on these, and most of the smarts
are performed during expansion (many of the 16 different +/-
signarg1/signarg2/signresult cases require different code, and for *
there are also a couple of different cases).
If somebody can come up with some shorter sequence how to test for the
less common cases, I'd appreciate hints (internal-fn.c has big comments
which explain how it now computes the integral result and especially
the overflow flag).

Bootstrapped/regtested on x86_64-linux and i686-linux (on top of the ICF
gimple_call fix I've mailed a few minutes ago), ok for trunk?

2014-11-10  Jakub Jelinek  <jakub@redhat.com>

	PR c/59708
	* builtin-attrs.def (ATTR_NOTHROW_TYPEGENERIC_LEAF): New attribute.
	* builtins.c (fold_builtin_arith_overflow): New function.
	(fold_builtin_3): Use it.
	* builtins.def (BUILT_IN_ADD_OVERFLOW, BUILT_IN_SUB_OVERFLOW,
	BUILT_IN_MUL_OVERFLOW, BUILT_IN_SADD_OVERFLOW, BUILT_IN_SADDL_OVERFLOW,
	BUILT_IN_SADDLL_OVERFLOW, BUILT_IN_SSUB_OVERFLOW,
	BUILT_IN_SSUBL_OVERFLOW, BUILT_IN_SSUBLL_OVERFLOW,
	BUILT_IN_SMUL_OVERFLOW, BUILT_IN_SMULL_OVERFLOW,
	BUILT_IN_SMULLL_OVERFLOW, BUILT_IN_UADDL_OVERFLOW,
	BUILT_IN_UADDLL_OVERFLOW, BUILT_IN_USUB_OVERFLOW,
	BUILT_IN_USUBL_OVERFLOW, BUILT_IN_USUBLL_OVERFLOW,
	BUILT_IN_UMUL_OVERFLOW, BUILT_IN_UMULL_OVERFLOW,
	BUILT_IN_UMULLL_OVERFLOW): New built-in functions.
	* builtin-types.def (BT_PTR_UINT, BT_PTR_ULONG, BT_PTR_LONGLONG,
	BT_FN_BOOL_INT_INT_INTPTR, BT_FN_BOOL_LONG_LONG_LONGPTR,
	BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, BT_FN_BOOL_UINT_UINT_UINTPTR,
	BT_FN_BOOL_ULONG_ULONG_ULONGPTR,
	BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, BT_FN_BOOL_VAR): New.
	* expr.c (write_complex_part): Remove prototype, no longer static.
	* expr.h (write_complex_part): New prototype.
	* function.c (aggregate_value_p): For internal functions return 0.
	* gimple-fold.c (arith_overflowed_p, find_non_realpart_uses): New
	functions.
	(gimple_fold_call): Fold {ADD,SUB,MUL}_OVERFLOW internal calls.
	* gimple-fold.h (arith_overflowed_p): New prototype.
	* gimplify.c (gimplify_call_expr): Handle gimplification of
	internal calls with lhs.
	* internal-fn.c (get_range_pos_neg, get_min_precision,
	expand_arith_overflow_result_store): New functions.
	(ubsan_expand_si_overflow_addsub_check): Renamed to ...
	(expand_addsub_overflow): ... this.  Add LOC, LHS, ARG0, ARG1,
	UNSR_P, UNS0_P, UNS1_P, IS_UBSAN arguments, remove STMT argument.
	Handle ADD_OVERFLOW and SUB_OVERFLOW expansion.
	(ubsan_expand_si_overflow_neg_check): Renamed to ...
	(expand_neg_overflow): ... this.  Add LOC, LHS, ARG1, IS_UBSAN
	arguments, remove STMT argument.  Handle SUB_OVERFLOW with
	0 as first argument expansion.
	(ubsan_expand_si_overflow_mul_check): Renamed to ...
	(expand_mul_overflow): ... this.  Add LOC, LHS, ARG0, ARG1,
	UNSR_P, UNS0_P, UNS1_P, IS_UBSAN arguments, remove STMT argument.
	Handle MUL_OVERFLOW expansion.
	(expand_UBSAN_CHECK_ADD): Use expand_addsub_overflow, prepare
	arguments for it.
	(expand_UBSAN_CHECK_SUB): Use expand_addsub_overflow or
	expand_neg_overflow, prepare arguments for it.
	(expand_UBSAN_CHECK_MUL): Use expand_mul_overflow, prepare arguments
	for it.
	(expand_arith_overflow, expand_ADD_OVERFLOW, expand_SUB_OVERFLOW,
	expand_MUL_OVERFLOW): New functions.
	* internal-fn.def (ADD_OVERFLOW, SUB_OVERFLOW, MUL_OVERFLOW): New
	internal functions.
	* tree-vrp.c (check_for_binary_op_overflow): New function.
	(extract_range_basic): Handle {REAL,IMAG}PART_EXPR if the operand
	is SSA_NAME set by {ADD,SUB,MUL}_OVERFLOW internal functions.
	(simplify_internal_call_using_ranges): Handle {ADD,SUB,MUL}_OVERFLOW
	internal functions.
	* optabs.def (umulv4_optab): New optab.
	* config/i386/i386.md (umulv<mode>4, <u>mulvqi4): New define_expands.
	(*umulv<mode>4, *<u>mulvqi4): New define_insns.
	* doc/extend.texi (Integer Overflow Builtins): Document
	__builtin_*_overflow.
c-family/
	* c-common.c (check_builtin_function_arguments): Handle
	BUILT_IN_{ADD,SUB,MUL}_OVERFLOW.
testsuite/
	* c-c++-common/builtin-arith-overflow-1.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-10.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-11.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-12.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-12.h: New file.
	* c-c++-common/torture/builtin-arith-overflow-13.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-14.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-15.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-16.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-17.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-18.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-1.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-1.h: New file.
	* c-c++-common/torture/builtin-arith-overflow-2.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-3.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-4.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-5.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-6.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-7.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-8.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-9.c: New test.
	* c-c++-common/torture/builtin-arith-overflow.h: New file.
	* gcc.dg/builtin-arith-overflow-1.c: New test.
	* gcc.dg/builtin-arith-overflow-2.c: New test.


	Jakub

Comments

Richard Biener Nov. 11, 2014, 2:12 p.m. UTC | #1
On Mon, 10 Nov 2014, Jakub Jelinek wrote:

> Hi!
> 
> This patch implements what I understood from Joseph's
> https://gcc.gnu.org/ml/gcc/2013-10/msg00280.html
> and also adds clang compatible builtins (which implement
> small subset of the typegeneric ones).
> 
> Besides the clang compatibility builtins, there are 3 new
> type-generic builtins, __builtin_{add,sub,mul}_overflow, which
> have 3 arguments, two arbitrary integral arguments, and pointer
> to some integer type.  These builtins extend both arguments
> to infinite precision signed arguments, perform {+,-,*} operations
> in the infinite precision and finally cast the result to the type
> pointed by the third argument and store the result there (modulo
> 2^precision of the type).  If the infinite precision result is equal
> to the stored value, the built-ins return false (no overflow), otherwise
> they return true.
> 
> The built-ins are folded immediately into internal functions that return
> both results (integer result and boolean overflow flag) as _Complex integer
> result, so that the integer result doesn't have to be addressable.
> It partly reuses code to emit -fsanitize=signed-integer-overflow internal
> functions, for signed overflows on e.g. i?86 will use jo/jno/seto/setno
> instructions after the arithmetic instructions; for imsogmed arithmetic
> overflow, combiner manages to transform what is emitted into
> jc/jnc/setc/setnc where possible.
> 
> After discussions with Richard on IRC, the internal functions have
> arbitrary integral arguments, which can have different or same signs,
> different or same precisions, and the result type is _Complex integer
> derived from the call's third argument.  gimple-fold.c and tree-vrp.c
> is tought to perform some optimizations on these, and most of the smarts
> are performed during expansion (many of the 16 different +/-
> signarg1/signarg2/signresult cases require different code, and for *
> there are also a couple of different cases).
> If somebody can come up with some shorter sequence how to test for the
> less common cases, I'd appreciate hints (internal-fn.c has big comments
> which explain how it now computes the integral result and especially
> the overflow flag).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux (on top of the ICF
> gimple_call fix I've mailed a few minutes ago), ok for trunk?

This is mostly fine but the immediate use walking in gimple-fold.
Statements do not have their SSA operands updated during (re-)folding
so the DCE transform needs to be done elsewhere - in DCE for example,
or in SRA.

The i386 backend changes need separate review.

Thanks,
Richard.

> 2014-11-10  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c/59708
> 	* builtin-attrs.def (ATTR_NOTHROW_TYPEGENERIC_LEAF): New attribute.
> 	* builtins.c (fold_builtin_arith_overflow): New function.
> 	(fold_builtin_3): Use it.
> 	* builtins.def (BUILT_IN_ADD_OVERFLOW, BUILT_IN_SUB_OVERFLOW,
> 	BUILT_IN_MUL_OVERFLOW, BUILT_IN_SADD_OVERFLOW, BUILT_IN_SADDL_OVERFLOW,
> 	BUILT_IN_SADDLL_OVERFLOW, BUILT_IN_SSUB_OVERFLOW,
> 	BUILT_IN_SSUBL_OVERFLOW, BUILT_IN_SSUBLL_OVERFLOW,
> 	BUILT_IN_SMUL_OVERFLOW, BUILT_IN_SMULL_OVERFLOW,
> 	BUILT_IN_SMULLL_OVERFLOW, BUILT_IN_UADDL_OVERFLOW,
> 	BUILT_IN_UADDLL_OVERFLOW, BUILT_IN_USUB_OVERFLOW,
> 	BUILT_IN_USUBL_OVERFLOW, BUILT_IN_USUBLL_OVERFLOW,
> 	BUILT_IN_UMUL_OVERFLOW, BUILT_IN_UMULL_OVERFLOW,
> 	BUILT_IN_UMULLL_OVERFLOW): New built-in functions.
> 	* builtin-types.def (BT_PTR_UINT, BT_PTR_ULONG, BT_PTR_LONGLONG,
> 	BT_FN_BOOL_INT_INT_INTPTR, BT_FN_BOOL_LONG_LONG_LONGPTR,
> 	BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, BT_FN_BOOL_UINT_UINT_UINTPTR,
> 	BT_FN_BOOL_ULONG_ULONG_ULONGPTR,
> 	BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, BT_FN_BOOL_VAR): New.
> 	* expr.c (write_complex_part): Remove prototype, no longer static.
> 	* expr.h (write_complex_part): New prototype.
> 	* function.c (aggregate_value_p): For internal functions return 0.
> 	* gimple-fold.c (arith_overflowed_p, find_non_realpart_uses): New
> 	functions.
> 	(gimple_fold_call): Fold {ADD,SUB,MUL}_OVERFLOW internal calls.
> 	* gimple-fold.h (arith_overflowed_p): New prototype.
> 	* gimplify.c (gimplify_call_expr): Handle gimplification of
> 	internal calls with lhs.
> 	* internal-fn.c (get_range_pos_neg, get_min_precision,
> 	expand_arith_overflow_result_store): New functions.
> 	(ubsan_expand_si_overflow_addsub_check): Renamed to ...
> 	(expand_addsub_overflow): ... this.  Add LOC, LHS, ARG0, ARG1,
> 	UNSR_P, UNS0_P, UNS1_P, IS_UBSAN arguments, remove STMT argument.
> 	Handle ADD_OVERFLOW and SUB_OVERFLOW expansion.
> 	(ubsan_expand_si_overflow_neg_check): Renamed to ...
> 	(expand_neg_overflow): ... this.  Add LOC, LHS, ARG1, IS_UBSAN
> 	arguments, remove STMT argument.  Handle SUB_OVERFLOW with
> 	0 as first argument expansion.
> 	(ubsan_expand_si_overflow_mul_check): Renamed to ...
> 	(expand_mul_overflow): ... this.  Add LOC, LHS, ARG0, ARG1,
> 	UNSR_P, UNS0_P, UNS1_P, IS_UBSAN arguments, remove STMT argument.
> 	Handle MUL_OVERFLOW expansion.
> 	(expand_UBSAN_CHECK_ADD): Use expand_addsub_overflow, prepare
> 	arguments for it.
> 	(expand_UBSAN_CHECK_SUB): Use expand_addsub_overflow or
> 	expand_neg_overflow, prepare arguments for it.
> 	(expand_UBSAN_CHECK_MUL): Use expand_mul_overflow, prepare arguments
> 	for it.
> 	(expand_arith_overflow, expand_ADD_OVERFLOW, expand_SUB_OVERFLOW,
> 	expand_MUL_OVERFLOW): New functions.
> 	* internal-fn.def (ADD_OVERFLOW, SUB_OVERFLOW, MUL_OVERFLOW): New
> 	internal functions.
> 	* tree-vrp.c (check_for_binary_op_overflow): New function.
> 	(extract_range_basic): Handle {REAL,IMAG}PART_EXPR if the operand
> 	is SSA_NAME set by {ADD,SUB,MUL}_OVERFLOW internal functions.
> 	(simplify_internal_call_using_ranges): Handle {ADD,SUB,MUL}_OVERFLOW
> 	internal functions.
> 	* optabs.def (umulv4_optab): New optab.
> 	* config/i386/i386.md (umulv<mode>4, <u>mulvqi4): New define_expands.
> 	(*umulv<mode>4, *<u>mulvqi4): New define_insns.
> 	* doc/extend.texi (Integer Overflow Builtins): Document
> 	__builtin_*_overflow.
> c-family/
> 	* c-common.c (check_builtin_function_arguments): Handle
> 	BUILT_IN_{ADD,SUB,MUL}_OVERFLOW.
> testsuite/
> 	* c-c++-common/builtin-arith-overflow-1.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-10.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-11.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-12.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-12.h: New file.
> 	* c-c++-common/torture/builtin-arith-overflow-13.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-14.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-15.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-16.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-17.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-18.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-1.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-1.h: New file.
> 	* c-c++-common/torture/builtin-arith-overflow-2.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-3.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-4.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-5.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-6.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-7.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-8.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow-9.c: New test.
> 	* c-c++-common/torture/builtin-arith-overflow.h: New file.
> 	* gcc.dg/builtin-arith-overflow-1.c: New test.
> 	* gcc.dg/builtin-arith-overflow-2.c: New test.
> 
> --- gcc/builtin-attrs.def.jj	2014-01-03 11:40:35.000000000 +0100
> +++ gcc/builtin-attrs.def	2014-10-30 14:57:07.696883004 +0100
> @@ -178,6 +178,9 @@ DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL
>  /* Nothrow functions whose fifth parameter is a nonnull pointer.  */
>  DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_5, ATTR_NONNULL, ATTR_LIST_5, \
>  			ATTR_NOTHROW_LIST)
> +/* Nothrow leaf functions which are type-generic.  */
> +DEF_ATTR_TREE_LIST (ATTR_NOTHROW_TYPEGENERIC_LEAF, ATTR_TYPEGENERIC, ATTR_NULL, \
> +			ATTR_NOTHROW_LEAF_LIST)
>  /* Nothrow const functions whose pointer parameter(s) are all nonnull.  */
>  DEF_ATTR_TREE_LIST (ATTR_CONST_NOTHROW_NONNULL, ATTR_CONST, ATTR_NULL, \
>  			ATTR_NOTHROW_NONNULL)
> --- gcc/builtins.c.jj	2014-10-30 14:42:22.000000000 +0100
> +++ gcc/builtins.c	2014-11-05 16:19:43.728949900 +0100
> @@ -9652,6 +9652,62 @@ fold_builtin_unordered_cmp (location_t l
>  		      fold_build2_loc (loc, code, type, arg0, arg1));
>  }
>  
> +/* Fold __builtin_{,s,u}{add,sub,mul}{,l,ll}_overflow, either into normal
> +   arithmetics if it can never overflow, or into internal functions that
> +   return both result of arithmetics and overflowed boolean flag in
> +   a complex integer result, or some other check for overflow.  */
> +
> +static tree
> +fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
> +			     tree arg0, tree arg1, tree arg2)
> +{
> +  enum internal_fn ifn = IFN_LAST;
> +  tree type = TREE_TYPE (TREE_TYPE (arg2));
> +  tree mem_arg2 = build_fold_indirect_ref_loc (loc, arg2);
> +  switch (fcode)
> +    {
> +    case BUILT_IN_ADD_OVERFLOW:
> +    case BUILT_IN_SADD_OVERFLOW:
> +    case BUILT_IN_SADDL_OVERFLOW:
> +    case BUILT_IN_SADDLL_OVERFLOW:
> +    case BUILT_IN_UADD_OVERFLOW:
> +    case BUILT_IN_UADDL_OVERFLOW:
> +    case BUILT_IN_UADDLL_OVERFLOW:
> +      ifn = IFN_ADD_OVERFLOW;
> +      break;
> +    case BUILT_IN_SUB_OVERFLOW:
> +    case BUILT_IN_SSUB_OVERFLOW:
> +    case BUILT_IN_SSUBL_OVERFLOW:
> +    case BUILT_IN_SSUBLL_OVERFLOW:
> +    case BUILT_IN_USUB_OVERFLOW:
> +    case BUILT_IN_USUBL_OVERFLOW:
> +    case BUILT_IN_USUBLL_OVERFLOW:
> +      ifn = IFN_SUB_OVERFLOW;
> +      break;
> +    case BUILT_IN_MUL_OVERFLOW:
> +    case BUILT_IN_SMUL_OVERFLOW:
> +    case BUILT_IN_SMULL_OVERFLOW:
> +    case BUILT_IN_SMULLL_OVERFLOW:
> +    case BUILT_IN_UMUL_OVERFLOW:
> +    case BUILT_IN_UMULL_OVERFLOW:
> +    case BUILT_IN_UMULLL_OVERFLOW:
> +      ifn = IFN_MUL_OVERFLOW;
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +  tree ctype = build_complex_type (type);
> +  tree call = build_call_expr_internal_loc (loc, ifn, ctype,
> +					    2, arg0, arg1);
> +  tree tgt = save_expr (call);
> +  tree intres = build1_loc (loc, REALPART_EXPR, type, tgt);
> +  tree ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt);
> +  ovfres = fold_convert_loc (loc, boolean_type_node, ovfres);
> +  tree store
> +    = fold_build2_loc (loc, MODIFY_EXPR, void_type_node, mem_arg2, intres);
> +  return build2_loc (loc, COMPOUND_EXPR, boolean_type_node, store, ovfres);
> +}
> +
>  /* Fold a call to built-in function FNDECL with 0 arguments.
>     IGNORE is true if the result of the function call is ignored.  This
>     function returns NULL_TREE if no simplification was possible.  */
> @@ -10359,6 +10415,29 @@ fold_builtin_3 (location_t loc, tree fnd
>      case BUILT_IN_EXPECT:
>        return fold_builtin_expect (loc, arg0, arg1, arg2);
>  
> +    case BUILT_IN_ADD_OVERFLOW:
> +    case BUILT_IN_SUB_OVERFLOW:
> +    case BUILT_IN_MUL_OVERFLOW:
> +    case BUILT_IN_SADD_OVERFLOW:
> +    case BUILT_IN_SADDL_OVERFLOW:
> +    case BUILT_IN_SADDLL_OVERFLOW:
> +    case BUILT_IN_SSUB_OVERFLOW:
> +    case BUILT_IN_SSUBL_OVERFLOW:
> +    case BUILT_IN_SSUBLL_OVERFLOW:
> +    case BUILT_IN_SMUL_OVERFLOW:
> +    case BUILT_IN_SMULL_OVERFLOW:
> +    case BUILT_IN_SMULLL_OVERFLOW:
> +    case BUILT_IN_UADD_OVERFLOW:
> +    case BUILT_IN_UADDL_OVERFLOW:
> +    case BUILT_IN_UADDLL_OVERFLOW:
> +    case BUILT_IN_USUB_OVERFLOW:
> +    case BUILT_IN_USUBL_OVERFLOW:
> +    case BUILT_IN_USUBLL_OVERFLOW:
> +    case BUILT_IN_UMUL_OVERFLOW:
> +    case BUILT_IN_UMULL_OVERFLOW:
> +    case BUILT_IN_UMULLL_OVERFLOW:
> +      return fold_builtin_arith_overflow (loc, fcode, arg0, arg1, arg2);
> +
>      default:
>        break;
>      }
> --- gcc/builtins.def.jj	2014-07-08 11:35:59.000000000 +0200
> +++ gcc/builtins.def	2014-10-31 08:23:57.202451020 +0100
> @@ -665,6 +665,30 @@ DEF_C94_BUILTIN        (BUILT_IN_ISWXDIG
>  DEF_C94_BUILTIN        (BUILT_IN_TOWLOWER, "towlower", BT_FN_WINT_WINT, ATTR_PURE_NOTHROW_LEAF_LIST)
>  DEF_C94_BUILTIN        (BUILT_IN_TOWUPPER, "towupper", BT_FN_WINT_WINT, ATTR_PURE_NOTHROW_LEAF_LIST)
>  
> +/* Category: integer overflow checking builtins.  */
> +DEF_GCC_BUILTIN        (BUILT_IN_ADD_OVERFLOW, "add_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
> +DEF_GCC_BUILTIN        (BUILT_IN_SUB_OVERFLOW, "sub_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
> +DEF_GCC_BUILTIN        (BUILT_IN_MUL_OVERFLOW, "mul_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
> +/* Clang compatibility.  */
> +DEF_GCC_BUILTIN        (BUILT_IN_SADD_OVERFLOW, "sadd_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_SADDL_OVERFLOW, "saddl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_SADDLL_OVERFLOW, "saddll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_SSUB_OVERFLOW, "ssub_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_SSUBL_OVERFLOW, "ssubl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_SSUBLL_OVERFLOW, "ssubll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_SMUL_OVERFLOW, "smul_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_SMULL_OVERFLOW, "smull_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_SMULLL_OVERFLOW, "smulll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_UADD_OVERFLOW, "uadd_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_UADDL_OVERFLOW, "uaddl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_UADDLL_OVERFLOW, "uaddll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_USUB_OVERFLOW, "usub_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_USUBL_OVERFLOW, "usubl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_USUBLL_OVERFLOW, "usubll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_UMUL_OVERFLOW, "umul_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_UMULL_OVERFLOW, "umull_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_UMULLL_OVERFLOW, "umulll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
> +
>  /* Category: miscellaneous builtins.  */
>  DEF_LIB_BUILTIN        (BUILT_IN_ABORT, "abort", BT_FN_VOID, ATTR_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_LIB_BUILTIN        (BUILT_IN_ABS, "abs", BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
> --- gcc/builtin-types.def.jj	2014-10-15 12:28:19.000000000 +0200
> +++ gcc/builtin-types.def	2014-10-31 08:25:08.801128373 +0100
> @@ -126,7 +126,10 @@ DEF_PRIMITIVE_TYPE (BT_I16, builtin_type
>  DEF_PRIMITIVE_TYPE (BT_BND, pointer_bounds_type_node)
>  
>  DEF_POINTER_TYPE (BT_PTR_CONST_STRING, BT_CONST_STRING)
> +DEF_POINTER_TYPE (BT_PTR_UINT, BT_UINT)
>  DEF_POINTER_TYPE (BT_PTR_LONG, BT_LONG)
> +DEF_POINTER_TYPE (BT_PTR_ULONG, BT_ULONG)
> +DEF_POINTER_TYPE (BT_PTR_LONGLONG, BT_LONGLONG)
>  DEF_POINTER_TYPE (BT_PTR_ULONGLONG, BT_ULONGLONG)
>  DEF_POINTER_TYPE (BT_PTR_PTR, BT_PTR)
>  
> @@ -435,6 +438,18 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I16
>  DEF_FUNCTION_TYPE_3 (BT_FN_INT_PTRPTR_SIZE_SIZE, BT_INT, BT_PTR_PTR, BT_SIZE, BT_SIZE)
>  DEF_FUNCTION_TYPE_3 (BT_FN_PTR_CONST_PTR_CONST_PTR_SIZE, BT_PTR, BT_CONST_PTR, BT_CONST_PTR, BT_SIZE)
>  DEF_FUNCTION_TYPE_3 (BT_FN_VOID_CONST_PTR_BND_CONST_PTR, BT_VOID, BT_CONST_PTR, BT_BND, BT_CONST_PTR)
> +DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_INT_INT_INTPTR, BT_BOOL, BT_INT, BT_INT,
> +		     BT_INT_PTR)
> +DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_LONG_LONG_LONGPTR, BT_BOOL, BT_LONG, BT_LONG,
> +		     BT_PTR_LONG)
> +DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, BT_BOOL,
> +		     BT_LONGLONG, BT_LONGLONG, BT_PTR_LONGLONG)
> +DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_UINT_UINT_UINTPTR, BT_BOOL, BT_UINT, BT_UINT,
> +		     BT_PTR_UINT)
> +DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_ULONG_ULONG_ULONGPTR, BT_BOOL, BT_ULONG,
> +		     BT_ULONG, BT_PTR_ULONG)
> +DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, BT_BOOL,
> +		     BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG)
>  
>  DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR,
>  		     BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR)
> @@ -532,6 +547,7 @@ DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PT
>  DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
>  DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT)
>  DEF_FUNCTION_TYPE_VAR_0 (BT_FN_PTR_VAR, BT_PTR)
> +DEF_FUNCTION_TYPE_VAR_0 (BT_FN_BOOL_VAR, BT_BOOL)
>  
>  DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_VALIST_REF_VAR,
>  			 BT_VOID, BT_VALIST_REF)
> --- gcc/expr.c.jj	2014-10-30 14:42:23.000000000 +0100
> +++ gcc/expr.c	2014-10-30 18:00:24.922852651 +0100
> @@ -165,7 +165,6 @@ static void emit_single_push_insn (machi
>  #endif
>  static void do_tablejump (rtx, machine_mode, rtx, rtx, rtx, int);
>  static rtx const_vector_from_tree (tree);
> -static void write_complex_part (rtx, rtx, bool);
>  
>  /* This macro is used to determine whether move_by_pieces should be called
>     to perform a structure copy.  */
> @@ -3018,7 +3017,7 @@ set_storage_via_setmem (rtx object, rtx
>  /* Write to one of the components of the complex value CPLX.  Write VAL to
>     the real part if IMAG_P is false, and the imaginary part if its true.  */
>  
> -static void
> +void
>  write_complex_part (rtx cplx, rtx val, bool imag_p)
>  {
>    machine_mode cmode;
> --- gcc/expr.h.jj	2014-10-30 14:42:23.000000000 +0100
> +++ gcc/expr.h	2014-10-30 18:01:18.409633404 +0100
> @@ -340,6 +340,7 @@ extern rtx_insn *emit_move_insn_1 (rtx,
>  
>  extern rtx_insn *emit_move_complex_push (machine_mode, rtx, rtx);
>  extern rtx_insn *emit_move_complex_parts (rtx, rtx);
> +extern void write_complex_part (rtx, rtx, bool);
>  extern rtx emit_move_resolve_push (machine_mode, rtx);
>  
>  /* Push a block of length SIZE (perhaps variable)
> --- gcc/function.c.jj	2014-10-30 14:42:28.000000000 +0100
> +++ gcc/function.c	2014-10-30 16:54:05.219777275 +0100
> @@ -2017,9 +2017,14 @@ aggregate_value_p (const_tree exp, const
>        case CALL_EXPR:
>  	{
>  	  tree fndecl = get_callee_fndecl (fntype);
> -	  fntype = (fndecl
> -		    ? TREE_TYPE (fndecl)
> -		    : TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype))));
> +	  if (fndecl)
> +	    fntype = TREE_TYPE (fndecl);
> +	  else if (CALL_EXPR_FN (fntype))
> +	    fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype)));
> +	  else
> +	    /* For internal functions, assume nothing needs to be
> +	       returned in memory.  */
> +	    return 0;
>  	}
>  	break;
>        case FUNCTION_DECL:
> --- gcc/gimple-fold.c.jj	2014-10-29 09:49:56.000000000 +0100
> +++ gcc/gimple-fold.c	2014-11-10 13:19:37.487851440 +0100
> @@ -2604,6 +2604,47 @@ gimple_fold_builtin (gimple_stmt_iterato
>    return false;
>  }
>  
> +/* Return true if ARG0 CODE ARG1 in infinite signed precision operation
> +   doesn't fit into TYPE.  The test for overflow should be regardless of
> +   -fwrapv, and even for unsigned types.  */
> +
> +bool
> +arith_overflowed_p (enum tree_code code, const_tree type,
> +		    const_tree arg0, const_tree arg1)
> +{
> +  typedef FIXED_WIDE_INT (WIDE_INT_MAX_PRECISION * 2) widest2_int;
> +  typedef generic_wide_int <wi::extended_tree <WIDE_INT_MAX_PRECISION * 2> >
> +    widest2_int_cst;
> +  widest2_int warg0 = widest2_int_cst (arg0);
> +  widest2_int warg1 = widest2_int_cst (arg1);
> +  widest2_int wres;
> +  switch (code)
> +    {
> +    case PLUS_EXPR: wres = wi::add (warg0, warg1); break;
> +    case MINUS_EXPR: wres = wi::sub (warg0, warg1); break;
> +    case MULT_EXPR: wres = wi::mul (warg0, warg1); break;
> +    default: gcc_unreachable ();
> +    }
> +  signop sign = TYPE_SIGN (type);
> +  if (sign == UNSIGNED && wi::neg_p (wres))
> +    return true;
> +  return wi::min_precision (wres, sign) > TYPE_PRECISION (type);
> +}
> +
> +/* Helper for {ADD,SUB,MUL}_OVERFLOW folding.  Find in *TP if
> +   there are any uses of data (SSA_NAME) other than REALPART_EXPR
> +   referencing it.  */
> +
> +static tree
> +find_non_realpart_uses (tree *tp, int *walk_subtrees, void *data)
> +{
> +  if (TYPE_P (*tp) || TREE_CODE (*tp) == REALPART_EXPR)
> +    *walk_subtrees = 0;
> +  if (*tp == (tree) data)
> +    return *tp;
> +  return NULL_TREE;
> +}
> +
>  /* Attempt to fold a call statement referenced by the statement iterator GSI.
>     The statement may be replaced by another statement, e.g., if the call
>     simplifies to a constant value. Return true if any changes were made.
> @@ -2732,6 +2773,8 @@ gimple_fold_call (gimple_stmt_iterator *
>      {
>        enum tree_code subcode = ERROR_MARK;
>        tree result = NULL_TREE;
> +      bool cplx_result = false;
> +      tree overflow = NULL_TREE;
>        switch (gimple_call_internal_fn (stmt))
>  	{
>  	case IFN_BUILTIN_EXPECT:
> @@ -2762,6 +2805,18 @@ gimple_fold_call (gimple_stmt_iterator *
>  	case IFN_UBSAN_CHECK_MUL:
>  	  subcode = MULT_EXPR;
>  	  break;
> +	case IFN_ADD_OVERFLOW:
> +	  subcode = PLUS_EXPR;
> +	  cplx_result = true;
> +	  break;
> +	case IFN_SUB_OVERFLOW:
> +	  subcode = MINUS_EXPR;
> +	  cplx_result = true;
> +	  break;
> +	case IFN_MUL_OVERFLOW:
> +	  subcode = MULT_EXPR;
> +	  cplx_result = true;
> +	  break;
>  	default:
>  	  break;
>  	}
> @@ -2769,30 +2824,149 @@ gimple_fold_call (gimple_stmt_iterator *
>  	{
>  	  tree arg0 = gimple_call_arg (stmt, 0);
>  	  tree arg1 = gimple_call_arg (stmt, 1);
> +	  tree type = TREE_TYPE (arg0);
> +	  if (cplx_result)
> +	    {
> +	      tree lhs = gimple_call_lhs (stmt);
> +	      if (lhs == NULL_TREE)
> +		type = NULL_TREE;
> +	      else
> +		type = TREE_TYPE (TREE_TYPE (lhs));
> +	    }
> +	  if (type == NULL_TREE)
> +	    ;
>  	  /* x = y + 0; x = y - 0; x = y * 0; */
> -	  if (integer_zerop (arg1))
> -	    result = subcode == MULT_EXPR
> -		     ? build_zero_cst (TREE_TYPE (arg0))
> -		     : arg0;
> +	  else if (integer_zerop (arg1))
> +	    result = subcode == MULT_EXPR ? integer_zero_node : arg0;
>  	  /* x = 0 + y; x = 0 * y; */
>  	  else if (subcode != MINUS_EXPR && integer_zerop (arg0))
> -	    result = subcode == MULT_EXPR
> -		     ? build_zero_cst (TREE_TYPE (arg0))
> -		     : arg1;
> +	    result = subcode == MULT_EXPR ? integer_zero_node : arg1;
>  	  /* x = y - y; */
>  	  else if (subcode == MINUS_EXPR && operand_equal_p (arg0, arg1, 0))
> -	    result = build_zero_cst (TREE_TYPE (arg0));
> +	    result = integer_zero_node;
>  	  /* x = y * 1; x = 1 * y; */
> -	  else if (subcode == MULT_EXPR)
> +	  else if (subcode == MULT_EXPR && integer_onep (arg1))
> +	    result = arg0;
> +	  else if (subcode == MULT_EXPR && integer_onep (arg0))
> +	    result = arg1;
> +	  else if (TREE_CODE (arg0) == INTEGER_CST
> +		   && TREE_CODE (arg1) == INTEGER_CST)
> +	    {
> +	      if (cplx_result)
> +		result = int_const_binop (subcode, fold_convert (type, arg0),
> +					  fold_convert (type, arg1));
> +	      else
> +		result = int_const_binop (subcode, arg0, arg1);
> +	      if (result && arith_overflowed_p (subcode, type, arg0, arg1))
> +		{
> +		  if (cplx_result)
> +		    overflow = build_one_cst (type);
> +		  else
> +		    result = NULL_TREE;
> +		}
> +	    }
> +	  if (result)
> +	    {
> +	      if (result == integer_zero_node)
> +		result = build_zero_cst (type);
> +	      else if (cplx_result && TREE_TYPE (result) != type)
> +		{
> +		  if (TREE_CODE (result) == INTEGER_CST)
> +		    {
> +		      if (arith_overflowed_p (PLUS_EXPR, type, result,
> +					      integer_zero_node))
> +			overflow = build_one_cst (type);
> +		    }
> +		  else if ((!TYPE_UNSIGNED (TREE_TYPE (result))
> +			    && TYPE_UNSIGNED (type))
> +			   || (TYPE_PRECISION (type)
> +			       < (TYPE_PRECISION (TREE_TYPE (result))
> +				  + (TYPE_UNSIGNED (TREE_TYPE (result))
> +				     && !TYPE_UNSIGNED (type)))))
> +		    result = NULL_TREE;
> +		  if (result)
> +		    result = fold_convert (type, result);
> +		}
> +	    }
> +
> +	  /* If the IMAGPART_EXPR of the result is never used, but
> +	     REALPART_EXPR is, optimize the {ADD,SUB,MUL}_OVERFLOW
> +	     builtins into plain unsigned {PLUS,MINUS,MULT}_EXPR,
> +	     and if needed reset debug uses.  */
> +	  if (result == NULL_TREE && cplx_result
> +	      && gimple_in_ssa_p (cfun) && type)
>  	    {
> -	      if (integer_onep (arg1))
> -		result = arg0;
> -	      else if (integer_onep (arg0))
> -		result = arg1;
> +	      tree lhs = gimple_call_lhs (stmt);
> +	      imm_use_iterator imm_iter;
> +	      use_operand_p use_p;
> +	      bool has_debug_uses = false;
> +	      bool has_realpart_uses = false;
> +	      bool has_other_uses = false;
> +	      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
> +		{
> +		  gimple use_stmt = USE_STMT (use_p);
> +		  if (is_gimple_debug (use_stmt))
> +		    has_debug_uses = true;
> +		  else if (is_gimple_assign (use_stmt)
> +			   && (gimple_assign_rhs_code (use_stmt)
> +			       == REALPART_EXPR)
> +			   && (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0)
> +			       == lhs))
> +		    has_realpart_uses = true;
> +		  else
> +		    {
> +		      has_other_uses = true;
> +		      break;
> +		    }
> +		}
> +	      if (has_realpart_uses && !has_other_uses)
> +		{
> +		  location_t loc = gimple_location (stmt);
> +		  tree utype = type;
> +		  if (!TYPE_UNSIGNED (type))
> +		    utype
> +		      = build_nonstandard_integer_type (TYPE_PRECISION (type),
> +							1);
> +		  result
> +		    = fold_build2_loc (loc, subcode, utype,
> +				       fold_convert_loc (loc, utype, arg0),
> +				       fold_convert_loc (loc, utype, arg1));
> +		  result = fold_convert_loc (loc, type, result);
> +		  if (has_debug_uses)
> +		    {
> +		      gimple use_stmt;
> +		      FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, lhs)
> +			{
> +			  if (!gimple_debug_bind_p (use_stmt))
> +			    continue;
> +			  tree v = gimple_debug_bind_get_value (use_stmt);
> +			  if (walk_tree (&v, find_non_realpart_uses,
> +					 lhs, NULL))
> +			    {
> +			      gimple_debug_bind_reset_value (use_stmt);
> +			      update_stmt (use_stmt);
> +			    }
> +			}
> +		    }
> +		}
>  	    }
>  	}
>        if (result)
>  	{
> +	  if (TREE_CODE (result) == INTEGER_CST && TREE_OVERFLOW (result))
> +	    result = drop_tree_overflow (result);
> +	  if (cplx_result)
> +	    {
> +	      if (overflow == NULL_TREE)
> +		overflow = build_zero_cst (TREE_TYPE (result));
> +	      tree ctype = build_complex_type (TREE_TYPE (result));
> +	      if (TREE_CODE (result) == INTEGER_CST
> +		  && TREE_CODE (overflow) == INTEGER_CST)
> +		result = build_complex (ctype, result, overflow);
> +	      else
> +		result = build2_loc (gimple_location (stmt), COMPLEX_EXPR,
> +				     ctype, result, overflow);
> +	    }
>  	  if (!update_call_from_tree (gsi, result))
>  	    gimplify_and_update_call_from_tree (gsi, result);
>  	  changed = true;
> --- gcc/gimple-fold.h.jj	2014-10-29 09:49:56.000000000 +0100
> +++ gcc/gimple-fold.h	2014-11-05 16:41:09.883123348 +0100
> @@ -32,6 +32,8 @@ extern tree maybe_fold_and_comparisons (
>  					enum tree_code, tree, tree);
>  extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
>  				       enum tree_code, tree, tree);
> +extern bool arith_overflowed_p (enum tree_code, const_tree, const_tree,
> +				const_tree);
>  extern tree no_follow_ssa_edges (tree);
>  extern tree follow_single_use_edges (tree);
>  extern tree gimple_fold_stmt_to_constant_1 (gimple, tree (*) (tree));
> --- gcc/gimplify.c.jj	2014-10-29 09:49:56.000000000 +0100
> +++ gcc/gimplify.c	2014-10-30 17:19:53.849074948 +0100
> @@ -2277,6 +2277,9 @@ gimplify_call_expr (tree *expr_p, gimple
>    /* Gimplify internal functions created in the FEs.  */
>    if (CALL_EXPR_FN (*expr_p) == NULL_TREE)
>      {
> +      if (want_value)
> +	return GS_ALL_DONE;
> +
>        nargs = call_expr_nargs (*expr_p);
>        enum internal_fn ifn = CALL_EXPR_IFN (*expr_p);
>        auto_vec<tree> vargs (nargs);
> @@ -4631,22 +4634,41 @@ gimplify_modify_expr (tree *expr_p, gimp
>      {
>        /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
>  	 instead of a GIMPLE_ASSIGN.  */
> -      tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
> -      CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
> -      STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
> -      tree fndecl = get_callee_fndecl (*from_p);
> -      if (fndecl
> -	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
> -	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
> -	  && call_expr_nargs (*from_p) == 3)
> -	assign = gimple_build_call_internal (IFN_BUILTIN_EXPECT, 3,
> -					     CALL_EXPR_ARG (*from_p, 0),
> -					     CALL_EXPR_ARG (*from_p, 1),
> -					     CALL_EXPR_ARG (*from_p, 2));
> +      if (CALL_EXPR_FN (*from_p) == NULL_TREE)
> +	{
> +	  /* Gimplify internal functions created in the FEs.  */
> +	  int nargs = call_expr_nargs (*from_p), i;
> +	  enum internal_fn ifn = CALL_EXPR_IFN (*from_p);
> +	  auto_vec<tree> vargs (nargs);
> +
> +	  for (i = 0; i < nargs; i++)
> +	    {
> +	      gimplify_arg (&CALL_EXPR_ARG (*from_p, i), pre_p,
> +			    EXPR_LOCATION (*from_p));
> +	      vargs.quick_push (CALL_EXPR_ARG (*from_p, i));
> +	    }
> +	  assign = gimple_build_call_internal_vec (ifn, vargs);
> +	  gimple_set_location (assign, EXPR_LOCATION (*expr_p));
> +	}
>        else
>  	{
> -	  assign = gimple_build_call_from_tree (*from_p);
> -	  gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
> +	  tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
> +	  CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
> +	  STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
> +	  tree fndecl = get_callee_fndecl (*from_p);
> +	  if (fndecl
> +	      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
> +	      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
> +	      && call_expr_nargs (*from_p) == 3)
> +	    assign = gimple_build_call_internal (IFN_BUILTIN_EXPECT, 3,
> +						 CALL_EXPR_ARG (*from_p, 0),
> +						 CALL_EXPR_ARG (*from_p, 1),
> +						 CALL_EXPR_ARG (*from_p, 2));
> +	  else
> +	    {
> +	      assign = gimple_build_call_from_tree (*from_p);
> +	      gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
> +	    }
>  	}
>        notice_special_calls (assign);
>        if (!gimple_call_noreturn_p (assign))
> --- gcc/internal-fn.c.jj	2014-10-30 14:42:22.000000000 +0100
> +++ gcc/internal-fn.c	2014-11-10 17:59:49.440129794 +0100
> @@ -207,32 +207,494 @@ expand_ASAN_CHECK (gimple stmt ATTRIBUTE
>    gcc_unreachable ();
>  }
>  
> +/* Helper function for expand_addsub_overflow.  Return 1
> +   if ARG interpreted as signed in its precision is known to be always
> +   positive or 2 if ARG is known to be always negative, or 3 if ARG may
> +   be positive or negative.  */
> +
> +static int
> +get_range_pos_neg (tree arg)
> +{
> +  if (arg == error_mark_node)
> +    return 3;
> +
> +  int prec = TYPE_PRECISION (TREE_TYPE (arg));
> +  int cnt = 0;
> +  if (TREE_CODE (arg) == INTEGER_CST)
> +    {
> +      wide_int w = wi::sext (arg, prec);
> +      if (wi::neg_p (w))
> +	return 2;
> +      else
> +	return 1;
> +    }
> +  while (CONVERT_EXPR_P (arg)
> +	 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
> +	 && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
> +    {
> +      arg = TREE_OPERAND (arg, 0);
> +      /* Narrower value zero extended into wider type
> +	 will always result in positive values.  */
> +      if (TYPE_UNSIGNED (TREE_TYPE (arg))
> +	  && TYPE_PRECISION (TREE_TYPE (arg)) < prec)
> +	return 1;
> +      prec = TYPE_PRECISION (TREE_TYPE (arg));
> +      if (++cnt > 30)
> +	return 3;
> +    }
> +
> +  if (TREE_CODE (arg) != SSA_NAME)
> +    return 3;
> +  wide_int arg_min, arg_max;
> +  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
> +    {
> +      gimple g = SSA_NAME_DEF_STMT (arg);
> +      if (is_gimple_assign (g)
> +	  && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
> +	{
> +	  tree t = gimple_assign_rhs1 (g);
> +	  if (INTEGRAL_TYPE_P (TREE_TYPE (t))
> +	      && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
> +	    {
> +	      if (TYPE_UNSIGNED (TREE_TYPE (t))
> +		  && TYPE_PRECISION (TREE_TYPE (t)) < prec)
> +		return 1;
> +	      prec = TYPE_PRECISION (TREE_TYPE (t));
> +	      arg = t;
> +	      if (++cnt > 30)
> +		return 3;
> +	      continue;
> +	    }
> +	}
> +      return 3;
> +    }
> +  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
> +    {
> +      /* For unsigned values, the "positive" range comes
> +	 below the "negative" range.  */
> +      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
> +	return 1;
> +      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
> +	return 2;
> +    }
> +  else
> +    {
> +      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
> +	return 1;
> +      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
> +	return 2;
> +    }
> +  return 3;
> +}
> +
> +/* Return minimum precision needed to represent all values
> +   of ARG in SIGNed integral type.  */
> +
> +static int
> +get_min_precision (tree arg, signop sign)
> +{
> +  int prec = TYPE_PRECISION (TREE_TYPE (arg));
> +  int cnt = 0;
> +  signop orig_sign = sign;
> +  if (TREE_CODE (arg) == INTEGER_CST)
> +    {
> +      int p;
> +      if (TYPE_SIGN (TREE_TYPE (arg)) != sign)
> +	{
> +	  widest_int w = wi::to_widest (arg);
> +	  w = wi::ext (w, prec, sign);
> +	  p = wi::min_precision (w, sign);
> +	}
> +      else
> +	p = wi::min_precision (arg, sign);
> +      return MIN (p, prec);
> +    }
> +  while (CONVERT_EXPR_P (arg)
> +	 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
> +	 && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
> +    {
> +      arg = TREE_OPERAND (arg, 0);
> +      if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
> +	{
> +	  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
> +	    sign = UNSIGNED;
> +	  else if (sign == UNSIGNED && get_range_pos_neg (arg) != 1)
> +	    return prec + (orig_sign != sign);
> +	  prec = TYPE_PRECISION (TREE_TYPE (arg));
> +	}
> +      if (++cnt > 30)
> +	return prec + (orig_sign != sign);
> +    }
> +  if (TREE_CODE (arg) != SSA_NAME)
> +    return prec + (orig_sign != sign);
> +  wide_int arg_min, arg_max;
> +  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
> +    {
> +      gimple g = SSA_NAME_DEF_STMT (arg);
> +      if (is_gimple_assign (g)
> +	  && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
> +	{
> +	  tree t = gimple_assign_rhs1 (g);
> +	  if (INTEGRAL_TYPE_P (TREE_TYPE (t))
> +	      && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
> +	    {
> +	      arg = t;
> +	      if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
> +		{
> +		  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
> +		    sign = UNSIGNED;
> +		  else if (sign == UNSIGNED && get_range_pos_neg (arg) != 1)
> +		    return prec + (orig_sign != sign);
> +		  prec = TYPE_PRECISION (TREE_TYPE (arg));
> +		}
> +	      if (++cnt > 30)
> +		return prec + (orig_sign != sign);
> +	      continue;
> +	    }
> +	}
> +      return prec + (orig_sign != sign);
> +    }
> +  if (sign == TYPE_SIGN (TREE_TYPE (arg)))
> +    {
> +      int p1 = wi::min_precision (arg_min, sign);
> +      int p2 = wi::min_precision (arg_max, sign);
> +      p1 = MAX (p1, p2);
> +      prec = MIN (prec, p1);
> +    }
> +  else if (sign == UNSIGNED && !wi::neg_p (arg_min, SIGNED))
> +    {
> +      int p = wi::min_precision (arg_max, SIGNED);
> +      prec = MIN (prec, p);
> +    }
> +  return prec + (orig_sign != sign);
> +}
> +
> +/* Helper for expand_*_overflow.  Store RES into the __real__ part
> +   of TARGET.  If RES has larger MODE than __real__ part of TARGET,
> +   set the __imag__ part to 1 if RES doesn't fit into it.  */
> +
> +static void
> +expand_arith_overflow_result_store (tree lhs, rtx target,
> +				    machine_mode mode, rtx res)
> +{
> +  machine_mode tgtmode = GET_MODE_INNER (GET_MODE (target));
> +  rtx lres = res;
> +  if (tgtmode != mode)
> +    {
> +      rtx_code_label *done_label = gen_label_rtx ();
> +      int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
> +      lres = convert_modes (tgtmode, mode, res, uns);
> +      gcc_assert (GET_MODE_PRECISION (tgtmode) < GET_MODE_PRECISION (mode));
> +      emit_cmp_and_jump_insns (res, convert_modes (mode, tgtmode, lres, uns),
> +			       EQ, NULL_RTX, mode, false, done_label,
> +			       PROB_VERY_LIKELY);
> +      write_complex_part (target, const1_rtx, true);
> +      emit_label (done_label);
> +    }
> +  write_complex_part (target, lres, false);
> +}
> +
>  /* 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)
> +static void
> +expand_addsub_overflow (location_t loc, tree_code code, tree lhs,
> +			tree arg0, tree arg1, bool unsr_p, bool uns0_p,
> +			bool uns1_p, bool is_ubsan)
>  {
> -  rtx res, op0, op1;
> -  tree lhs, fn, arg0, arg1;
> -  rtx_code_label *done_label, *do_error;
> -  rtx 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 ();
> +  rtx res, target = NULL_RTX;
> +  tree fn;
> +  rtx_code_label *done_label = gen_label_rtx ();
> +  rtx_code_label *do_error = gen_label_rtx ();
>    do_pending_stack_adjust ();
> -  op0 = expand_normal (arg0);
> -  op1 = expand_normal (arg1);
> -
> +  rtx op0 = expand_normal (arg0);
> +  rtx op1 = expand_normal (arg1);
>    machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
> +  int prec = GET_MODE_PRECISION (mode);
> +  rtx sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
> +  bool do_xor = false;
> +
> +  if (is_ubsan)
> +    gcc_assert (!unsr_p && !uns0_p && !uns1_p);
> +
>    if (lhs)
> -    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +    {
> +      target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +      if (!is_ubsan)
> +	write_complex_part (target, const0_rtx, true);
> +    }
> +
> +  /* We assume both operands and result have the same precision
> +     here (GET_MODE_BITSIZE (mode)), S stands for signed type
> +     with that precision, U for unsigned type with that precision,
> +     sgn for unsigned most significant bit in that precision.
> +     s1 is signed first operand, u1 is unsigned first operand,
> +     s2 is signed second operand, u2 is unsigned second operand,
> +     sr is signed result, ur is unsigned result and the following
> +     rules say how to compute result (which is always result of
> +     the operands as if both were unsigned, cast to the right
> +     signedness) and how to compute whether operation overflowed.
> +
> +     s1 + s2 -> sr
> +	res = (S) ((U) s1 + (U) s2)
> +	ovf = s2 < 0 ? res > s1 : res < s1 (or jump on overflow)
> +     s1 - s2 -> sr
> +	res = (S) ((U) s1 - (U) s2)
> +	ovf = s2 < 0 ? res < s1 : res > s2 (or jump on overflow)
> +     u1 + u2 -> ur
> +	res = u1 + u2
> +	ovf = res < u1 (or jump on carry, but RTL opts will handle it)
> +     u1 - u2 -> ur
> +	res = u1 - u2
> +	ovf = res > u1 (or jump on carry, but RTL opts will handle it)
> +     s1 + u2 -> sr
> +	res = (S) ((U) s1 + u2)
> +	ovf = ((U) res ^ sgn) < u2
> +     s1 + u2 -> ur
> +	t1 = (S) (u2 ^ sgn)
> +	t2 = s1 + t1
> +	res = (U) t2 ^ sgn
> +	ovf = t1 < 0 ? t2 > s1 : t2 < s1 (or jump on overflow)
> +     s1 - u2 -> sr
> +	res = (S) ((U) s1 - u2)
> +	ovf = u2 > ((U) s1 ^ sgn)
> +     s1 - u2 -> ur
> +	res = (U) s1 - u2
> +	ovf = s1 < 0 || u2 > (U) s1
> +     u1 - s2 -> sr
> +	res = u1 - (U) s2
> + 	ovf = u1 >= ((U) s2 ^ sgn)
> +     u1 - s2 -> ur
> +	t1 = u1 ^ sgn
> +	t2 = t1 - (U) s2
> +	res = t2 ^ sgn
> +	ovf = s2 < 0 ? (S) t2 < (S) t1 : (S) t2 > (S) t1 (or jump on overflow)
> +     s1 + s2 -> ur
> +	res = (U) s1 + (U) s2
> +	ovf = s2 < 0 ? (s1 | (S) res) < 0) : (s1 & (S) res) < 0)
> +     u1 + u2 -> sr
> +	res = (S) (u1 + u2)
> +	ovf = (U) res < u2 || res < 0
> +     u1 - u2 -> sr
> +	res = (S) (u1 - u2)
> +	ovf = u1 >= u2 ? res < 0 : res >= 0
> +     s1 - s2 -> ur
> +	res = (U) s1 - (U) s2
> +	ovf = s2 >= 0 ? ((s1 | (S) res) < 0) : ((s1 & (S) res) < 0)  */
>  
> -  enum insn_code icode
> -    = optab_handler (code == PLUS_EXPR ? addv4_optab : subv4_optab, mode);
> +  if (code == PLUS_EXPR && uns0_p && !uns1_p)
> +    {
> +      /* PLUS_EXPR is commutative, if operand signedness differs,
> +	 canonicalize to the first operand being signed and second
> +	 unsigned to simplify following code.  */
> +      rtx tem = op1;
> +      op1 = op0;
> +      op0 = tem;
> +      tree t = arg1;
> +      arg1 = arg0;
> +      arg0 = t;
> +      uns0_p = 0;
> +      uns1_p = 1;
> +    }
> +
> +  /* u1 +- u2 -> ur  */
> +  if (uns0_p && uns1_p && unsr_p)
> +    {
> +      /* Compute the operation.  On RTL level, the addition is always
> +	 unsigned.  */
> +      res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
> +			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
> +      rtx tem = op0;
> +      /* For PLUS_EXPR, the operation is commutative, so we can pick
> +	 operand to compare against.  For prec <= BITS_PER_WORD, I think
> +	 preferring REG operand is better over CONST_INT, because
> +	 the CONST_INT might enlarge the instruction or CSE would need
> +	 to figure out we'd already loaded it into a register before.
> +	 For prec > BITS_PER_WORD, I think CONST_INT might be more beneficial,
> +	 as then the multi-word comparison can be perhaps simplified.  */
> +      if (code == PLUS_EXPR
> +	  && (prec <= BITS_PER_WORD
> +	      ? (CONST_SCALAR_INT_P (op0) && REG_P (op1))
> +	      : CONST_SCALAR_INT_P (op1)))
> +	tem = op1;
> +      emit_cmp_and_jump_insns (res, tem, code == PLUS_EXPR ? GEU : LEU,
> +			       NULL_RTX, mode, false, done_label,
> +			       PROB_VERY_LIKELY);
> +      goto do_error_label;
> +    }
> +
> +  /* s1 +- u2 -> sr  */
> +  if (!uns0_p && uns1_p && !unsr_p)
> +    {
> +      /* Compute the operation.  On RTL level, the addition is always
> +	 unsigned.  */
> +      res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
> +			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
> +      rtx tem = expand_binop (mode, add_optab,
> +			      code == PLUS_EXPR ? res : op0, sgn,
> +			      NULL_RTX, false, OPTAB_LIB_WIDEN);
> +      emit_cmp_and_jump_insns (tem, op1, GEU, NULL_RTX, mode, false,
> +			       done_label, PROB_VERY_LIKELY);
> +      goto do_error_label;
> +    }
> +
> +  /* s1 + u2 -> ur  */
> +  if (code == PLUS_EXPR && !uns0_p && uns1_p && unsr_p)
> +    {
> +      op1 = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
> +			  OPTAB_LIB_WIDEN);
> +      /* As we've changed op1, we have to avoid using the value range
> +	 for the original argument.  */
> +      arg1 = error_mark_node;
> +      do_xor = true;
> +      goto do_signed;
> +    }
> +
> +  /* u1 - s2 -> ur  */
> +  if (code == MINUS_EXPR && uns0_p && !uns1_p && unsr_p)
> +    {
> +      op0 = expand_binop (mode, add_optab, op0, sgn, NULL_RTX, false,
> +			  OPTAB_LIB_WIDEN);
> +      /* As we've changed op0, we have to avoid using the value range
> +	 for the original argument.  */
> +      arg0 = error_mark_node;
> +      do_xor = true;
> +      goto do_signed;
> +    }
> +
> +  /* s1 - u2 -> ur  */
> +  if (code == MINUS_EXPR && !uns0_p && uns1_p && unsr_p)
> +    {
> +      /* Compute the operation.  On RTL level, the addition is always
> +	 unsigned.  */
> +      res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
> +			  OPTAB_LIB_WIDEN);
> +      int pos_neg = get_range_pos_neg (arg0);
> +      if (pos_neg == 2)
> +	/* If ARG0 is known to be always negative, this is always overflow.  */
> +	emit_jump (do_error);
> +      else if (pos_neg == 3)
> +	/* If ARG0 is not known to be always positive, check at runtime.  */
> +	emit_cmp_and_jump_insns (op0, const0_rtx, LT, NULL_RTX, mode, false,
> +				 do_error, PROB_VERY_UNLIKELY);
> +      emit_cmp_and_jump_insns (op1, op0, LEU, NULL_RTX, mode, false,
> +			       done_label, PROB_VERY_LIKELY);
> +      goto do_error_label;
> +    }
> +
> +  /* u1 - s2 -> sr  */
> +  if (code == MINUS_EXPR && uns0_p && !uns1_p && !unsr_p)
> +    {
> +      /* Compute the operation.  On RTL level, the addition is always
> +	 unsigned.  */
> +      res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
> +			  OPTAB_LIB_WIDEN);
> +      rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
> +			      OPTAB_LIB_WIDEN);
> +      emit_cmp_and_jump_insns (op0, tem, LTU, NULL_RTX, mode, false,
> +			       done_label, PROB_VERY_LIKELY);
> +      goto do_error_label;
> +    }
> +
> +  /* u1 + u2 -> sr  */
> +  if (code == PLUS_EXPR && uns0_p && uns1_p && !unsr_p)
> +    {
> +      /* 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);
> +      emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode, false,
> +			       do_error, PROB_VERY_UNLIKELY);
> +      rtx tem = op1;
> +      /* The operation is commutative, so we can pick operand to compare
> +	 against.  For prec <= BITS_PER_WORD, I think preferring REG operand
> +	 is better over CONST_INT, because the CONST_INT might enlarge the
> +	 instruction or CSE would need to figure out we'd already loaded it
> +	 into a register before.  For prec > BITS_PER_WORD, I think CONST_INT
> +	 might be more beneficial, as then the multi-word comparison can be
> +	 perhaps simplified.  */
> +      if (prec <= BITS_PER_WORD
> +	  ? (CONST_SCALAR_INT_P (op1) && REG_P (op0))
> +	  : CONST_SCALAR_INT_P (op0))
> +	tem = op0;
> +      emit_cmp_and_jump_insns (res, tem, GEU, NULL_RTX, mode, false,
> +			       done_label, PROB_VERY_LIKELY);
> +      goto do_error_label;
> +    }
> +
> +  /* s1 +- s2 -> ur  */
> +  if (!uns0_p && !uns1_p && unsr_p)
> +    {
> +      /* Compute the operation.  On RTL level, the addition is always
> +	 unsigned.  */
> +      res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
> +			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
> +      int pos_neg = get_range_pos_neg (arg1);
> +      if (code == PLUS_EXPR)
> +	{
> +	  int pos_neg0 = get_range_pos_neg (arg0);
> +	  if (pos_neg0 != 3 && pos_neg == 3)
> +	    {
> +	      rtx tem = op1;
> +	      op1 = op0;
> +	      op0 = tem;
> +	      pos_neg = pos_neg0;
> +	    }
> +	}
> +      rtx tem;
> +      if (pos_neg != 3)
> +	{
> +	  tem = expand_binop (mode, ((pos_neg == 1) ^ (code == MINUS_EXPR))
> +				    ? and_optab : ior_optab,
> +			      op0, res, NULL_RTX, false, OPTAB_LIB_WIDEN);
> +	  emit_cmp_and_jump_insns (tem, const0_rtx, GE, NULL_RTX, mode, false,
> +				   done_label, PROB_VERY_LIKELY);
> +	}
> +      else
> +	{
> +	  rtx_code_label *do_ior_label = gen_label_rtx ();
> +	  emit_cmp_and_jump_insns (op1, const0_rtx,
> +				   code == MINUS_EXPR ? GE : LT, NULL_RTX,
> +				   mode, false, do_ior_label, PROB_EVEN);
> +	  tem = expand_binop (mode, and_optab, op0, res, NULL_RTX, false,
> +			      OPTAB_LIB_WIDEN);
> +	  emit_cmp_and_jump_insns (tem, const0_rtx, GE, NULL_RTX, mode, false,
> +				   done_label, PROB_VERY_LIKELY);
> +	  emit_jump (do_error);
> +	  emit_label (do_ior_label);
> +	  tem = expand_binop (mode, ior_optab, op0, res, NULL_RTX, false,
> +			      OPTAB_LIB_WIDEN);
> +	  emit_cmp_and_jump_insns (tem, const0_rtx, GE, NULL_RTX, mode, false,
> +				   done_label, PROB_VERY_LIKELY);
> +	}
> +      goto do_error_label;
> +    }
> +
> +  /* u1 - u2 -> sr  */
> +  if (code == MINUS_EXPR && uns0_p && uns1_p && !unsr_p)
> +    {
> +      /* Compute the operation.  On RTL level, the addition is always
> +	 unsigned.  */
> +      res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
> +			  OPTAB_LIB_WIDEN);
> +      rtx_code_label *op0_geu_op1 = gen_label_rtx ();
> +      emit_cmp_and_jump_insns (op0, op1, GEU, NULL_RTX, mode, false,
> +			       op0_geu_op1, PROB_EVEN);
> +      emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode, false,
> +			       done_label, PROB_VERY_LIKELY);
> +      emit_jump (do_error);
> +      emit_label (op0_geu_op1);
> +      emit_cmp_and_jump_insns (res, const0_rtx, GE, NULL_RTX, mode, false,
> +			       done_label, PROB_VERY_LIKELY);
> +      goto do_error_label;
> +    }
> +
> +  gcc_assert (!uns0_p && !uns1_p && !unsr_p);
> +
> +  /* s1 +- s2 -> sr  */
> + do_signed: ;
> +  enum insn_code icode;
> +  icode = optab_handler (code == PLUS_EXPR ? addv4_optab : subv4_optab, mode);
>    if (icode != CODE_FOR_nothing)
>      {
>        struct expand_operand ops[4];
> @@ -288,14 +750,7 @@ ubsan_expand_si_overflow_addsub_check (t
>  	;
>        else if (code == PLUS_EXPR && TREE_CODE (arg0) == SSA_NAME)
>  	{
> -	  wide_int arg0_min, arg0_max;
> -	  if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
> -	    {
> -	      if (!wi::neg_p (arg0_min, TYPE_SIGN (TREE_TYPE (arg0))))
> -		pos_neg = 1;
> -	      else if (wi::neg_p (arg0_max, TYPE_SIGN (TREE_TYPE (arg0))))
> -		pos_neg = 2;
> -	    }
> +	  pos_neg = get_range_pos_neg (arg0);
>  	  if (pos_neg != 3)
>  	    {
>  	      rtx tem = op0;
> @@ -304,16 +759,7 @@ ubsan_expand_si_overflow_addsub_check (t
>  	    }
>  	}
>        if (pos_neg == 3 && !CONST_INT_P (op1) && TREE_CODE (arg1) == SSA_NAME)
> -	{
> -	  wide_int arg1_min, arg1_max;
> -	  if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
> -	    {
> -	      if (!wi::neg_p (arg1_min, TYPE_SIGN (TREE_TYPE (arg1))))
> -		pos_neg = 1;
> -	      else if (wi::neg_p (arg1_max, TYPE_SIGN (TREE_TYPE (arg1))))
> -		pos_neg = 2;
> -	    }
> -	}
> +	pos_neg = get_range_pos_neg (arg1);
>  
>        /* If the op1 is negative, we have to use a different check.  */
>        if (pos_neg == 3)
> @@ -341,34 +787,49 @@ ubsan_expand_si_overflow_addsub_check (t
>  				 PROB_VERY_LIKELY);
>      }
>  
> + do_error_label:
>    emit_label (do_error);
> -  /* Expand the ubsan builtin call.  */
> -  push_temp_slots ();
> -  fn = ubsan_build_overflow_builtin (code, gimple_location (stmt),
> -				     TREE_TYPE (arg0), arg0, arg1);
> -  expand_normal (fn);
> -  pop_temp_slots ();
> -  do_pending_stack_adjust ();
> +  if (is_ubsan)
> +    {
> +      /* Expand the ubsan builtin call.  */
> +      push_temp_slots ();
> +      fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0),
> +					 arg0, arg1);
> +      expand_normal (fn);
> +      pop_temp_slots ();
> +      do_pending_stack_adjust ();
> +    }
> +  else if (lhs)
> +    write_complex_part (target, const1_rtx, true);
>  
>    /* We're done.  */
>    emit_label (done_label);
>  
>    if (lhs)
> -    emit_move_insn (target, res);
> +    {
> +      if (is_ubsan)
> +	emit_move_insn (target, res);
> +      else
> +	{
> +	  if (do_xor)
> +	    res = expand_binop (mode, add_optab, res, sgn, NULL_RTX, false,
> +				OPTAB_LIB_WIDEN);
> +
> +	  expand_arith_overflow_result_store (lhs, target, mode, res);
> +	}
> +    }
>  }
>  
>  /* Add negate overflow checking to the statement STMT.  */
>  
> -void
> -ubsan_expand_si_overflow_neg_check (gimple stmt)
> +static void
> +expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan)
>  {
>    rtx res, op1;
> -  tree lhs, fn, arg1;
> +  tree fn;
>    rtx_code_label *done_label, *do_error;
>    rtx target = NULL_RTX;
>  
> -  lhs = gimple_call_lhs (stmt);
> -  arg1 = gimple_call_arg (stmt, 1);
>    done_label = gen_label_rtx ();
>    do_error = gen_label_rtx ();
>  
> @@ -377,7 +838,11 @@ ubsan_expand_si_overflow_neg_check (gimp
>  
>    machine_mode mode = TYPE_MODE (TREE_TYPE (arg1));
>    if (lhs)
> -    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +    {
> +      target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +      if (!is_ubsan)
> +	write_complex_part (target, const0_rtx, true);
> +    }
>  
>    enum insn_code icode = optab_handler (negv3_optab, mode);
>    if (icode != CODE_FOR_nothing)
> @@ -419,34 +884,44 @@ ubsan_expand_si_overflow_neg_check (gimp
>      }
>  
>    emit_label (do_error);
> -  /* Expand the ubsan builtin call.  */
> -  push_temp_slots ();
> -  fn = ubsan_build_overflow_builtin (NEGATE_EXPR, gimple_location (stmt),
> -				     TREE_TYPE (arg1), arg1, NULL_TREE);
> -  expand_normal (fn);
> -  pop_temp_slots ();
> -  do_pending_stack_adjust ();
> +  if (is_ubsan)
> +    {
> +      /* Expand the ubsan builtin call.  */
> +      push_temp_slots ();
> +      fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1),
> +					 arg1, NULL_TREE);
> +      expand_normal (fn);
> +      pop_temp_slots ();
> +      do_pending_stack_adjust ();
> +    }
> +  else if (lhs)
> +    write_complex_part (target, const1_rtx, true);
>  
>    /* We're done.  */
>    emit_label (done_label);
>  
>    if (lhs)
> -    emit_move_insn (target, res);
> +    {
> +      if (is_ubsan)
> +	emit_move_insn (target, res);
> +      else
> +	expand_arith_overflow_result_store (lhs, target, mode, res);
> +    }
>  }
>  
>  /* Add mul overflow checking to the statement STMT.  */
>  
> -void
> -ubsan_expand_si_overflow_mul_check (gimple stmt)
> +static void
> +expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
> +		     bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan)
>  {
>    rtx res, op0, op1;
> -  tree lhs, fn, arg0, arg1;
> +  tree fn, type;
>    rtx_code_label *done_label, *do_error;
>    rtx target = NULL_RTX;
> +  signop sign;
> +  enum insn_code icode;
>  
> -  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 ();
>  
> @@ -455,10 +930,243 @@ ubsan_expand_si_overflow_mul_check (gimp
>    op1 = expand_normal (arg1);
>  
>    machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
> +  bool uns = unsr_p;
>    if (lhs)
> -    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +    {
> +      target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +      if (!is_ubsan)
> +	write_complex_part (target, const0_rtx, true);
> +    }
> +
> +  if (is_ubsan)
> +    gcc_assert (!unsr_p && !uns0_p && !uns1_p);
> +
> +  /* We assume both operands and result have the same precision
> +     here (GET_MODE_BITSIZE (mode)), S stands for signed type
> +     with that precision, U for unsigned type with that precision,
> +     sgn for unsigned most significant bit in that precision.
> +     s1 is signed first operand, u1 is unsigned first operand,
> +     s2 is signed second operand, u2 is unsigned second operand,
> +     sr is signed result, ur is unsigned result and the following
> +     rules say how to compute result (which is always result of
> +     the operands as if both were unsigned, cast to the right
> +     signedness) and how to compute whether operation overflowed.
> +     main_ovf (false) stands for jump on signed multiplication
> +     overflow or the main algorithm with uns == false.
> +     main_ovf (true) stands for jump on unsigned multiplication
> +     overflow or the main algorithm with uns == true.
> +
> +     s1 * s2 -> sr
> +	res = (S) ((U) s1 * (U) s2)
> +	ovf = main_ovf (false)
> +     u1 * u2 -> ur
> +	res = u1 * u2
> +	ovf = main_ovf (true)
> +     s1 * u2 -> ur
> +	res = (U) s1 * u2
> +	ovf = (s1 < 0 && u2) || main_ovf (true)
> +     u1 * u2 -> sr
> +	res = (S) (u1 * u2)
> +	ovf = res < 0 || main_ovf (true)
> +     s1 * u2 -> sr
> +	res = (S) ((U) s1 * u2)
> +	ovf = (S) u2 >= 0 ? main_ovf (false)
> +			  : (s1 != 0 && (s1 != -1 || u2 != (U) res))
> +     s1 * s2 -> ur
> +	t1 = (s1 & s2) < 0 ? (-(U) s1) : ((U) s1)
> +	t2 = (s1 & s2) < 0 ? (-(U) s2) : ((U) s2)
> +	res = t1 * t2
> +	ovf = (s1 ^ s2) < 0 ? (s1 && s2) : main_ovf (true)  */
> +
> +  if (uns0_p && !uns1_p)
> +    {
> +      /* Multiplication is commutative, if operand signedness differs,
> +	 canonicalize to the first operand being signed and second
> +	 unsigned to simplify following code.  */
> +      rtx tem = op1;
> +      op1 = op0;
> +      op0 = tem;
> +      tree t = arg1;
> +      arg1 = arg0;
> +      arg0 = t;
> +      uns0_p = 0;
> +      uns1_p = 1;
> +    }
> +
> +  int pos_neg0 = get_range_pos_neg (arg0);
> +  int pos_neg1 = get_range_pos_neg (arg1);
> +
> +  /* s1 * u2 -> ur  */
> +  if (!uns0_p && uns1_p && unsr_p)
> +    {
> +      switch (pos_neg0)
> +	{
> +	case 1:
> +	  /* If s1 is non-negative, just perform normal u1 * u2 -> ur.  */
> +	  goto do_main;
> +	case 2:
> +	  /* If s1 is negative, avoid the main code, just multiply and
> +	     signal overflow if op1 is not 0.  */
> +	  struct separate_ops ops;
> +	  ops.code = MULT_EXPR;
> +	  ops.type = TREE_TYPE (arg1);
> +	  ops.op0 = make_tree (ops.type, op0);
> +	  ops.op1 = make_tree (ops.type, op1);
> +	  ops.op2 = NULL_TREE;
> +	  ops.location = loc;
> +	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
> +	  emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, mode,
> +				   false, done_label, PROB_VERY_LIKELY);
> +	  goto do_error_label;
> +	case 3:
> +	  rtx_code_label *do_main_label;
> +	  do_main_label = gen_label_rtx ();
> +	  emit_cmp_and_jump_insns (op0, const0_rtx, GE, NULL_RTX, mode,
> +				   false, do_main_label, PROB_VERY_LIKELY);
> +	  emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, mode,
> +				   false, do_main_label, PROB_VERY_LIKELY);
> +	  write_complex_part (target, const1_rtx, true);
> +	  emit_label (do_main_label);
> +	  goto do_main;
> +	default:
> +	  gcc_unreachable ();
> +	}
> +    }
> +
> +  /* u1 * u2 -> sr  */
> +  if (uns0_p && uns1_p && !unsr_p)
> +    {
> +      uns = true;
> +      /* Rest of handling of this case after res is computed.  */
> +      goto do_main;
> +    }
> +
> +  /* s1 * u2 -> sr  */
> +  if (!uns0_p && uns1_p && !unsr_p)
> +    {
> +      switch (pos_neg1)
> +	{
> +	case 1:
> +	  goto do_main;
> +	case 2:
> +	  /* If (S) u2 is negative (i.e. u2 is larger than maximum of S,
> +	     avoid the main code, just multiply and signal overflow
> +	     unless 0 * u2 or -1 * ((U) Smin).  */
> +	  struct separate_ops ops;
> +	  ops.code = MULT_EXPR;
> +	  ops.type = TREE_TYPE (arg1);
> +	  ops.op0 = make_tree (ops.type, op0);
> +	  ops.op1 = make_tree (ops.type, op1);
> +	  ops.op2 = NULL_TREE;
> +	  ops.location = loc;
> +	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
> +	  emit_cmp_and_jump_insns (op0, const0_rtx, EQ, NULL_RTX, mode,
> +				   false, done_label, PROB_VERY_LIKELY);
> +	  emit_cmp_and_jump_insns (op0, constm1_rtx, NE, NULL_RTX, mode,
> +				   false, do_error, PROB_VERY_UNLIKELY);
> +	  int prec;
> +	  prec = GET_MODE_PRECISION (mode);
> +	  rtx sgn;
> +	  sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
> +	  emit_cmp_and_jump_insns (op1, sgn, EQ, NULL_RTX, mode,
> +				   false, done_label, PROB_VERY_LIKELY);
> +	  goto do_error_label;
> +	case 3:
> +	  /* Rest of handling of this case after res is computed.  */
> +	  goto do_main;
> +	default:
> +	  gcc_unreachable ();
> +	}
> +    }
> +
> +  /* s1 * s2 -> ur  */
> +  if (!uns0_p && !uns1_p && unsr_p)
> +    {
> +      rtx tem, tem2;
> +      switch (pos_neg0 | pos_neg1)
> +	{
> +	case 1: /* Both operands known to be non-negative.  */
> +	  goto do_main;
> +	case 2: /* Both operands known to be negative.  */
> +	  op0 = expand_unop (mode, neg_optab, op0, NULL_RTX, false);
> +	  op1 = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
> +	  /* Avoid looking at arg0/arg1 ranges, as we've changed
> +	     the arguments.  */
> +	  arg0 = error_mark_node;
> +	  arg1 = error_mark_node;
> +	  goto do_main;
> +	case 3:
> +	  if ((pos_neg0 ^ pos_neg1) == 3)
> +	    {
> +	      /* If one operand is known to be negative and the other
> +		 non-negative, this overflows always, unless the non-negative
> +		 one is 0.  Just do normal multiply and set overflow
> +		 unless one of the operands is 0.  */
> +	      struct separate_ops ops;
> +	      ops.code = MULT_EXPR;
> +	      ops.type
> +		= build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
> +						  1);
> +	      ops.op0 = make_tree (ops.type, op0);
> +	      ops.op1 = make_tree (ops.type, op1);
> +	      ops.op2 = NULL_TREE;
> +	      ops.location = loc;
> +	      res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
> +	      tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
> +				  OPTAB_LIB_WIDEN);
> +	      emit_cmp_and_jump_insns (tem, const0_rtx, EQ, NULL_RTX, mode,
> +				       false, done_label, PROB_VERY_LIKELY);
> +	      goto do_error_label;
> +	    }
> +	  /* The general case, do all the needed comparisons at runtime.  */
> +	  rtx_code_label *do_main_label, *after_negate_label;
> +	  rtx rop0, rop1;
> +	  rop0 = gen_reg_rtx (mode);
> +	  rop1 = gen_reg_rtx (mode);
> +	  emit_move_insn (rop0, op0);
> +	  emit_move_insn (rop1, op1);
> +	  op0 = rop0;
> +	  op1 = rop1;
> +	  do_main_label = gen_label_rtx ();
> +	  after_negate_label = gen_label_rtx ();
> +	  tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
> +			      OPTAB_LIB_WIDEN);
> +	  emit_cmp_and_jump_insns (tem, const0_rtx, GE, NULL_RTX, mode, false,
> +				   after_negate_label, PROB_VERY_LIKELY);
> +	  /* Both arguments negative here, negate them and continue with
> +	     normal unsigned overflow checking multiplication.  */
> +	  emit_move_insn (op0, expand_unop (mode, neg_optab, op0,
> +					    NULL_RTX, false));
> +	  emit_move_insn (op1, expand_unop (mode, neg_optab, op1,
> +					    NULL_RTX, false));
> +	  /* Avoid looking at arg0/arg1 ranges, as we might have changed
> +	     the arguments.  */
> +	  arg0 = error_mark_node;
> +	  arg1 = error_mark_node;
> +	  emit_jump (do_main_label);
> +	  emit_label (after_negate_label);
> +	  tem2 = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
> +			       OPTAB_LIB_WIDEN);
> +	  emit_cmp_and_jump_insns (tem2, const0_rtx, GE, NULL_RTX, mode, false,
> +				   do_main_label, PROB_VERY_LIKELY);
> +	  /* One argument is negative here, the other positive.  This
> +	     overflows always, unless one of the arguments is 0.  But
> +	     if e.g. s2 is 0, (U) s1 * 0 doesn't overflow, whatever s1
> +	     is, thus we can keep do_main code oring in overflow as is.  */
> +	  emit_cmp_and_jump_insns (tem, const0_rtx, EQ, NULL_RTX, mode, false,
> +				   do_main_label, PROB_VERY_LIKELY);
> +	  write_complex_part (target, const1_rtx, true);
> +	  emit_label (do_main_label);
> +	  goto do_main;
> +	default:
> +	  gcc_unreachable ();
> +	}
> +    }
>  
> -  enum insn_code icode = optab_handler (mulv4_optab, mode);
> + do_main:
> +  type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode), uns);
> +  sign = uns ? UNSIGNED : SIGNED;
> +  icode = optab_handler (uns ? umulv4_optab : mulv4_optab, mode);
>    if (icode != CODE_FOR_nothing)
>      {
>        struct expand_operand ops[4];
> @@ -489,59 +1197,69 @@ ubsan_expand_si_overflow_mul_check (gimp
>    if (icode == CODE_FOR_nothing)
>      {
>        struct separate_ops ops;
> -      machine_mode hmode
> -	= mode_for_size (GET_MODE_PRECISION (mode) / 2, MODE_INT, 1);
> -      ops.op0 = arg0;
> -      ops.op1 = arg1;
> +      int prec = GET_MODE_PRECISION (mode);
> +      machine_mode hmode = mode_for_size (prec / 2, MODE_INT, 1);
> +      ops.op0 = make_tree (type, op0);
> +      ops.op1 = make_tree (type, op1);
>        ops.op2 = NULL_TREE;
> -      ops.location = gimple_location (stmt);
> +      ops.location = loc;
>        if (GET_MODE_2XWIDER_MODE (mode) != VOIDmode
>  	  && targetm.scalar_mode_supported_p (GET_MODE_2XWIDER_MODE (mode)))
>  	{
>  	  machine_mode wmode = GET_MODE_2XWIDER_MODE (mode);
>  	  ops.code = WIDEN_MULT_EXPR;
>  	  ops.type
> -	    = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), 0);
> +	    = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
>  
>  	  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);
> +	  rtx hipart = expand_shift (RSHIFT_EXPR, wmode, res, prec,
> +				     NULL_RTX, uns);
>  	  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);
> +	  if (uns)
> +	    /* For the unsigned multiplication, there was overflow if
> +	       HIPART is non-zero.  */
> +	    emit_cmp_and_jump_insns (hipart, const0_rtx, EQ, NULL_RTX, mode,
> +				     false, done_label, PROB_VERY_LIKELY);
> +	  else
> +	    {
> +	      rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 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 if (hmode != BLKmode
> -	       && 2 * GET_MODE_PRECISION (hmode) == GET_MODE_PRECISION (mode))
> +      else if (hmode != BLKmode && 2 * GET_MODE_PRECISION (hmode) == prec)
>  	{
>  	  rtx_code_label *large_op0 = gen_label_rtx ();
>  	  rtx_code_label *small_op0_large_op1 = gen_label_rtx ();
>  	  rtx_code_label *one_small_one_large = gen_label_rtx ();
>  	  rtx_code_label *both_ops_large = gen_label_rtx ();
> -	  rtx_code_label *after_hipart_neg = gen_label_rtx ();
> -	  rtx_code_label *after_lopart_neg = gen_label_rtx ();
> +	  rtx_code_label *after_hipart_neg = uns ? NULL : gen_label_rtx ();
> +	  rtx_code_label *after_lopart_neg = uns ? NULL : gen_label_rtx ();
>  	  rtx_code_label *do_overflow = gen_label_rtx ();
> -	  rtx_code_label *hipart_different = gen_label_rtx ();
> +	  rtx_code_label *hipart_different = uns ? NULL : gen_label_rtx ();
>  
>  	  unsigned int hprec = GET_MODE_PRECISION (hmode);
>  	  rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
> -				      NULL_RTX, 0);
> +				      NULL_RTX, uns);
>  	  hipart0 = gen_lowpart (hmode, hipart0);
>  	  rtx lopart0 = gen_lowpart (hmode, op0);
> -	  rtx signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
> -				       NULL_RTX, 0);
> +	  rtx signbit0 = const0_rtx;
> +	  if (!uns)
> +	    signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
> +				     NULL_RTX, 0);
>  	  rtx hipart1 = expand_shift (RSHIFT_EXPR, mode, op1, hprec,
> -				      NULL_RTX, 0);
> +				      NULL_RTX, uns);
>  	  hipart1 = gen_lowpart (hmode, hipart1);
>  	  rtx lopart1 = gen_lowpart (hmode, op1);
> -	  rtx signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
> -				       NULL_RTX, 0);
> +	  rtx signbit1 = const0_rtx;
> +	  if (!uns)
> +	    signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
> +				     NULL_RTX, 0);
>  
>  	  res = gen_reg_rtx (mode);
>  
> @@ -559,40 +1277,29 @@ ubsan_expand_si_overflow_mul_check (gimp
>  	  int op0_sign = 1;
>  	  int op1_sign = 1;
>  
> -	  if (TREE_CODE (arg0) == SSA_NAME)
> -	    {
> -	      wide_int arg0_min, arg0_max;
> -	      if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
> -		{
> -		  unsigned int mprec0 = wi::min_precision (arg0_min, SIGNED);
> -		  unsigned int mprec1 = wi::min_precision (arg0_max, SIGNED);
> -		  if (mprec0 <= hprec && mprec1 <= hprec)
> -		    op0_small_p = true;
> -		  else if (mprec0 <= hprec + 1 && mprec1 <= hprec + 1)
> -		    op0_medium_p = true;
> -		  if (!wi::neg_p (arg0_min, TYPE_SIGN (TREE_TYPE (arg0))))
> -		    op0_sign = 0;
> -		  else if (wi::neg_p (arg0_max, TYPE_SIGN (TREE_TYPE (arg0))))
> -		    op0_sign = -1;
> -		}
> -	    }
> -	  if (TREE_CODE (arg1) == SSA_NAME)
> -	    {
> -	      wide_int arg1_min, arg1_max;
> -	      if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
> -		{
> -		  unsigned int mprec0 = wi::min_precision (arg1_min, SIGNED);
> -		  unsigned int mprec1 = wi::min_precision (arg1_max, SIGNED);
> -		  if (mprec0 <= hprec && mprec1 <= hprec)
> -		    op1_small_p = true;
> -		  else if (mprec0 <= hprec + 1 && mprec1 <= hprec + 1)
> -		    op1_medium_p = true;
> -		  if (!wi::neg_p (arg1_min, TYPE_SIGN (TREE_TYPE (arg1))))
> -		    op1_sign = 0;
> -		  else if (wi::neg_p (arg1_max, TYPE_SIGN (TREE_TYPE (arg1))))
> -		    op1_sign = -1;
> -		}
> -	    }
> +	  if (pos_neg0 == 1)
> +	    op0_sign = 0;
> +	  else if (pos_neg0 == 2)
> +	    op0_sign = -1;
> +	  if (pos_neg1 == 1)
> +	    op1_sign = 0;
> +	  else if (pos_neg1 == 2)
> +	    op1_sign = -1;
> +
> +	  unsigned int mprec0 = prec;
> +	  if (arg0 != error_mark_node)
> +	    mprec0 = get_min_precision (arg0, sign);
> +	  if (mprec0 <= hprec)
> +	    op0_small_p = true;
> +	  else if (!uns && mprec0 <= hprec + 1)
> +	    op0_medium_p = true;
> +	  unsigned int mprec1 = prec;
> +	  if (arg1 != error_mark_node)
> +	    mprec1 = get_min_precision (arg1, sign);
> +	  if (mprec1 <= hprec)
> +	    op1_small_p = true;
> +	  else if (!uns && mprec1 <= hprec + 1)
> +	    op1_medium_p = true;
>  
>  	  int smaller_sign = 1;
>  	  int larger_sign = 1;
> @@ -621,24 +1328,27 @@ ubsan_expand_si_overflow_mul_check (gimp
>  				     false, small_op0_large_op1,
>  				     PROB_UNLIKELY);
>  
> -	  /* If both op0 and op1 are sign extended from hmode to mode,
> -	     the multiplication will never overflow.  We can do just one
> -	     hmode x hmode => mode widening multiplication.  */
> +	  /* If both op0 and op1 are sign (!uns) or zero (uns) extended from
> +	     hmode to mode, the multiplication will never overflow.  We can
> +	     do just one hmode x hmode => mode widening multiplication.  */
> +	  rtx lopart0s = lopart0, lopart1s = lopart1;
>  	  if (GET_CODE (lopart0) == SUBREG)
>  	    {
> -	      SUBREG_PROMOTED_VAR_P (lopart0) = 1;
> -	      SUBREG_PROMOTED_SET (lopart0, 0);
> +	      lopart0s = shallow_copy_rtx (lopart0);
> +	      SUBREG_PROMOTED_VAR_P (lopart0s) = 1;
> +	      SUBREG_PROMOTED_SET (lopart0s, uns ? SRP_UNSIGNED : SRP_SIGNED);
>  	    }
>  	  if (GET_CODE (lopart1) == SUBREG)
>  	    {
> -	      SUBREG_PROMOTED_VAR_P (lopart1) = 1;
> -	      SUBREG_PROMOTED_SET (lopart1, 0);
> +	      lopart1s = shallow_copy_rtx (lopart1);
> +	      SUBREG_PROMOTED_VAR_P (lopart1s) = 1;
> +	      SUBREG_PROMOTED_SET (lopart1s, uns ? SRP_UNSIGNED : SRP_SIGNED);
>  	    }
> -	  tree halfstype = build_nonstandard_integer_type (hprec, 0);
> -	  ops.op0 = make_tree (halfstype, lopart0);
> -	  ops.op1 = make_tree (halfstype, lopart1);
> +	  tree halfstype = build_nonstandard_integer_type (hprec, uns);
> +	  ops.op0 = make_tree (halfstype, lopart0s);
> +	  ops.op1 = make_tree (halfstype, lopart1s);
>  	  ops.code = WIDEN_MULT_EXPR;
> -	  ops.type = TREE_TYPE (arg0);
> +	  ops.type = type;
>  	  rtx thisres
>  	    = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
>  	  emit_move_insn (res, thisres);
> @@ -646,9 +1356,9 @@ ubsan_expand_si_overflow_mul_check (gimp
>  
>  	  emit_label (small_op0_large_op1);
>  
> -	  /* If op0 is sign extended from hmode to mode, but op1 is not,
> -	     just swap the arguments and handle it as op1 sign extended,
> -	     op0 not.  */
> +	  /* If op0 is sign (!uns) or zero (uns) extended from hmode to mode,
> +	     but op1 is not, just swap the arguments and handle it as op1
> +	     sign/zero extended, op0 not.  */
>  	  rtx larger = gen_reg_rtx (mode);
>  	  rtx hipart = gen_reg_rtx (hmode);
>  	  rtx lopart = gen_reg_rtx (hmode);
> @@ -663,9 +1373,9 @@ ubsan_expand_si_overflow_mul_check (gimp
>  	    emit_cmp_and_jump_insns (signbit1, hipart1, NE, NULL_RTX, hmode,
>  				     false, both_ops_large, PROB_UNLIKELY);
>  
> -	  /* If op1 is sign extended from hmode to mode, but op0 is not,
> -	     prepare larger, hipart and lopart pseudos and handle it together
> -	     with small_op0_large_op1.  */
> +	  /* If op1 is sign (!uns) or zero (uns) extended from hmode to mode,
> +	     but op0 is not, prepare larger, hipart and lopart pseudos and
> +	     handle it together with small_op0_large_op1.  */
>  	  emit_move_insn (larger, op0);
>  	  emit_move_insn (hipart, hipart0);
>  	  emit_move_insn (lopart, lopart1);
> @@ -690,33 +1400,38 @@ ubsan_expand_si_overflow_mul_check (gimp
>  	  rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
>  	  emit_move_insn (loxhi, tem);
>  
> -	  /* if (hipart < 0) loxhi -= lopart << (bitsize / 2);  */
> -	  if (larger_sign == 0)
> -	    emit_jump (after_hipart_neg);
> -	  else if (larger_sign != -1)
> -	    emit_cmp_and_jump_insns (hipart, const0_rtx, GE, NULL_RTX, hmode,
> -				     false, after_hipart_neg, PROB_EVEN);
> -
> -	  tem = convert_modes (mode, hmode, lopart, 1);
> -	  tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
> -	  tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
> -				     1, OPTAB_DIRECT);
> -	  emit_move_insn (loxhi, tem);
> -
> -	  emit_label (after_hipart_neg);
> -
> -	  /* if (lopart < 0) loxhi -= larger;  */
> -	  if (smaller_sign == 0)
> -	    emit_jump (after_lopart_neg);
> -	  else if (smaller_sign != -1)
> -	    emit_cmp_and_jump_insns (lopart, const0_rtx, GE, NULL_RTX, hmode,
> -				     false, after_lopart_neg, PROB_EVEN);
> -
> -	  tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
> -				     1, OPTAB_DIRECT);
> -	  emit_move_insn (loxhi, tem);
> +	  if (!uns)
> +	    {
> +	      /* if (hipart < 0) loxhi -= lopart << (bitsize / 2);  */
> +	      if (larger_sign == 0)
> +		emit_jump (after_hipart_neg);
> +	      else if (larger_sign != -1)
> +		emit_cmp_and_jump_insns (hipart, const0_rtx, GE, NULL_RTX,
> +					 hmode, false, after_hipart_neg,
> +					 PROB_EVEN);
> +
> +	      tem = convert_modes (mode, hmode, lopart, 1);
> +	      tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
> +	      tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
> +					 1, OPTAB_DIRECT);
> +	      emit_move_insn (loxhi, tem);
> +
> +	      emit_label (after_hipart_neg);
> +
> +	      /* if (lopart < 0) loxhi -= larger;  */
> +	      if (smaller_sign == 0)
> +		emit_jump (after_lopart_neg);
> +	      else if (smaller_sign != -1)
> +		emit_cmp_and_jump_insns (lopart, const0_rtx, GE, NULL_RTX,
> +					 hmode, false, after_lopart_neg,
> +					 PROB_EVEN);
> +
> +	      tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
> +					 1, OPTAB_DIRECT);
> +	      emit_move_insn (loxhi, tem);
>  
> -	  emit_label (after_lopart_neg);
> +	      emit_label (after_lopart_neg);
> +	    }
>  
>  	  /* loxhi += (uns) lo0xlo1 >> (bitsize / 2);  */
>  	  tem = expand_shift (RSHIFT_EXPR, mode, lo0xlo1, hprec, NULL_RTX, 1);
> @@ -725,13 +1440,16 @@ ubsan_expand_si_overflow_mul_check (gimp
>  	  emit_move_insn (loxhi, tem);
>  
>  	  /* if (loxhi >> (bitsize / 2)
> -		 == (hmode) loxhi >> (bitsize / 2 - 1))  */
> +		 == (hmode) loxhi >> (bitsize / 2 - 1))  (if !uns)
> +	     if (loxhi >> (bitsize / 2) == 0		 (if uns).  */
>  	  rtx hipartloxhi = expand_shift (RSHIFT_EXPR, mode, loxhi, hprec,
>  					  NULL_RTX, 0);
>  	  hipartloxhi = gen_lowpart (hmode, hipartloxhi);
> -	  rtx lopartloxhi = gen_lowpart (hmode, loxhi);
> -	  rtx signbitloxhi = expand_shift (RSHIFT_EXPR, hmode, lopartloxhi,
> -					   hprec - 1, NULL_RTX, 0);
> +	  rtx signbitloxhi = const0_rtx;
> +	  if (!uns)
> +	    signbitloxhi = expand_shift (RSHIFT_EXPR, hmode,
> +					 gen_lowpart (hmode, loxhi),
> +					 hprec - 1, NULL_RTX, 0);
>  
>  	  emit_cmp_and_jump_insns (signbitloxhi, hipartloxhi, NE, NULL_RTX,
>  				   hmode, false, do_overflow,
> @@ -750,82 +1468,131 @@ ubsan_expand_si_overflow_mul_check (gimp
>  
>  	  emit_label (both_ops_large);
>  
> -	  /* If both operands are large (not sign extended from hmode),
> -	     then perform the full multiplication which will be the result
> -	     of the operation.  The only cases which don't overflow are
> -	     some cases where both hipart0 and highpart1 are 0 or -1.  */
> +	  /* If both operands are large (not sign (!uns) or zero (uns)
> +	     extended from hmode), then perform the full multiplication
> +	     which will be the result of the operation.
> +	     The only cases which don't overflow are for signed multiplication
> +	     some cases where both hipart0 and highpart1 are 0 or -1.
> +	     For unsigned multiplication when high parts are both non-zero
> +	     this overflows always.  */
>  	  ops.code = MULT_EXPR;
> -	  ops.op0 = make_tree (TREE_TYPE (arg0), op0);
> -	  ops.op1 = make_tree (TREE_TYPE (arg0), op1);
> +	  ops.op0 = make_tree (type, op0);
> +	  ops.op1 = make_tree (type, op1);
>  	  tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
>  	  emit_move_insn (res, tem);
>  
> -	  if (!op0_medium_p)
> +	  if (!uns)
>  	    {
> -	      tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
> -					 NULL_RTX, 1, OPTAB_DIRECT);
> -	      emit_cmp_and_jump_insns (tem, const1_rtx, GTU, NULL_RTX, hmode,
> -				       true, do_error, PROB_VERY_UNLIKELY);
> -	    }
> -
> -	  if (!op1_medium_p)
> -	    {
> -	      tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
> -					 NULL_RTX, 1, OPTAB_DIRECT);
> -	      emit_cmp_and_jump_insns (tem, const1_rtx, GTU, NULL_RTX, hmode,
> -				       true, do_error, PROB_VERY_UNLIKELY);
> -	    }
> -
> -	  /* At this point hipart{0,1} are both in [-1, 0].  If they are the
> -	     same, overflow happened if res is negative, if they are different,
> -	     overflow happened if res is positive.  */
> -	  if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
> -	    emit_jump (hipart_different);
> -	  else if (op0_sign == 1 || op1_sign == 1)
> -	    emit_cmp_and_jump_insns (hipart0, hipart1, NE, NULL_RTX, hmode,
> -				     true, hipart_different, PROB_EVEN);
> -
> -	  emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode, false,
> -				   do_error, PROB_VERY_UNLIKELY);
> -	  emit_jump (done_label);
> +	      if (!op0_medium_p)
> +		{
> +		  tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
> +					     NULL_RTX, 1, OPTAB_DIRECT);
> +		  emit_cmp_and_jump_insns (tem, const1_rtx, GTU, NULL_RTX,
> +					   hmode, true, do_error,
> +					   PROB_VERY_UNLIKELY);
> +		}
>  
> -	  emit_label (hipart_different);
> +	      if (!op1_medium_p)
> +		{
> +		  tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
> +					     NULL_RTX, 1, OPTAB_DIRECT);
> +		  emit_cmp_and_jump_insns (tem, const1_rtx, GTU, NULL_RTX,
> +					   hmode, true, do_error,
> +					   PROB_VERY_UNLIKELY);
> +		}
>  
> -	  emit_cmp_and_jump_insns (res, const0_rtx, GE, NULL_RTX, mode, false,
> -				   do_error, PROB_VERY_UNLIKELY);
> -	  emit_jump (done_label);
> +	      /* At this point hipart{0,1} are both in [-1, 0].  If they are
> +		 the same, overflow happened if res is negative, if they are
> +		 different, overflow happened if res is positive.  */
> +	      if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
> +		emit_jump (hipart_different);
> +	      else if (op0_sign == 1 || op1_sign == 1)
> +		emit_cmp_and_jump_insns (hipart0, hipart1, NE, NULL_RTX, hmode,
> +					 true, hipart_different, PROB_EVEN);
> +
> +	      emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode,
> +				       false, do_error, PROB_VERY_UNLIKELY);
> +	      emit_jump (done_label);
> +
> +	      emit_label (hipart_different);
> +
> +	      emit_cmp_and_jump_insns (res, const0_rtx, GE, NULL_RTX, mode,
> +				       false, do_error, PROB_VERY_UNLIKELY);
> +	      emit_jump (done_label);
> +	    }
>  
>  	  emit_label (do_overflow);
>  
>  	  /* Overflow, do full multiplication and fallthru into do_error.  */
> -	  ops.op0 = make_tree (TREE_TYPE (arg0), op0);
> -	  ops.op1 = make_tree (TREE_TYPE (arg0), op1);
> +	  ops.op0 = make_tree (type, op0);
> +	  ops.op1 = make_tree (type, op1);
>  	  tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
>  	  emit_move_insn (res, tem);
>  	}
>        else
>  	{
> +	  gcc_assert (!is_ubsan);
>  	  ops.code = MULT_EXPR;
> -	  ops.type = TREE_TYPE (arg0);
> +	  ops.type = type;
>  	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
>  	  emit_jump (done_label);
>  	}
>      }
>  
> + do_error_label:
>    emit_label (do_error);
> -  /* Expand the ubsan builtin call.  */
> -  push_temp_slots ();
> -  fn = ubsan_build_overflow_builtin (MULT_EXPR, gimple_location (stmt),
> -				     TREE_TYPE (arg0), arg0, arg1);
> -  expand_normal (fn);
> -  pop_temp_slots ();
> -  do_pending_stack_adjust ();
> +  if (is_ubsan)
> +    {
> +      /* Expand the ubsan builtin call.  */
> +      push_temp_slots ();
> +      fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (arg0),
> +					 arg0, arg1);
> +      expand_normal (fn);
> +      pop_temp_slots ();
> +      do_pending_stack_adjust ();
> +    }
> +  else if (lhs)
> +    write_complex_part (target, const1_rtx, true);
>  
>    /* We're done.  */
>    emit_label (done_label);
>  
> +  /* u1 * u2 -> sr  */
> +  if (uns0_p && uns1_p && !unsr_p)
> +    {
> +      rtx_code_label *all_done_label = gen_label_rtx ();
> +      emit_cmp_and_jump_insns (res, const0_rtx, GE, NULL_RTX, mode,
> +			       false, all_done_label, PROB_VERY_LIKELY);
> +      write_complex_part (target, const1_rtx, true);
> +      emit_label (all_done_label);
> +    }
> +
> +  /* s1 * u2 -> sr  */
> +  if (!uns0_p && uns1_p && !unsr_p && pos_neg1 == 3)
> +    {
> +      rtx_code_label *all_done_label = gen_label_rtx ();
> +      rtx_code_label *set_noovf = gen_label_rtx ();
> +      emit_cmp_and_jump_insns (op1, const0_rtx, GE, NULL_RTX, mode,
> +			       false, all_done_label, PROB_VERY_LIKELY);
> +      write_complex_part (target, const1_rtx, true);
> +      emit_cmp_and_jump_insns (op0, const0_rtx, EQ, NULL_RTX, mode,
> +			       false, set_noovf, PROB_VERY_LIKELY);
> +      emit_cmp_and_jump_insns (op0, constm1_rtx, NE, NULL_RTX, mode,
> +			       false, all_done_label, PROB_VERY_UNLIKELY);
> +      emit_cmp_and_jump_insns (op1, res, NE, NULL_RTX, mode,
> +			       false, all_done_label, PROB_VERY_UNLIKELY);
> +      emit_label (set_noovf);
> +      write_complex_part (target, const0_rtx, true);
> +      emit_label (all_done_label);
> +    }
> +
>    if (lhs)
> -    emit_move_insn (target, res);
> +    {
> +      if (is_ubsan)
> +	emit_move_insn (target, res);
> +      else
> +	expand_arith_overflow_result_store (lhs, target, mode, res);
> +    }
>  }
>  
>  /* Expand UBSAN_CHECK_ADD call STMT.  */
> @@ -833,7 +1600,12 @@ ubsan_expand_si_overflow_mul_check (gimp
>  static void
>  expand_UBSAN_CHECK_ADD (gimple stmt)
>  {
> -  ubsan_expand_si_overflow_addsub_check (PLUS_EXPR, stmt);
> +  location_t loc = gimple_location (stmt);
> +  tree lhs = gimple_call_lhs (stmt);
> +  tree arg0 = gimple_call_arg (stmt, 0);
> +  tree arg1 = gimple_call_arg (stmt, 1);
> +  expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1,
> +			  false, false, false, true);
>  }
>  
>  /* Expand UBSAN_CHECK_SUB call STMT.  */
> @@ -841,10 +1613,15 @@ expand_UBSAN_CHECK_ADD (gimple stmt)
>  static void
>  expand_UBSAN_CHECK_SUB (gimple stmt)
>  {
> -  if (integer_zerop (gimple_call_arg (stmt, 0)))
> -    ubsan_expand_si_overflow_neg_check (stmt);
> +  location_t loc = gimple_location (stmt);
> +  tree lhs = gimple_call_lhs (stmt);
> +  tree arg0 = gimple_call_arg (stmt, 0);
> +  tree arg1 = gimple_call_arg (stmt, 1);
> +  if (integer_zerop (arg0))
> +    expand_neg_overflow (loc, lhs, arg1, true);
>    else
> -    ubsan_expand_si_overflow_addsub_check (MINUS_EXPR, stmt);
> +    expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1,
> +			    false, false, false, true);
>  }
>  
>  /* Expand UBSAN_CHECK_MUL call STMT.  */
> @@ -852,7 +1629,208 @@ expand_UBSAN_CHECK_SUB (gimple stmt)
>  static void
>  expand_UBSAN_CHECK_MUL (gimple stmt)
>  {
> -  ubsan_expand_si_overflow_mul_check (stmt);
> +  location_t loc = gimple_location (stmt);
> +  tree lhs = gimple_call_lhs (stmt);
> +  tree arg0 = gimple_call_arg (stmt, 0);
> +  tree arg1 = gimple_call_arg (stmt, 1);
> +  expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true);
> +}
> +
> +/* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion.  */
> +
> +static void
> +expand_arith_overflow (enum tree_code code, gimple stmt)
> +{
> +  tree lhs = gimple_call_lhs (stmt);
> +  if (lhs == NULL_TREE)
> +    return;
> +  tree arg0 = gimple_call_arg (stmt, 0);
> +  tree arg1 = gimple_call_arg (stmt, 1);
> +  tree type = TREE_TYPE (TREE_TYPE (lhs));
> +  int uns0_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
> +  int uns1_p = TYPE_UNSIGNED (TREE_TYPE (arg1));
> +  int unsr_p = TYPE_UNSIGNED (type);
> +  int prec0 = TYPE_PRECISION (TREE_TYPE (arg0));
> +  int prec1 = TYPE_PRECISION (TREE_TYPE (arg1));
> +  int precres = TYPE_PRECISION (type);
> +  location_t loc = gimple_location (stmt);
> +  if (!uns0_p && get_range_pos_neg (arg0) == 1)
> +    uns0_p = true;
> +  if (!uns1_p && get_range_pos_neg (arg1) == 1)
> +    uns1_p = true;
> +  int pr = get_min_precision (arg0, uns0_p ? UNSIGNED : SIGNED);
> +  prec0 = MIN (prec0, pr);
> +  pr = get_min_precision (arg1, uns1_p ? UNSIGNED : SIGNED);
> +  prec1 = MIN (prec1, pr);
> +
> +  /* If uns0_p && uns1_p, precop is minimum needed precision
> +     of unsigned type to hold the exact result, otherwise
> +     precop is minimum needed precision of signed type to
> +     hold the exact result.  */
> +  int precop;
> +  if (code == MULT_EXPR)
> +    precop = prec0 + prec1 + (uns0_p != uns1_p);
> +  else
> +    {
> +      if (uns0_p == uns1_p)
> +	precop = MAX (prec0, prec1) + 1;
> +      else if (uns0_p)
> +	precop = MAX (prec0 + 1, prec1) + 1;
> +      else
> +	precop = MAX (prec0, prec1 + 1) + 1;
> +    }
> +  int orig_precres = precres;
> +
> +  do
> +    {
> +      if ((uns0_p && uns1_p)
> +	  ? ((precop + !unsr_p) <= precres
> +	     /* u1 - u2 -> ur can overflow, no matter what precision
> +		the result has.  */
> +	     && (code != MINUS_EXPR || !unsr_p))
> +	  : (!unsr_p && precop <= precres))
> +	{
> +	  /* The infinity precision result will always fit into result.  */
> +	  rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +	  write_complex_part (target, const0_rtx, true);
> +	  enum machine_mode mode = TYPE_MODE (type);
> +	  struct separate_ops ops;
> +	  ops.code = code;
> +	  ops.type = type;
> +	  ops.op0 = fold_convert_loc (loc, type, arg0);
> +	  ops.op1 = fold_convert_loc (loc, type, arg1);
> +	  ops.op2 = NULL_TREE;
> +	  ops.location = loc;
> +	  rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
> +	  expand_arith_overflow_result_store (lhs, target, mode, tem);
> +	  return;
> +	}
> +
> +#ifdef WORD_REGISTER_OPERATIONS
> +      /* For sub-word operations, if target doesn't have them, start
> +	 with precres widening right away, otherwise do it only
> +	 if the most simple cases can't be used.  */
> +      if (orig_precres == precres && precres < BITS_PER_WORD)
> +	;
> +      else
> +#endif
> +      if ((uns0_p && uns1_p && unsr_p && prec0 <= precres && prec1 <= precres)
> +	  || ((!uns0_p || !uns1_p) && !unsr_p
> +	      && prec0 + uns0_p <= precres
> +	      && prec1 + uns1_p <= precres))
> +	{
> +	  arg0 = fold_convert_loc (loc, type, arg0);
> +	  arg1 = fold_convert_loc (loc, type, arg1);
> +	  switch (code)
> +	    {
> +	    case MINUS_EXPR:
> +	      if (integer_zerop (arg0) && !unsr_p)
> +		expand_neg_overflow (loc, lhs, arg1, false);
> +	      /* FALLTHRU */
> +	    case PLUS_EXPR:
> +	      expand_addsub_overflow (loc, code, lhs, arg0, arg1,
> +				      unsr_p, unsr_p, unsr_p, false);
> +	      return;
> +	    case MULT_EXPR:
> +	      expand_mul_overflow (loc, lhs, arg0, arg1,
> +				   unsr_p, unsr_p, unsr_p, false);
> +	      return;
> +	    default:
> +	      gcc_unreachable ();
> +	    }
> +	}
> +
> +      /* For sub-word operations, retry with a wider type first.  */
> +      if (orig_precres == precres && precop <= BITS_PER_WORD)
> +	{
> +#ifdef WORD_REGISTER_OPERATIONS
> +	  int p = BITS_PER_WORD;
> +#else
> +	  int p = precop;
> +#endif
> +	  enum machine_mode m = smallest_mode_for_size (p, MODE_INT);
> +	  tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
> +							uns0_p && uns1_p
> +							&& unsr_p);
> +	  p = TYPE_PRECISION (optype);
> +	  if (p > precres)
> +	    {
> +	      precres = p;
> +	      unsr_p = TYPE_UNSIGNED (optype);
> +	      type = optype;
> +	      continue;
> +	    }
> +	}
> +
> +      if (prec0 <= precres && prec1 <= precres)
> +	{
> +	  tree types[2];
> +	  if (unsr_p)
> +	    {
> +	      types[0] = build_nonstandard_integer_type (precres, 0);
> +	      types[1] = type;
> +	    }
> +	  else
> +	    {
> +	      types[0] = type;
> +	      types[1] = build_nonstandard_integer_type (precres, 1);
> +	    }
> +	  arg0 = fold_convert_loc (loc, types[uns0_p], arg0);
> +	  arg1 = fold_convert_loc (loc, types[uns1_p], arg1);
> +	  if (code != MULT_EXPR)
> +	    expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
> +				    uns0_p, uns1_p, false);
> +	  else
> +	    expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
> +				 uns0_p, uns1_p, false);
> +	  return;
> +	}
> +
> +      /* Retry with a wider type.  */
> +      if (orig_precres == precres)
> +	{
> +	  int p = MAX (prec0, prec1);
> +	  enum machine_mode m = smallest_mode_for_size (p, MODE_INT);
> +	  tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
> +							uns0_p && uns1_p
> +							&& unsr_p);
> +	  p = TYPE_PRECISION (optype);
> +	  if (p > precres)
> +	    {
> +	      precres = p;
> +	      unsr_p = TYPE_UNSIGNED (optype);
> +	      type = optype;
> +	      continue;
> +	    }
> +	}
> +
> +      gcc_unreachable ();
> +    }
> +  while (1);
> +}
> +
> +/* Expand ADD_OVERFLOW STMT.  */
> +
> +static void
> +expand_ADD_OVERFLOW (gimple stmt)
> +{
> +  expand_arith_overflow (PLUS_EXPR, stmt);
> +}
> +
> +/* Expand SUB_OVERFLOW STMT.  */
> +
> +static void
> +expand_SUB_OVERFLOW (gimple stmt)
> +{
> +  expand_arith_overflow (MINUS_EXPR, stmt);
> +}
> +
> +/* Expand MUL_OVERFLOW STMT.  */
> +
> +static void
> +expand_MUL_OVERFLOW (gimple stmt)
> +{
> +  expand_arith_overflow (MULT_EXPR, stmt);
>  }
>  
>  /* This should get folded in tree-vectorizer.c.  */
> --- gcc/internal-fn.def.jj	2014-10-10 19:42:22.000000000 +0200
> +++ gcc/internal-fn.def	2014-10-30 15:27:28.173658758 +0100
> @@ -57,3 +57,6 @@ DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_
>  DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
>  DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
>  DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".W...")
> +DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
> +DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
> +DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
> --- gcc/tree-vrp.c.jj	2014-10-31 09:49:52.000000000 +0100
> +++ gcc/tree-vrp.c	2014-11-10 09:42:38.190965111 +0100
> @@ -3753,6 +3753,113 @@ extract_range_from_comparison (value_ran
>      set_value_range_to_truthvalue (vr, type);
>  }
>  
> +/* Helper function for simplify_internal_call_using_ranges and
> +   extract_range_basic.  Return true if OP0 SUBCODE OP1 for
> +   SUBCODE {PLUS,MINUS,MULT}_EXPR is known to never overflow or
> +   always overflow.  Set *OVF to true if it is known to always
> +   overflow.  */
> +
> +static bool
> +check_for_binary_op_overflow (enum tree_code subcode, tree type,
> +			      tree op0, tree op1, bool *ovf)
> +{
> +  value_range_t vr0 = VR_INITIALIZER;
> +  value_range_t vr1 = VR_INITIALIZER;
> +  if (TREE_CODE (op0) == SSA_NAME)
> +    vr0 = *get_value_range (op0);
> +  else if (TREE_CODE (op0) == INTEGER_CST)
> +    set_value_range_to_value (&vr0, op0, NULL);
> +  else
> +    set_value_range_to_varying (&vr0);
> +
> +  if (TREE_CODE (op1) == SSA_NAME)
> +    vr1 = *get_value_range (op1);
> +  else if (TREE_CODE (op1) == INTEGER_CST)
> +    set_value_range_to_value (&vr1, op1, NULL);
> +  else
> +    set_value_range_to_varying (&vr1);
> +
> +  if (!range_int_cst_p (&vr0)
> +      || TREE_OVERFLOW (vr0.min)
> +      || TREE_OVERFLOW (vr0.max))
> +    {
> +      vr0.min = vrp_val_min (TREE_TYPE (op0));
> +      vr0.max = vrp_val_max (TREE_TYPE (op0));
> +    }
> +  if (!range_int_cst_p (&vr1)
> +      || TREE_OVERFLOW (vr1.min)
> +      || TREE_OVERFLOW (vr1.max))
> +    {
> +      vr1.min = vrp_val_min (TREE_TYPE (op1));
> +      vr1.max = vrp_val_max (TREE_TYPE (op1));
> +    }
> +  *ovf = arith_overflowed_p (subcode, type, vr0.min,
> +			     subcode == MINUS_EXPR ? vr1.max : vr1.min);
> +  if (arith_overflowed_p (subcode, type, vr0.max,
> +			  subcode == MINUS_EXPR ? vr1.min : vr1.max) != *ovf)
> +    return false;
> +  if (subcode == MULT_EXPR)
> +    {
> +      if (arith_overflowed_p (subcode, type, vr0.min, vr1.max) != *ovf
> +	  || arith_overflowed_p (subcode, type, vr0.max, vr1.min) != *ovf)
> +	return false;
> +    }
> +  if (*ovf)
> +    {
> +      /* So far we found that there is an overflow on the boundaries.
> +	 That doesn't prove that there is an overflow even for all values
> +	 in between the boundaries.  For that compute widest_int range
> +	 of the result and see if it doesn't overlap the range of
> +	 type.  */
> +      widest_int wmin, wmax;
> +      widest_int w[4];
> +      int i;
> +      w[0] = wi::to_widest (vr0.min);
> +      w[1] = wi::to_widest (vr0.max);
> +      w[2] = wi::to_widest (vr1.min);
> +      w[3] = wi::to_widest (vr1.max);
> +      for (i = 0; i < 4; i++)
> +	{
> +	  widest_int wt;
> +	  switch (subcode)
> +	    {
> +	    case PLUS_EXPR:
> +	      wt = wi::add (w[i & 1], w[2 + (i & 2) / 2]);
> +	      break;
> +	    case MINUS_EXPR:
> +	      wt = wi::sub (w[i & 1], w[2 + (i & 2) / 2]);
> +	      break;
> +	    case MULT_EXPR:
> +	      wt = wi::mul (w[i & 1], w[2 + (i & 2) / 2]);
> +	      break;
> +	    default:
> +	      gcc_unreachable ();
> +	    }
> +	  if (i == 0)
> +	    {
> +	      wmin = wt;
> +	      wmax = wt;
> +	    }
> +	  else
> +	    {
> +	      wmin = wi::smin (wmin, wt);
> +	      wmax = wi::smax (wmax, wt);
> +	    }
> +	}
> +      /* The result of op0 CODE op1 is known to be in range
> +	 [wmin, wmax].  */
> +      widest_int wtmin = wi::to_widest (vrp_val_min (type));
> +      widest_int wtmax = wi::to_widest (vrp_val_max (type));
> +      /* If all values in [wmin, wmax] are smaller than
> +	 [wtmin, wtmax] or all are larger than [wtmin, wtmax],
> +	 the arithmetic operation will always overflow.  */
> +      if (wi::lts_p (wmax, wtmin) || wi::gts_p (wmin, wtmax))
> +	return true;
> +      return false;
> +    }
> +  return true;
> +}
> +
>  /* Try to derive a nonnegative or nonzero range out of STMT relying
>     primarily on generic routines in fold in conjunction with range data.
>     Store the result in *VR */
> @@ -3942,8 +4049,7 @@ extract_range_basic (value_range_t *vr,
>  	  break;
>  	}
>      }
> -  else if (is_gimple_call (stmt)
> -	   && gimple_call_internal_p (stmt))
> +  else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
>      {
>        enum tree_code subcode = ERROR_MARK;
>        switch (gimple_call_internal_fn (stmt))
> @@ -3983,6 +4089,84 @@ extract_range_basic (value_range_t *vr,
>  	  return;
>  	}
>      }
> +  /* Handle extraction of the two results (result of arithmetics and
> +     a flag whether arithmetics overflowed) from {ADD,SUB,MUL}_OVERFLOW
> +     internal function.  */
> +  else if (is_gimple_assign (stmt)
> +	   && (gimple_assign_rhs_code (stmt) == REALPART_EXPR
> +	       || gimple_assign_rhs_code (stmt) == IMAGPART_EXPR)
> +	   && INTEGRAL_TYPE_P (type))
> +    {
> +      enum tree_code code = gimple_assign_rhs_code (stmt);
> +      tree op = gimple_assign_rhs1 (stmt);
> +      if (TREE_CODE (op) == code && TREE_CODE (TREE_OPERAND (op, 0)) == SSA_NAME)
> +	{
> +	  gimple g = SSA_NAME_DEF_STMT (TREE_OPERAND (op, 0));
> +	  if (is_gimple_call (g) && gimple_call_internal_p (g))
> +	    {
> +	      enum tree_code subcode = ERROR_MARK;
> +	      switch (gimple_call_internal_fn (g))
> +		{
> +		case IFN_ADD_OVERFLOW:
> +		  subcode = PLUS_EXPR;
> +		  break;
> +		case IFN_SUB_OVERFLOW:
> +		  subcode = MINUS_EXPR;
> +		  break;
> +		case IFN_MUL_OVERFLOW:
> +		  subcode = MULT_EXPR;
> +		  break;
> +		default:
> +		  break;
> +		}
> +	      if (subcode != ERROR_MARK)
> +		{
> +		  tree op0 = gimple_call_arg (g, 0);
> +		  tree op1 = gimple_call_arg (g, 1);
> +		  if (code == IMAGPART_EXPR)
> +		    {
> +		      bool ovf = false;
> +		      if (check_for_binary_op_overflow (subcode, type,
> +							op0, op1, &ovf))
> +			set_value_range_to_value (vr,
> +						  build_int_cst (type, ovf),
> +						  NULL);
> +		      else
> +			set_value_range (vr, VR_RANGE, build_int_cst (type, 0),
> +					 build_int_cst (type, 1), NULL);
> +		    }
> +		  else if (types_compatible_p (type, TREE_TYPE (op0))
> +			   && types_compatible_p (type, TREE_TYPE (op1)))
> +		    {
> +		      bool saved_flag_wrapv = flag_wrapv;
> +		      /* Pretend the arithmetics is wrapping.  If there is
> +			 any overflow, IMAGPART_EXPR will be set.  */
> +		      flag_wrapv = 1;
> +		      extract_range_from_binary_expr (vr, subcode, type,
> +						      op0, op1);
> +		      flag_wrapv = saved_flag_wrapv;
> +		    }
> +		  else
> +		    {
> +		      value_range_t vr0 = VR_INITIALIZER;
> +		      value_range_t vr1 = VR_INITIALIZER;
> +		      bool saved_flag_wrapv = flag_wrapv;
> +		      /* Pretend the arithmetics is wrapping.  If there is
> +			 any overflow, IMAGPART_EXPR will be set.  */
> +		      flag_wrapv = 1;
> +		      extract_range_from_unary_expr (&vr0, NOP_EXPR,
> +						     type, op0);
> +		      extract_range_from_unary_expr (&vr1, NOP_EXPR,
> +						     type, op1);
> +		      extract_range_from_binary_expr_1 (vr, subcode, type,
> +							&vr0, &vr1);
> +		      flag_wrapv = saved_flag_wrapv;
> +		    }
> +		  return;
> +		}
> +	    }
> +	}
> +    }
>    if (INTEGRAL_TYPE_P (type)
>        && gimple_stmt_nonnegative_warnv_p (stmt, &sop))
>      set_value_range_to_nonnegative (vr, type,
> @@ -9476,87 +9660,100 @@ static bool
>  simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
>  {
>    enum tree_code subcode;
> +  bool is_ubsan = false;
> +  bool ovf = false;
>    switch (gimple_call_internal_fn (stmt))
>      {
>      case IFN_UBSAN_CHECK_ADD:
>        subcode = PLUS_EXPR;
> +      is_ubsan = true;
>        break;
>      case IFN_UBSAN_CHECK_SUB:
>        subcode = MINUS_EXPR;
> +      is_ubsan = true;
>        break;
>      case IFN_UBSAN_CHECK_MUL:
>        subcode = MULT_EXPR;
> +      is_ubsan = true;
> +      break;
> +    case IFN_ADD_OVERFLOW:
> +      subcode = PLUS_EXPR;
> +      break;
> +    case IFN_SUB_OVERFLOW:
> +      subcode = MINUS_EXPR;
> +      break;
> +    case IFN_MUL_OVERFLOW:
> +      subcode = MULT_EXPR;
>        break;
>      default:
>        return false;
>      }
>  
> -  value_range_t vr0 = VR_INITIALIZER;
> -  value_range_t vr1 = VR_INITIALIZER;
>    tree op0 = gimple_call_arg (stmt, 0);
>    tree op1 = gimple_call_arg (stmt, 1);
> -
> -  if (TREE_CODE (op0) == SSA_NAME)
> -    vr0 = *get_value_range (op0);
> -  else if (TREE_CODE (op0) == INTEGER_CST)
> -    set_value_range_to_value (&vr0, op0, NULL);
> -  else
> -    set_value_range_to_varying (&vr0);
> -
> -  if (TREE_CODE (op1) == SSA_NAME)
> -    vr1 = *get_value_range (op1);
> -  else if (TREE_CODE (op1) == INTEGER_CST)
> -    set_value_range_to_value (&vr1, op1, NULL);
> +  tree type;
> +  if (is_ubsan)
> +    type = TREE_TYPE (op0);
> +  else if (gimple_call_lhs (stmt) == NULL_TREE)
> +    return false;
>    else
> -    set_value_range_to_varying (&vr1);
> +    type = TREE_TYPE (TREE_TYPE (gimple_call_lhs (stmt)));
> +  if (!check_for_binary_op_overflow (subcode, type, op0, op1, &ovf)
> +      || (is_ubsan && ovf))
> +    return false;
>  
> -  if (!range_int_cst_p (&vr0))
> -    {
> -      /* If one range is VR_ANTI_RANGE, VR_VARYING etc.,
> -	 optimize at least x = y + 0; x = y - 0; x = y * 0;
> -	 and x = y * 1; which never overflow.  */
> -      if (!range_int_cst_p (&vr1))
> -	return false;
> -      if (tree_int_cst_sgn (vr1.min) == -1)
> -	return false;
> -      if (compare_tree_int (vr1.max, subcode == MULT_EXPR) == 1)
> -	return false;
> -    }
> -  else if (!range_int_cst_p (&vr1))
> -    {
> -      /* If one range is VR_ANTI_RANGE, VR_VARYING etc.,
> -	 optimize at least x = 0 + y; x = 0 * y; and x = 1 * y;
> -	 which never overflow.  */
> -      if (subcode == MINUS_EXPR)
> -	return false;
> -      if (!range_int_cst_p (&vr0))
> -	return false;
> -      if (tree_int_cst_sgn (vr0.min) == -1)
> -	return false;
> -      if (compare_tree_int (vr0.max, subcode == MULT_EXPR) == 1)
> -	return false;
> -    }
> +  gimple g;
> +  location_t loc = gimple_location (stmt);
> +  if (is_ubsan)
> +    g = gimple_build_assign_with_ops (subcode, gimple_call_lhs (stmt),
> +				      op0, op1);
>    else
>      {
> -      tree r1 = int_const_binop (subcode, vr0.min,
> -				 subcode == MINUS_EXPR ? vr1.max : vr1.min);
> -      tree r2 = int_const_binop (subcode, vr0.max,
> -				 subcode == MINUS_EXPR ? vr1.min : vr1.max);
> -      if (r1 == NULL_TREE || TREE_OVERFLOW (r1)
> -	  || r2 == NULL_TREE || TREE_OVERFLOW (r2))
> -	return false;
> -      if (subcode == MULT_EXPR)
> -	{
> -	  tree r3 = int_const_binop (subcode, vr0.min, vr1.max);
> -	  tree r4 = int_const_binop (subcode, vr0.max, vr1.min);
> -	  if (r3 == NULL_TREE || TREE_OVERFLOW (r3)
> -	      || r4 == NULL_TREE || TREE_OVERFLOW (r4))
> -	    return false;
> +      int prec = TYPE_PRECISION (type);
> +      tree utype = type;
> +      if (ovf
> +	  || !useless_type_conversion_p (type, TREE_TYPE (op0))
> +	  || !useless_type_conversion_p (type, TREE_TYPE (op1)))
> +	utype = build_nonstandard_integer_type (prec, 1);
> +      if (TREE_CODE (op0) == INTEGER_CST)
> +	op0 = fold_convert (utype, op0);
> +      else if (!useless_type_conversion_p (utype, TREE_TYPE (op0)))
> +	{
> +	  g = gimple_build_assign_with_ops (NOP_EXPR,
> +					    make_ssa_name (utype, NULL),
> +					    op0, NULL_TREE);
> +	  gimple_set_location (g, loc);
> +	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
> +	  op0 = gimple_assign_lhs (g);
>  	}
> +      if (TREE_CODE (op1) == INTEGER_CST)
> +	op1 = fold_convert (utype, op1);
> +      else if (!useless_type_conversion_p (utype, TREE_TYPE (op1)))
> +	{
> +	  g = gimple_build_assign_with_ops (NOP_EXPR,
> +					    make_ssa_name (utype, NULL),
> +					    op1, NULL_TREE);
> +	  gimple_set_location (g, loc);
> +	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
> +	  op1 = gimple_assign_lhs (g);
> +	}
> +      g = gimple_build_assign_with_ops (subcode, make_ssa_name (utype, NULL),
> +					op0, op1);
> +      gimple_set_location (g, loc);
> +      gsi_insert_before (gsi, g, GSI_SAME_STMT);
> +      if (utype != type)
> +	{
> +	  g = gimple_build_assign_with_ops (NOP_EXPR,
> +					    make_ssa_name (type, NULL),
> +					    gimple_assign_lhs (g), NULL_TREE);
> +	  gimple_set_location (g, loc);
> +	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
> +	}
> +      g = gimple_build_assign_with_ops (COMPLEX_EXPR, gimple_call_lhs (stmt),
> +					gimple_assign_lhs (g),
> +					build_int_cst (type, ovf));
>      }
> -
> -  gimple g = gimple_build_assign_with_ops (subcode, gimple_call_lhs (stmt),
> -					   op0, op1);
> +  gimple_set_location (g, loc);
>    gsi_replace (gsi, g, false);
>    return true;
>  }
> --- gcc/optabs.def.jj	2014-10-28 14:40:00.000000000 +0100
> +++ gcc/optabs.def	2014-11-03 10:52:06.311865217 +0100
> @@ -190,6 +190,7 @@ 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 (umulv4_optab, "umulv$I$a4")
>  OPTAB_D (negv3_optab, "negv$I$a3")
>  OPTAB_D (addptr3_optab, "addptr$a3")
>  
> --- gcc/config/i386/i386.md.jj	2014-10-30 14:42:30.000000000 +0100
> +++ gcc/config/i386/i386.md	2014-11-04 10:11:37.272678588 +0100
> @@ -6644,6 +6644,99 @@ (define_insn "*mulv<mode>4_1"
>  		  (const_string "4")]
>  	      (const_string "<MODE_SIZE>")))])
>  
> +(define_expand "umulv<mode>4"
> +  [(parallel [(set (reg:CCO FLAGS_REG)
> +		   (eq:CCO (mult:<DWI>
> +			      (zero_extend:<DWI>
> +				 (match_operand:SWI48 1
> +						      "nonimmediate_operand"))
> +			      (zero_extend:<DWI>
> +				 (match_operand:SWI48 2
> +						      "nonimmediate_operand")))
> +			   (zero_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)))
> +	      (clobber (match_scratch:SWI48 4))])
> +   (set (pc) (if_then_else
> +	       (eq (reg:CCO FLAGS_REG) (const_int 0))
> +	       (label_ref (match_operand 3))
> +	       (pc)))]
> +  ""
> +{
> +  if (MEM_P (operands[1]) && MEM_P (operands[2]))
> +    operands[1] = force_reg (<MODE>mode, operands[1]);
> +})
> +
> +(define_insn "*umulv<mode>4"
> +  [(set (reg:CCO FLAGS_REG)
> +	(eq:CCO (mult:<DWI>
> +		   (zero_extend:<DWI>
> +		      (match_operand:SWI48 1 "nonimmediate_operand" "%0"))
> +		   (zero_extend:<DWI>
> +		      (match_operand:SWI48 2 "nonimmediate_operand" "rm")))
> +		(zero_extend:<DWI>
> +		   (mult:SWI48 (match_dup 1) (match_dup 2)))))
> +   (set (match_operand:SWI48 0 "register_operand" "=a")
> +	(mult:SWI48 (match_dup 1) (match_dup 2)))
> +   (clobber (match_scratch:SWI48 3 "=d"))]
> +  "!(MEM_P (operands[1]) && MEM_P (operands[2]))"
> +  "mul{<imodesuffix>}\t%2"
> +  [(set_attr "type" "imul")
> +   (set_attr "length_immediate" "0")
> +   (set (attr "athlon_decode")
> +     (if_then_else (eq_attr "cpu" "athlon")
> +       (const_string "vector")
> +       (const_string "double")))
> +   (set_attr "amdfam10_decode" "double")
> +   (set_attr "bdver1_decode" "direct")
> +   (set_attr "mode" "<MODE>")])
> +
> +(define_expand "<u>mulvqi4"
> +  [(parallel [(set (reg:CCO FLAGS_REG)
> +		   (eq:CCO (mult:HI
> +			      (any_extend:HI
> +				 (match_operand:QI 1 "nonimmediate_operand"))
> +			      (any_extend:HI
> +				 (match_operand:QI 2 "nonimmediate_operand")))
> +			   (any_extend:HI
> +			      (mult:QI (match_dup 1) (match_dup 2)))))
> +	      (set (match_operand:QI 0 "register_operand")
> +		   (mult:QI (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)))]
> +  "TARGET_QIMODE_MATH"
> +{
> +  if (MEM_P (operands[1]) && MEM_P (operands[2]))
> +    operands[1] = force_reg (QImode, operands[1]);
> +})
> +
> +(define_insn "*<u>mulvqi4"
> +  [(set (reg:CCO FLAGS_REG)
> +	(eq:CCO (mult:HI
> +		   (any_extend:HI
> +		      (match_operand:QI 1 "nonimmediate_operand" "%0"))
> +		   (any_extend:HI
> +		      (match_operand:QI 2 "nonimmediate_operand" "qm")))
> +		(any_extend:HI
> +		   (mult:QI (match_dup 1) (match_dup 2)))))
> +   (set (match_operand:QI 0 "register_operand" "=a")
> +	(mult:QI (match_dup 1) (match_dup 2)))]
> +  "TARGET_QIMODE_MATH
> +   && !(MEM_P (operands[1]) && MEM_P (operands[2]))"
> +  "<sgnprefix>mul{b}\t%2"
> +  [(set_attr "type" "imul")
> +   (set_attr "length_immediate" "0")
> +   (set (attr "athlon_decode")
> +     (if_then_else (eq_attr "cpu" "athlon")
> +	(const_string "vector")
> +	(const_string "direct")))
> +   (set_attr "amdfam10_decode" "direct")
> +   (set_attr "bdver1_decode" "direct")
> +   (set_attr "mode" "QI")])
> +
>  (define_expand "<u>mul<mode><dwi>3"
>    [(parallel [(set (match_operand:<DWI> 0 "register_operand")
>  		   (mult:<DWI>
> --- gcc/doc/extend.texi.jj	2014-10-10 08:19:20.000000000 +0200
> +++ gcc/doc/extend.texi	2014-11-07 18:00:59.768652854 +0100
> @@ -76,6 +76,8 @@ extensions, accepted by GCC in C90 mode
>  * Offsetof::            Special syntax for implementing @code{offsetof}.
>  * __sync Builtins::     Legacy built-in functions for atomic memory access.
>  * __atomic Builtins::   Atomic built-in functions with memory model.
> +* Integer Overflow Builtins:: Built-in functions to perform arithmetics and
> +                        arithmetic overflow checking.
>  * x86 specific memory model extensions for transactional memory:: x86 memory models.
>  * Object Size Checking:: Built-in functions for limited buffer overflow
>                          checking.
> @@ -8444,6 +8446,65 @@ alignment.  A value of 0 indicates typic
>  compiler may also ignore this parameter.
>  @end deftypefn
>  
> +@node Integer Overflow Builtins
> +@section Built-in functions to perform arithmetics and arithmetic overflow checking.
> +
> +The following built-in functions allow performing simple arithmetic operations
> +together with checking whether the operations overflowed.
> +
> +@deftypefn {Built-in Function} bool __builtin_add_overflow (@var{type1} a, @var{type2} b, @var{type3} *res)
> +@deftypefnx {Built-in Function} bool __builtin_sadd_overflow (int a, int b, int *res)
> +@deftypefnx {Built-in Function} bool __builtin_saddl_overflow (long int a, long int b, long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_saddll_overflow (long long int a, long long int b, long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_uadd_overflow (unsigned int a, unsigned int b, unsigned int *res)
> +@deftypefnx {Built-in Function} bool __builtin_uaddl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_uaddll_overflow (unsigned long long int a, unsigned long long int b, unsigned long int *res)
> +
> +These built-in functions promote the first two operands into infinite precision signed
> +type and perform addition on those promoted operands.  The result is then
> +cast to the type the third pointer argument points to and stored there.
> +If the stored result is equal to the infinite precision result, the built-in
> +functions return false, otherwise they return true.  As the addition is
> +performed in infinite signed precision, these built-in functions have fully defined
> +behavior for all argument values.
> +
> +The first built-in function allows arbitrary integral types for operands and
> +the result type must be pointer to some integer type, the rest of the built-in
> +functions have explicit integer types.
> +
> +The compiler will attempt to use hardware instructions to implement
> +these built-in functions where possible, like conditional jump on overflow
> +after addition, conditional jump on carry etc.
> +
> +@end deftypefn
> +
> +@deftypefn {Built-in Function} bool __builtin_sub_overflow (@var{type1} a, @var{type2} b, @var{type3} *res)
> +@deftypefnx {Built-in Function} bool __builtin_ssub_overflow (int a, int b, int *res)
> +@deftypefnx {Built-in Function} bool __builtin_ssubl_overflow (long int a, long int b, long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_ssubll_overflow (long long int a, long long int b, long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_usub_overflow (unsigned int a, unsigned int b, unsigned int *res)
> +@deftypefnx {Built-in Function} bool __builtin_usubl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_usubll_overflow (unsigned long long int a, unsigned long long int b, unsigned long int *res)
> +
> +These built-in functions are similar to the add overflow checking built-in
> +functions above, except they perform subtraction, subtract the second argument
> +from the first one, instead of addition.
> +
> +@end deftypefn
> +
> +@deftypefn {Built-in Function} bool __builtin_mul_overflow (@var{type1} a, @var{type2} b, @var{type3} *res)
> +@deftypefnx {Built-in Function} bool __builtin_smul_overflow (int a, int b, int *res)
> +@deftypefnx {Built-in Function} bool __builtin_smull_overflow (long int a, long int b, long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_smulll_overflow (long long int a, long long int b, long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_umul_overflow (unsigned int a, unsigned int b, unsigned int *res)
> +@deftypefnx {Built-in Function} bool __builtin_umull_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
> +@deftypefnx {Built-in Function} bool __builtin_umulll_overflow (unsigned long long int a, unsigned long long int b, unsigned long int *res)
> +
> +These built-in functions are similar to the add overflow checking built-in
> +functions above, except they perform multiplication, instead of addition.
> +
> +@end deftypefn
> +
>  @node x86 specific memory model extensions for transactional memory
>  @section x86 specific memory model extensions for transactional memory
>  
> --- gcc/c-family/c-common.c.jj	2014-10-30 14:42:20.000000000 +0100
> +++ gcc/c-family/c-common.c	2014-11-10 14:45:05.066375016 +0100
> @@ -9577,6 +9577,30 @@ check_builtin_function_arguments (tree f
>  	}
>        return false;
>  
> +    case BUILT_IN_ADD_OVERFLOW:
> +    case BUILT_IN_SUB_OVERFLOW:
> +    case BUILT_IN_MUL_OVERFLOW:
> +      if (builtin_function_validate_nargs (fndecl, nargs, 3))
> +	{
> +	  unsigned i;
> +	  for (i = 0; i < 2; i++)
> +	    if (!INTEGRAL_TYPE_P (TREE_TYPE (args[i])))
> +	      {
> +		error ("argument %u in call to function %qE does not have "
> +		       "integral type", i + 1, fndecl);
> +		return false;
> +	      }
> +	  if (TREE_CODE (TREE_TYPE (args[2])) != POINTER_TYPE
> +	      || TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) != INTEGER_TYPE)
> +	    {
> +	      error ("argument 3 in call to function %qE does not have "
> +		     "pointer to integer type", fndecl);
> +	      return false;
> +	    }
> +	  return true;
> +	}
> +      return false;
> +
>      default:
>        return true;
>      }
> --- gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c.jj	2014-11-10 14:46:19.707055522 +0100
> +++ gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c	2014-11-10 14:46:14.251304496 +0100
> @@ -0,0 +1,49 @@
> +/* { dg-do compile } */
> +
> +int
> +f1 (void)
> +{
> +  int x = __builtin_add_overflow ();	/* { dg-error "not enough arguments to function" } */
> +  x += __builtin_sub_overflow ();	/* { dg-error "not enough arguments to function" } */
> +  x += __builtin_mul_overflow ();	/* { dg-error "not enough arguments to function" } */
> +  return x;
> +}
> +
> +int
> +f2 (int a, int b, int *c, int d)
> +{
> +  int x = __builtin_add_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
> +  x += __builtin_sub_overflow (a, b, c, d, d, d);	/* { dg-error "too many arguments to function" } */
> +  x += __builtin_mul_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
> +  return x;
> +}
> +
> +enum E { e0 = 0, e1 = 1 };
> +
> +#ifndef __cplusplus
> +#define bool _Bool
> +#endif
> +
> +int
> +f3 (float fa, int a, _Complex long int ca, double fb, void *pb, int b, enum E eb, bool bb, int *c)
> +{
> +  int x = __builtin_add_overflow (fa, b, c);	/* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */
> +  x += __builtin_sub_overflow (ca, b, c);	/* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */
> +  x += __builtin_mul_overflow (a, fb, c);	/* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */
> +  x += __builtin_add_overflow (a, pb, c);	/* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */
> +  x += __builtin_sub_overflow (a, eb, c);
> +  x += __builtin_mul_overflow (a, bb, c);
> +  return x;
> +}
> +
> +int
> +f4 (float *fp, double *dp, _Complex int *cp, enum E *ep, bool *bp, long long int *llp)
> +{
> +  int x = __builtin_add_overflow (1, 2, fp);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
> +  x += __builtin_sub_overflow (1, 2, dp);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
> +  x += __builtin_mul_overflow (1, 2, cp);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
> +  x += __builtin_add_overflow (1, 2, ep);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
> +  x += __builtin_sub_overflow (1, 2, bp);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
> +  x += __builtin_mul_overflow (1, 2, llp);
> +  return x;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-10.c.jj	2014-11-05 11:04:22.654982970 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-10.c	2014-11-07 19:10:26.130018889 +0100
> @@ -0,0 +1,19 @@
> +/* Test __builtin_{add,sub}_overflow on {,un}signed long int.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +typedef signed long int S;
> +typedef unsigned long int U;
> +#define COND 1
> +#define SHIFT ((__SIZEOF_LONG__ - 1) * __CHAR_BIT__)
> +#define S_MAX __LONG_MAX__
> +#define S_MIN (-__LONG_MAX__ - 1)
> +#if __SIZEOF_LONG_LONG__ > __SIZEOF_LONG__
> +typedef long long int W;
> +#elif __SIZEOF_INT128__ > __SIZEOF_LONG__
> +typedef __int128 W;
> +#else
> +#undef COND
> +#define COND 0
> +#endif
> +#include "builtin-arith-overflow-7.c"
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-11.c.jj	2014-11-05 11:05:36.909635260 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-11.c	2014-11-07 19:10:26.131018871 +0100
> @@ -0,0 +1,17 @@
> +/* Test __builtin_{add,sub}_overflow on {,un}signed long long int.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +typedef signed long long int S;
> +typedef unsigned long long int U;
> +#define COND 1
> +#define SHIFT ((__SIZEOF_LONG_LONG__ - 1) * __CHAR_BIT__)
> +#define S_MAX __LONG_LONG_MAX__
> +#define S_MIN (-__LONG_LONG_MAX__ - 1)
> +#if __SIZEOF_INT128__ > __SIZEOF_LONG_LONG__
> +typedef __int128 W;
> +#else
> +#undef COND
> +#define COND 0
> +#endif
> +#include "builtin-arith-overflow-7.c"
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-12.c.jj	2014-11-07 19:19:14.087548729 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-12.c	2014-11-07 19:19:44.940993939 +0100
> @@ -0,0 +1,17 @@
> +/* Test __builtin_{add,sub,mul_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-12.h"
> +
> +TESTS (int, INT_MIN, INT_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (int, INT_MIN, INT_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-12.h.jj	2014-11-07 19:11:25.549953828 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-12.h	2014-11-10 13:41:24.000000000 +0100
> @@ -0,0 +1,80 @@
> +#include "builtin-arith-overflow.h"
> +
> +#define TESTS(type, min, max) \
> +T (100, signed type, unsigned type, unsigned type, -1, 0, 0, mul, 0) \
> +T (101, signed type, unsigned type, unsigned type, -1, 1, (unsigned type) -1, mul, 1) \
> +T (102, unsigned type, signed type, unsigned type, 12, -3, (unsigned type) -36, mul, 1) \
> +T (103, signed type, unsigned type, unsigned type, 3, 4, 12, mul, 0) \
> +T (104, unsigned type, signed type, unsigned type, (unsigned type) -1 / 12, 12, (unsigned type) -1 / 12 * 12, mul, 0) \
> +T (105, unsigned type, signed type, unsigned type, (unsigned type) -1 / 12, 13, (unsigned type) -1 / 12 * 13, mul, 1) \
> +T (106, unsigned type, unsigned type, signed type, 0, 0, 0, mul, 0) \
> +T (107, unsigned type, unsigned type, signed type, max / 31, 31, (signed type) ((unsigned type) max / 31 * 31), mul, 0) \
> +T (108, unsigned type, unsigned type, signed type, max / 31, 32, (signed type) ((unsigned type) max / 31 * 32), mul, 1) \
> +T (109, unsigned type, unsigned type, signed type, max / 31, 65, (signed type) ((unsigned type) max / 31 * 65), mul, 1) \
> +T (110, signed type, unsigned type, signed type, -1, 7, -7, mul, 0) \
> +T (111, unsigned type, signed type, signed type, 2, min / 2, min, mul, 0) \
> +T (112, signed type, unsigned type, signed type, max / 12, 13, (signed type) ((unsigned type) max / 12 * 13), mul, 1) \
> +T (113, unsigned type, signed type, signed type, (unsigned type) max + 19, 0, 0, mul, 0) \
> +T (114, signed type, unsigned type, signed type, 0, (unsigned type) max + 1, 0, mul, 0) \
> +T (115, unsigned type, signed type, signed type, (unsigned type) max + 1, -1, min, mul, 0) \
> +T (116, signed type, unsigned type, signed type, -1, (unsigned type) max + 2, max, mul, 1) \
> +T (117, signed type, signed type, unsigned type, min / 64, -64, (unsigned type) min, mul, 0) \
> +T (118, signed type, signed type, unsigned type, min / 32, -33, ((unsigned type) max + 1) / 32 * 33, mul, 0) \
> +T (119, signed type, signed type, unsigned type, min / 32, -65, ((unsigned type) max + 1) / 32 * 65, mul, 1) \
> +T (120, signed type, signed type, unsigned type, -1, -1, 1, mul, 0) \
> +T (121, signed type, signed type, unsigned type, 0, 0, 0, mul, 0) \
> +T (122, signed type, signed type, unsigned type, 0, -6, 0, mul, 0) \
> +T (123, signed type, signed type, unsigned type, -15, 0, 0, mul, 0) \
> +T (124, signed type, signed type, unsigned type, -1, 1, ~(unsigned type) 0, mul, 1) \
> +T (125, signed type, signed type, unsigned type, -17, 5, (unsigned type) -17 * 5, mul, 1) \
> +T (126, signed type, signed type, unsigned type, 7, max / 7, max / 7 * 7, mul, 0) \
> +T (127, signed type, signed type, unsigned type, max / 7, 8, (unsigned type) max / 7 * 8, mul, 0) \
> +T (128, signed type, signed type, unsigned type, 15, max / 7, (unsigned type) max / 7 * 15, mul, 1) \
> +T (129, signed type, unsigned type, signed type, min, 5, min + 5, add, 0) \
> +T (130, unsigned type, signed type, signed type, ~(unsigned type) 0, min, max, add, 0) \
> +T (131, signed type, unsigned type, signed type, max, 1, min, add, 1) \
> +T (132, unsigned type, signed type, signed type, max / 2, max / 2 + 1, max, add, 0) \
> +T (133, signed type, unsigned type, signed type, max / 2 + 1, max / 2 + 1, min, add, 1) \
> +T (134, signed type, unsigned type, unsigned type, min, ~(unsigned type) 0, max, add, 0) \
> +T (135, unsigned type, signed type, unsigned type, ~(unsigned type) 0, min + 1, (unsigned type) max + 1, add, 0) \
> +T (136, signed type, unsigned type, unsigned type, 1, ~(unsigned type) 0, 0, add, 1) \
> +T (137, unsigned type, signed type, unsigned type, 2, -3, ~(unsigned type) 0, add, 1) \
> +T (138, signed type, unsigned type, signed type, min, 1, max, sub, 1) \
> +T (139, signed type, unsigned type, signed type, min + 1, 1, min, sub, 0) \
> +T (140, signed type, unsigned type, signed type, max, (unsigned type) max + 1, -1, sub, 0) \
> +T (141, signed type, unsigned type, signed type, max, ~(unsigned type) 0, min, sub, 0) \
> +T (142, signed type, unsigned type, signed type, max - 1, ~(unsigned type) 0, max, sub, 1) \
> +T (143, signed type, unsigned type, unsigned type, -1, 0, ~(unsigned type) 0, sub, 1) \
> +T (144, signed type, unsigned type, unsigned type, -1, ~(unsigned type) 0, 0, sub, 1) \
> +T (145, signed type, unsigned type, unsigned type, min, 0, min, sub, 1) \
> +T (146, signed type, unsigned type, unsigned type, max, max, 0, sub, 0) \
> +T (147, signed type, unsigned type, unsigned type, max, (unsigned type) max + 1, -1, sub, 1) \
> +T (148, signed type, unsigned type, unsigned type, max - 1, max, -1, sub, 1) \
> +T (149, unsigned type, signed type, signed type, 0, max, -max, sub, 0) \
> +T (150, unsigned type, signed type, signed type, (unsigned type) max + 1, 0, min, sub, 1) \
> +T (151, unsigned type, signed type, signed type, (unsigned type) max + 1, 1, max, sub, 0) \
> +T (152, unsigned type, unsigned type, signed type, 0, (unsigned type) max + 1, min, add, 1) \
> +T (153, signed type, signed type, unsigned type, -1, 0, -1, add, 1) \
> +T (154, unsigned type, signed type, unsigned type, 5, 6, -1, sub, 1) \
> +T (155, unsigned type, signed type, unsigned type, ~(unsigned type) 0, max, (unsigned type) max + 1, sub, 0) \
> +T (156, unsigned type, signed type, unsigned type, (unsigned type) max + 1, min, 0, sub, 1) \
> +T (157, signed type, signed type, unsigned type, 3, -2, 1, add, 0) \
> +T (158, signed type, signed type, unsigned type, 3, -4, -1, add, 1) \
> +T (159, signed type, signed type, unsigned type, -3, -4, -7, add, 1) \
> +T (160, signed type, signed type, unsigned type, -5, 4, -1, add, 1) \
> +T (161, signed type, signed type, unsigned type, -5, 5, 0, add, 0) \
> +T (162, signed type, signed type, unsigned type, min, 1, min + 1, add, 1) \
> +T (163, unsigned type, unsigned type, signed type, max, 1, min, add, 1) \
> +T (164, unsigned type, unsigned type, signed type, max - 1, 1, max, add, 0) \
> +T (165, unsigned type, unsigned type, signed type, ~(unsigned type) 0, ~(unsigned type) 0, ~(unsigned type) 0 - 1, add, 1) \
> +T (166, unsigned type, unsigned type, signed type, (unsigned type) max + 3, 2, min, sub, 1) \
> +T (167, unsigned type, unsigned type, signed type, (unsigned type) max + 2, 2, max, sub, 0) \
> +T (168, unsigned type, unsigned type, signed type, (unsigned type) max + 2, (unsigned type) max + 3, -1, sub, 0) \
> +T (169, unsigned type, unsigned type, signed type, 0, (unsigned type) max + 1, min, sub, 0) \
> +T (170, unsigned type, unsigned type, signed type, 0, (unsigned type) max + 2, max, sub, 1) \
> +T (171, signed type, signed type, unsigned type, 3, 2, 1, sub, 0) \
> +T (172, signed type, signed type, unsigned type, 3, 4, -1, sub, 1) \
> +T (173, signed type, signed type, unsigned type, -3, 4, -7, sub, 1) \
> +T (174, signed type, signed type, unsigned type, -5, -4, -1, sub, 1) \
> +T (175, signed type, signed type, unsigned type, -5, -5, 0, sub, 0) \
> +T (176, signed type, signed type, unsigned type, min, -1, min + 1, sub, 1)
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-13.c.jj	2014-11-07 19:19:58.402751898 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-13.c	2014-11-07 19:20:22.219323644 +0100
> @@ -0,0 +1,17 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-12.h"
> +
> +TESTS (long, LONG_MIN, LONG_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (long, LONG_MIN, LONG_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-14.c.jj	2014-11-07 19:20:57.193695507 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-14.c	2014-11-07 19:21:45.937818318 +0100
> @@ -0,0 +1,17 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-12.h"
> +
> +TESTS (long long, LLONG_MIN, LLONG_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (long long, LLONG_MIN, LLONG_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-15.c.jj	2014-11-07 19:21:00.023643833 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-15.c	2014-11-07 19:22:46.606727387 +0100
> @@ -0,0 +1,17 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-12.h"
> +
> +TESTS (char, SCHAR_MIN, SCHAR_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (char, SCHAR_MIN, SCHAR_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-16.c.jj	2014-11-07 19:21:03.116588279 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-16.c	2014-11-07 19:22:39.406856377 +0100
> @@ -0,0 +1,17 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-12.h"
> +
> +TESTS (short, SHRT_MIN, SHRT_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (short, SHRT_MIN, SHRT_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-17.c.jj	2014-11-07 19:22:21.781173435 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-17.c	2014-11-07 19:22:57.811526120 +0100
> @@ -0,0 +1,20 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run { target int128 } } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-12.h"
> +
> +#define INT128_MAX ((signed __int128) (((unsigned __int128) 1 << (__SIZEOF_INT128__ * __CHAR_BIT__ - 1)) - 1))
> +#define INT128_MIN (-INT128_MAX - 1)
> +
> +TESTS (__int128, INT128_MIN, INT128_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (__int128, INT128_MIN, INT128_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-18.c.jj	2014-11-10 15:28:16.953257135 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-18.c	2014-11-10 17:06:18.342709092 +0100
> @@ -0,0 +1,36 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow.h"
> +
> +#ifdef __SIZEOF_INT128__
> +#define WTYPE __int128
> +#else
> +#define WTYPE long long int
> +#endif
> +
> +#define TESTS \
> +T (100, signed char, signed char, unsigned WTYPE, -1, 0, -1, add, 1) \
> +T (101, unsigned char, unsigned char, unsigned WTYPE, 5, 5, 10, add, 0) \
> +T (102, signed char, unsigned short, unsigned WTYPE, 5, 5, 0, sub, 0) \
> +T (103, signed char, unsigned short, unsigned WTYPE, 5, 6, -1, sub, 1) \
> +T (104, signed char, signed char, unsigned WTYPE, -1, -1, 1, mul, 0) \
> +T (105, unsigned char, signed char, unsigned WTYPE, 17, -2, -34, mul, 1) \
> +T (106, unsigned WTYPE, signed WTYPE, signed char, 5, -2, -10, mul, 0) \
> +T (107, long long int, long long int, unsigned char, -3, 5, 2, add, 0) \
> +T (108, long long int, int, unsigned char, -5, 3, -2, add, 1) \
> +T (109, int, WTYPE, unsigned char, -3, 5, 2, add, 0) \
> +T (110, unsigned char, unsigned char, unsigned WTYPE, SCHAR_MAX - 1, (unsigned char) SCHAR_MAX + 4, -5, sub, 1)
> +
> +TESTS
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-1.c.jj	2014-11-03 18:40:54.074461851 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-1.c	2014-11-07 19:10:26.131018871 +0100
> @@ -0,0 +1,24 @@
> +/* Test __builtin_{add,sub,mul,{s,u}add,{s,u}sub,{s,u}mul}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-1.h"
> +
> +#define U(s, op) s##op
> +TESTS (int, INT_MIN, INT_MAX)
> +#undef U
> +#define U(s, op) op
> +TESTS (int, INT_MIN, INT_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (int, INT_MIN, INT_MAX)
> +#undef U
> +#define U(s, op) s##op
> +  TESTS (int, INT_MIN, INT_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-1.h.jj	2014-11-03 18:36:56.604776189 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-1.h	2014-11-03 19:22:18.789374761 +0100
> @@ -0,0 +1,37 @@
> +#include "builtin-arith-overflow.h"
> +
> +#define TESTS(type, min, max) \
> +ST (100, signed type, 2, 3, 5, U(s, add), 0) \
> +ST (101, signed type, max, -1, max - 1, U(s, add), 0) \
> +ST (102, signed type, max, 0, max, U(s, add), 0) \
> +ST (103, signed type, 1, max, min, U(s, add), 1) \
> +ST (104, signed type, 0, min, min, U(s, sub), 1) \
> +ST (110, signed type, 2, 3, -1, U(s, sub), 0) \
> +ST (111, signed type, max, -1, min, U(s, sub), 1) \
> +ST (112, signed type, max, 0, max, U(s, sub), 0) \
> +ST (113, signed type, 1, max, min + 2, U(s, sub), 0) \
> +ST (114, signed type, max, -1, min, U(s, sub), 1) \
> +ST (120, signed type, 2, 3, 6, U(s, mul), 0) \
> +ST (122, signed type, min, -1, min, U(s, mul), 1) \
> +ST (123, signed type, max, 0, 0, U(s, mul), 0) \
> +ST (124, signed type, 1, max, max, U(s, mul), 0) \
> +ST (125, signed type, max, 2, -2, U(s, mul), 1) \
> +ST (126, signed type, max / 25, 25, max / 25 * 25, U(s, mul), 0) \
> +ST (127, signed type, max / 25 + 1, 25, max / 25 * 25 + (unsigned type) 25, U(s, mul), 1) \
> +ST (150, unsigned type, 2, 3, 5, U(u, add), 0) \
> +ST (151, unsigned type, -1, -1, -2, U(u, add), 1) \
> +ST (152, unsigned type, -1, 0, -1, U(u, add), 0) \
> +ST (153, unsigned type, 1, -1, 0, U(u, add), 1) \
> +ST (154, unsigned type, 0, min, min, U(u, sub), 1) \
> +ST (160, unsigned type, 2, 3, -1, U(u, sub), 1) \
> +ST (161, unsigned type, -1, -1, 0, U(u, sub), 0) \
> +ST (162, unsigned type, -1, 0, -1, U(u, sub), 0) \
> +ST (163, unsigned type, 1, -1, 2, U(u, sub), 1) \
> +ST (164, unsigned type, 15, 14, 1, U(u, sub), 0) \
> +ST (170, unsigned type, 2, 3, 6, U(u, mul), 0) \
> +ST (171, unsigned type, max, 3, 3 * (unsigned type) max, U(u, mul), 1) \
> +ST (172, unsigned type, -1, 0, 0, U(u, mul), 0) \
> +ST (173, unsigned type, 1, -1, -1, U(u, mul), 0) \
> +ST (174, unsigned type, -1, 2, -2, U(u, mul), 1) \
> +ST (175, unsigned type, ((unsigned type) -1) / 25, 25, ((unsigned type) -1) / 25 * 25, U(u, mul), 0) \
> +ST (176, unsigned type, ((unsigned type) -1) / 25 + 1, 25, ((unsigned type) -1) / 25 * 25 + (unsigned type) 25, U(u, mul), 1)
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-2.c.jj	2014-11-03 18:44:53.490111010 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-2.c	2014-11-07 19:10:26.131018871 +0100
> @@ -0,0 +1,24 @@
> +/* Test __builtin_{add,sub,mul,{s,u}addl,{s,u}subl,{s,u}mull}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-1.h"
> +
> +#define U(s, op) s##op##l
> +TESTS (long, LONG_MIN, LONG_MAX)
> +#undef U
> +#define U(s, op) op
> +TESTS (long, LONG_MIN, LONG_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (long, LONG_MIN, LONG_MAX)
> +#undef U
> +#define U(s, op) s##op##l
> +  TESTS (long, LONG_MIN, LONG_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-3.c.jj	2014-11-03 18:45:41.585236605 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-3.c	2014-11-07 19:10:26.132018853 +0100
> @@ -0,0 +1,24 @@
> +/* Test __builtin_{add,sub,mul,{s,u}addll,{s,u}subll,{s,u}mulll}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-1.h"
> +
> +#define U(s, op) s##op##ll
> +TESTS (long long, LLONG_MIN, LLONG_MAX)
> +#undef U
> +#define U(s, op) op
> +TESTS (long long, LLONG_MIN, LLONG_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (long long, LLONG_MIN, LLONG_MAX)
> +#undef U
> +#define U(s, op) s##op##ll
> +  TESTS (long long, LLONG_MIN, LLONG_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-4.c.jj	2014-11-03 19:09:34.330185643 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-4.c	2014-11-07 19:10:26.132018853 +0100
> @@ -0,0 +1,18 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-1.h"
> +
> +#define U(s, op) op
> +TESTS (char, SCHAR_MIN, SCHAR_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (char, SCHAR_MIN, SCHAR_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-5.c.jj	2014-11-03 19:11:00.427620935 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-5.c	2014-11-07 19:10:26.132018853 +0100
> @@ -0,0 +1,18 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-1.h"
> +
> +#define U(s, op) op
> +TESTS (short, SHRT_MIN, SHRT_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (short, SHRT_MIN, SHRT_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-6.c.jj	2014-11-03 19:27:55.763293162 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-6.c	2014-11-07 19:10:26.133018835 +0100
> @@ -0,0 +1,21 @@
> +/* Test __builtin_{add,sub,mul}_overflow.  */
> +/* { dg-do run { target int128 } } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#include "builtin-arith-overflow-1.h"
> +
> +#define INT128_MAX ((signed __int128) (((unsigned __int128) 1 << (__SIZEOF_INT128__ * __CHAR_BIT__ - 1)) - 1))
> +#define INT128_MIN (-INT128_MAX - 1)
> +
> +#define U(s, op) op
> +TESTS (__int128, INT128_MIN, INT128_MAX)
> +
> +#undef T
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
> +
> +int
> +main ()
> +{
> +  TESTS (__int128, INT128_MIN, INT128_MAX)
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-7.c.jj	2014-11-05 10:55:31.370621720 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-7.c	2014-11-07 19:10:26.133018835 +0100
> @@ -0,0 +1,80 @@
> +/* Test __builtin_{add,sub}_overflow on {,un}signed char.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +#define UCHAR_MAX ((unsigned char) ~0)
> +#ifndef SHIFT
> +typedef signed char S;
> +typedef unsigned char U;
> +typedef int W;
> +#define SHIFT 0
> +#define S_MAX __SCHAR_MAX__
> +#define S_MIN (-__SCHAR_MAX__ - 1)
> +#define COND (__SIZEOF_INT__ > 1)
> +#endif
> +
> +#define F(n, t1, t2, tr, b) \
> +__attribute__((noinline, noclone)) tr		\
> +n (t1 x, t2 y, int *ovf)			\
> +{						\
> +  tr res;					\
> +  *ovf = __builtin_##b##_overflow (x, y, &res);	\
> +  return res;					\
> +}
> +
> +F (spses, S, S, S, add)
> +F (upueu, U, U, U, add)
> +F (spseu, S, S, U, add)
> +F (upues, U, U, S, add)
> +F (spues, S, U, S, add)
> +F (upses, U, S, S, add)
> +F (spueu, S, U, U, add)
> +F (upseu, U, S, U, add)
> +F (ssses, S, S, S, sub)
> +F (usueu, U, U, U, sub)
> +F (ssseu, S, S, U, sub)
> +F (usues, U, U, S, sub)
> +F (ssues, S, U, S, sub)
> +F (usses, U, S, S, sub)
> +F (ssueu, S, U, U, sub)
> +F (usseu, U, S, U, sub)
> +
> +int
> +main ()
> +{
> +#if COND
> +  int i, j;
> +  for (i = 0; i < UCHAR_MAX; i++)
> +    for (j = 0; j < UCHAR_MAX; j++)
> +      {
> +	S s1 = ((W) i << SHIFT) + S_MIN;
> +	U u1 = ((W) i << SHIFT);
> +	S s2 = ((W) j << SHIFT) + S_MIN;
> +	U u2 = ((W) j << SHIFT);
> +	W w;
> +	int ovf;
> +#define T(n, t1, t2, tr, op) \
> +	w = ((W) t1##1) op ((W) t2##2);		\
> +	if (n (t1##1, t2##2, &ovf) != (tr) w	\
> +	    || ovf != (w != (tr) w))		\
> +	  __builtin_abort ();
> +	T (spses, s, s, S, +)
> +	T (upueu, u, u, U, +)
> +	T (spseu, s, s, U, +)
> +	T (upues, u, u, S, +)
> +	T (spues, s, u, S, +)
> +	T (upses, u, s, S, +)
> +	T (spueu, s, u, U, +)
> +	T (upseu, u, s, U, +)
> +	T (ssses, s, s, S, -)
> +	T (usueu, u, u, U, -)
> +	T (ssseu, s, s, U, -)
> +	T (usues, u, u, S, -)
> +	T (ssues, s, u, S, -)
> +	T (usses, u, s, S, -)
> +	T (ssueu, s, u, U, -)
> +	T (usseu, u, s, U, -)
> +      }
> +#endif
> +  return 0;
> +}
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-8.c.jj	2014-11-05 10:56:19.418748918 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-8.c	2014-11-07 19:10:26.134018817 +0100
> @@ -0,0 +1,23 @@
> +/* Test __builtin_{add,sub}_overflow on {,un}signed short.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +typedef signed short int S;
> +typedef unsigned short int U;
> +#define COND 1
> +#define SHIFT ((__SIZEOF_SHORT__ - 1) * __CHAR_BIT__)
> +#define S_MAX __SHRT_MAX__
> +#define S_MIN (-__SHRT_MAX__ - 1)
> +#if __SIZEOF_INT__ > __SIZEOF_SHORT__
> +typedef int W;
> +#elif __SIZEOF_LONG__ > __SIZEOF_SHORT__
> +typedef long int W;
> +#elif __SIZEOF_LONG_LONG__ > __SIZEOF_SHORT__
> +typedef long long int W;
> +#elif __SIZEOF_INT128__ > __SIZEOF_SHORT__
> +typedef __int128 W;
> +#else
> +#undef COND
> +#define COND 0
> +#endif
> +#include "builtin-arith-overflow-7.c"
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-9.c.jj	2014-11-05 11:03:40.760743270 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-9.c	2014-11-07 19:10:26.134018817 +0100
> @@ -0,0 +1,21 @@
> +/* Test __builtin_{add,sub}_overflow on {,un}signed int.  */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +
> +typedef signed int S;
> +typedef unsigned int U;
> +#define COND 1
> +#define SHIFT ((__SIZEOF_INT__ - 1) * __CHAR_BIT__)
> +#define S_MAX __INT_MAX__
> +#define S_MIN (-__INT_MAX__ - 1)
> +#if __SIZEOF_LONG__ > __SIZEOF_INT__
> +typedef long int W;
> +#elif __SIZEOF_LONG_LONG__ > __SIZEOF_INT__
> +typedef long long int W;
> +#elif __SIZEOF_INT128__ > __SIZEOF_INT__
> +typedef __int128 W;
> +#else
> +#undef COND
> +#define COND 0
> +#endif
> +#include "builtin-arith-overflow-7.c"
> --- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow.h.jj	2014-11-03 18:36:53.701831741 +0100
> +++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow.h	2014-11-03 19:05:15.441885624 +0100
> @@ -0,0 +1,94 @@
> +#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)
> +#define LONG_MAX __LONG_MAX__
> +#define LONG_MIN (-__LONG_MAX__ - 1)
> +#define LLONG_MAX __LONG_LONG_MAX__
> +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1)
> +
> +int v;
> +
> +__attribute__((noinline, noclone)) void
> +bar (void)
> +{
> +  v++;
> +}
> +
> +#define T(n, t1, t2, tr, v1, v2, vr, b, o) \
> +__attribute__((noinline, noclone)) tr		\
> +t##n##_1##b (t1 x, t2 y)			\
> +{						\
> +  tr r;						\
> +  if (__builtin_##b##_overflow (x, y, &r))	\
> +    bar ();					\
> +  return r;					\
> +}						\
> +						\
> +__attribute__((noinline, noclone)) tr		\
> +t##n##_2##b (t2 y)				\
> +{						\
> +  t1 x = (v1);					\
> +  tr r;						\
> +  if (__builtin_##b##_overflow (x, y, &r))	\
> +    bar ();					\
> +  return r;					\
> +}						\
> +						\
> +__attribute__((noinline, noclone)) tr		\
> +t##n##_3##b (t2 y)				\
> +{						\
> +  tr r;						\
> +  if (__builtin_##b##_overflow ((t1) (v1), y,	\
> +				&r))		\
> +    bar ();					\
> +  return r;					\
> +}						\
> +						\
> +__attribute__((noinline, noclone)) tr		\
> +t##n##_4##b (t1 x)				\
> +{						\
> +  t2 y = (v2);					\
> +  tr r;						\
> +  if (__builtin_##b##_overflow (x, y, &r))	\
> +    bar ();					\
> +  return r;					\
> +}						\
> +						\
> +__attribute__((noinline, noclone)) tr		\
> +t##n##_5##b (t1 x)				\
> +{						\
> +  tr r;						\
> +  if (__builtin_##b##_overflow (x, (t2) (v2),	\
> +				&r))		\
> +    bar ();					\
> +  return r;					\
> +}						\
> +						\
> +__attribute__((noinline, noclone)) void		\
> +t##n##b (void)					\
> +{						\
> +  t1 x = (v1);					\
> +  t2 y = (v2);					\
> +  tr r1, r2;					\
> +  v = 0;					\
> +  if (t##n##_1##b (x, y) != (tr) (vr)		\
> +      || t##n##_2##b (y) != (tr) (vr)		\
> +      || t##n##_3##b (y) != (tr) (vr)		\
> +      || t##n##_4##b (x) != (tr) (vr)		\
> +      || t##n##_5##b (x) != (tr) (vr))		\
> +    __builtin_abort ();				\
> +  if (__builtin_##b##_overflow (x, y, &r1))	\
> +    bar ();					\
> +  if (r1 != (tr) (vr))				\
> +    __builtin_abort ();				\
> +  if (__builtin_##b##_overflow ((t1) (v1),	\
> +				(t2) (v2), &r2))\
> +    bar ();					\
> +  if (r2 != (tr) (vr) || v != 7 * o)		\
> +    __builtin_abort ();				\
> +}
> +#define ST(n, t, v1, v2, vr, b, o) \
> +T (n, t, t, t, v1, v2, vr, b, o)
> --- gcc/testsuite/gcc.dg/builtin-arith-overflow-1.c.jj	2014-11-07 16:41:14.558730074 +0100
> +++ gcc/testsuite/gcc.dg/builtin-arith-overflow-1.c	2014-11-07 17:27:16.631821188 +0100
> @@ -0,0 +1,132 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fdump-tree-optimized -g" } */
> +
> +/* SUB_OVERFLOW should be folded into unsigned subtraction,
> +   because ovf is never used.  */
> +__attribute__((noinline, noclone)) int
> +fn1 (int x, unsigned int y)
> +{
> +  int res;
> +  int ovf = __builtin_sub_overflow (x, y, &res);
> +  int res2 = res;
> +  int res3 = res2 - 2;
> +  (void) ovf;
> +  return res;
> +}
> +
> +/* MUL_OVERFLOW should be folded into unsigned multiplication,
> +   because ovf is never used.  */
> +__attribute__((noinline, noclone)) int
> +fn2 (char x, long int y)
> +{
> +  short int res;
> +  int ovf = __builtin_mul_overflow (x, y, &res);
> +  int res2 = res;
> +  int res3 = res2 - 2;
> +  (void) ovf;
> +  return res;
> +}
> +
> +#if __SIZEOF_INT__ > __SIZEOF_SHORT__ && __SIZEOF_INT__ > 1
> +/* ADD_OVERFLOW should be folded into unsigned addition,
> +   because it never overflows.  */
> +__attribute__((noinline, noclone)) int
> +fn3 (char x, unsigned short y, int *ovf)
> +{
> +  int res;
> +  *ovf = __builtin_add_overflow (x, y, &res);
> +  return res;
> +}
> +#endif
> +
> +/* MUL_OVERFLOW should be folded into unsigned multiplication,
> +   because it never overflows.  */
> +__attribute__((noinline, noclone)) long int
> +fn4 (long int x, long int y, int *ovf)
> +{
> +  long int res;
> +  x &= 65535;
> +  y = (y & 65535) - 32768;
> +  *ovf = __builtin_mul_overflow (x, y, &res);
> +  return res;
> +}
> +
> +#if __SIZEOF_INT__ > 1
> +/* MUL_OVERFLOW should be folded into unsigned multiplication,
> +   because it always overflows.  */
> +__attribute__((noinline, noclone)) signed char
> +fn5 (long int x, long int y, int *ovf)
> +{
> +  signed char res;
> +  x = (x & 63) + (__SCHAR_MAX__ / 4);
> +  y = (y & 3) + 5;
> +  *ovf = __builtin_mul_overflow (x, y, &res);
> +  return res;
> +}
> +#endif
> +
> +/* ADD_OVERFLOW should be folded into unsigned additrion,
> +   because it never overflows.  */
> +__attribute__((noinline, noclone)) unsigned char
> +fn6 (unsigned char x, unsigned char y, int *ovf)
> +{
> +  unsigned char res;
> +  x = (x & 63) + ((unsigned char) ~0 - 66);
> +  y = (y & 3);
> +  *ovf = __builtin_add_overflow (x, y, &res);
> +  return res;
> +}
> +
> +/* ADD_OVERFLOW should be folded into unsigned additrion,
> +   because it always overflows.  */
> +__attribute__((noinline, noclone)) unsigned char
> +fn7 (unsigned char x, unsigned char y, int *ovf)
> +{
> +  unsigned char res;
> +  x = (x & 15) + ((unsigned char) ~0 - 15);
> +  y = (y & 3) + 16;
> +  *ovf = __builtin_add_overflow (x, y, &res);
> +  return res;
> +}
> +
> +int
> +main ()
> +{
> +  int ovf;
> +  if (fn1 (-10, __INT_MAX__) != (int) (-10U - __INT_MAX__)
> +      || fn2 (0, 0) != 0
> +      || fn2 (32, 16383) != (short int) 524256ULL)
> +    __builtin_abort ();
> +#if __SIZEOF_INT__ > __SIZEOF_SHORT__ && __SIZEOF_INT__ > 1
> +  if (fn3 (__SCHAR_MAX__, (unsigned short) ~0, &ovf) != (int) (__SCHAR_MAX__ + (unsigned short) ~0)
> +      || ovf
> +      || fn3 (-__SCHAR_MAX__ - 1, 0, &ovf) != (int) (-__SCHAR_MAX__ - 1)
> +      || ovf)
> +    __builtin_abort ();
> +#endif
> +  if (fn4 (65535, 0, &ovf) != 65535L * -32768 || ovf)
> +    __builtin_abort ();
> +#if __SIZEOF_INT__ > 1
> +  if (fn5 (0, 0, &ovf) != (signed char) (__SCHAR_MAX__ / 4 * 5)
> +      || !ovf
> +      || fn5 (63, 3, &ovf) != (signed char) ((__SCHAR_MAX__ / 4 + 63) * 8)
> +      || !ovf)
> +    __builtin_abort ();
> +#endif
> +  if (fn6 (0, 0, &ovf) != (unsigned char) ~0 - 66
> +      || ovf
> +      || fn6 (63, 3, &ovf) != (unsigned char) ~0
> +      || ovf)
> +    __builtin_abort ();
> +  if (fn7 (0, 0, &ovf) != 0
> +      || !ovf
> +      || fn7 (63, 3, &ovf) != 18
> +      || !ovf)
> +    __builtin_abort ();
> +  return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-not "ADD_OVERFLOW" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "SUB_OVERFLOW" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "MUL_OVERFLOW" "optimized" } } */
> +/* { dg-final { cleanup-tree-dump "optimized" } } */
> --- gcc/testsuite/gcc.dg/builtin-arith-overflow-2.c.jj	2014-11-07 17:06:35.695212103 +0100
> +++ gcc/testsuite/gcc.dg/builtin-arith-overflow-2.c	2014-11-10 18:04:00.819605719 +0100
> @@ -0,0 +1,110 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +/* MUL_OVERFLOW should not be folded into unsigned multiplication,
> +   because it sometimes overflows and sometimes does not.  */
> +__attribute__((noinline, noclone)) long int
> +fn1 (long int x, long int y, int *ovf)
> +{
> +  long int res;
> +  x &= 65535;
> +  y = (y & 65535) - (__LONG_MAX__ / 65535 + 32768);
> +  *ovf = __builtin_mul_overflow (x, y, &res);
> +  return res;
> +}
> +
> +/* MUL_OVERFLOW should not be folded into unsigned multiplication,
> +   because it sometimes overflows and sometimes does not.  */
> +__attribute__((noinline, noclone)) signed char
> +fn2 (long int x, long int y, int *ovf)
> +{
> +  signed char res;
> +  x = (x & 63) + (__SCHAR_MAX__ / 4);
> +  y = (y & 3) + 4;
> +  *ovf = __builtin_mul_overflow (x, y, &res);
> +  return res;
> +}
> +
> +/* ADD_OVERFLOW should be folded into unsigned additrion,
> +   because it sometimes overflows and sometimes does not.  */
> +__attribute__((noinline, noclone)) unsigned char
> +fn3 (unsigned char x, unsigned char y, int *ovf)
> +{
> +  unsigned char res;
> +  x = (x & 63) + ((unsigned char) ~0 - 65);
> +  y = (y & 3);
> +  *ovf = __builtin_add_overflow (x, y, &res);
> +  return res;
> +}
> +
> +/* ADD_OVERFLOW should be folded into unsigned additrion,
> +   because it sometimes overflows and sometimes does not.  */
> +__attribute__((noinline, noclone)) unsigned char
> +fn4 (unsigned char x, unsigned char y, int *ovf)
> +{
> +  unsigned char res;
> +  x = (x & 15) + ((unsigned char) ~0 - 16);
> +  y = (y & 3) + 16;
> +  *ovf = __builtin_add_overflow (x, y, &res);
> +  return res;
> +}
> +
> +/* MUL_OVERFLOW should not be folded into unsigned multiplication,
> +   because it sometimes overflows and sometimes does not.  */
> +__attribute__((noinline, noclone)) long int
> +fn5 (long int x, unsigned long int y, int *ovf)
> +{
> +  long int res;
> +  y = -65536UL + (y & 65535);
> +  *ovf = __builtin_mul_overflow (x, y, &res);
> +  return res;
> +}
> +
> +int
> +main ()
> +{
> +  int ovf;
> +  if (fn1 (0, 0, &ovf) != 0
> +      || ovf
> +      || fn1 (65535, 0, &ovf) != (long int) ((__LONG_MAX__ / 65535 + 32768UL) * -65535UL)
> +      || !ovf)
> +    __builtin_abort ();
> +  if (fn2 (0, 0, &ovf) != (signed char) (__SCHAR_MAX__ / 4 * 4U)
> +      || ovf
> +      || fn2 (0, 1, &ovf) != (signed char) (__SCHAR_MAX__ / 4 * 5U)
> +      || !ovf)
> +    __builtin_abort ();
> +  if (fn3 (0, 0, &ovf) != (unsigned char) ~0 - 65
> +      || ovf
> +      || fn3 (63, 2, &ovf) != (unsigned char) ~0
> +      || ovf
> +      || fn3 (62, 3, &ovf) != (unsigned char) ~0
> +      || ovf
> +      || fn3 (63, 3, &ovf) != 0
> +      || !ovf)
> +    __builtin_abort ();
> +  if (fn4 (0, 0, &ovf) != (unsigned char) ~0
> +      || ovf
> +      || fn4 (1, 0, &ovf) != 0
> +      || !ovf
> +      || fn4 (0, 1, &ovf) != 0
> +      || !ovf
> +      || fn4 (63, 3, &ovf) != 17
> +      || !ovf)
> +    __builtin_abort ();
> +  if (fn5 (0, 0, &ovf) != 0
> +      || ovf
> +      || fn5 (1, 0, &ovf) != -65536L
> +      || !ovf
> +      || fn5 (2, 32768, &ovf) != -65536L
> +      || !ovf
> +      || fn5 (4, 32768 + 16384 + 8192, &ovf) != -32768L
> +      || !ovf)
> +    __builtin_abort ();
> +  return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 2 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 0 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "MUL_OVERFLOW" 3 "optimized" } } */
> +/* { dg-final { cleanup-tree-dump "optimized" } } */
> 
> 	Jakub
> 
>
diff mbox

Patch

--- gcc/builtin-attrs.def.jj	2014-01-03 11:40:35.000000000 +0100
+++ gcc/builtin-attrs.def	2014-10-30 14:57:07.696883004 +0100
@@ -178,6 +178,9 @@  DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL
 /* Nothrow functions whose fifth parameter is a nonnull pointer.  */
 DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_5, ATTR_NONNULL, ATTR_LIST_5, \
 			ATTR_NOTHROW_LIST)
+/* Nothrow leaf functions which are type-generic.  */
+DEF_ATTR_TREE_LIST (ATTR_NOTHROW_TYPEGENERIC_LEAF, ATTR_TYPEGENERIC, ATTR_NULL, \
+			ATTR_NOTHROW_LEAF_LIST)
 /* Nothrow const functions whose pointer parameter(s) are all nonnull.  */
 DEF_ATTR_TREE_LIST (ATTR_CONST_NOTHROW_NONNULL, ATTR_CONST, ATTR_NULL, \
 			ATTR_NOTHROW_NONNULL)
--- gcc/builtins.c.jj	2014-10-30 14:42:22.000000000 +0100
+++ gcc/builtins.c	2014-11-05 16:19:43.728949900 +0100
@@ -9652,6 +9652,62 @@  fold_builtin_unordered_cmp (location_t l
 		      fold_build2_loc (loc, code, type, arg0, arg1));
 }
 
+/* Fold __builtin_{,s,u}{add,sub,mul}{,l,ll}_overflow, either into normal
+   arithmetics if it can never overflow, or into internal functions that
+   return both result of arithmetics and overflowed boolean flag in
+   a complex integer result, or some other check for overflow.  */
+
+static tree
+fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
+			     tree arg0, tree arg1, tree arg2)
+{
+  enum internal_fn ifn = IFN_LAST;
+  tree type = TREE_TYPE (TREE_TYPE (arg2));
+  tree mem_arg2 = build_fold_indirect_ref_loc (loc, arg2);
+  switch (fcode)
+    {
+    case BUILT_IN_ADD_OVERFLOW:
+    case BUILT_IN_SADD_OVERFLOW:
+    case BUILT_IN_SADDL_OVERFLOW:
+    case BUILT_IN_SADDLL_OVERFLOW:
+    case BUILT_IN_UADD_OVERFLOW:
+    case BUILT_IN_UADDL_OVERFLOW:
+    case BUILT_IN_UADDLL_OVERFLOW:
+      ifn = IFN_ADD_OVERFLOW;
+      break;
+    case BUILT_IN_SUB_OVERFLOW:
+    case BUILT_IN_SSUB_OVERFLOW:
+    case BUILT_IN_SSUBL_OVERFLOW:
+    case BUILT_IN_SSUBLL_OVERFLOW:
+    case BUILT_IN_USUB_OVERFLOW:
+    case BUILT_IN_USUBL_OVERFLOW:
+    case BUILT_IN_USUBLL_OVERFLOW:
+      ifn = IFN_SUB_OVERFLOW;
+      break;
+    case BUILT_IN_MUL_OVERFLOW:
+    case BUILT_IN_SMUL_OVERFLOW:
+    case BUILT_IN_SMULL_OVERFLOW:
+    case BUILT_IN_SMULLL_OVERFLOW:
+    case BUILT_IN_UMUL_OVERFLOW:
+    case BUILT_IN_UMULL_OVERFLOW:
+    case BUILT_IN_UMULLL_OVERFLOW:
+      ifn = IFN_MUL_OVERFLOW;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  tree ctype = build_complex_type (type);
+  tree call = build_call_expr_internal_loc (loc, ifn, ctype,
+					    2, arg0, arg1);
+  tree tgt = save_expr (call);
+  tree intres = build1_loc (loc, REALPART_EXPR, type, tgt);
+  tree ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt);
+  ovfres = fold_convert_loc (loc, boolean_type_node, ovfres);
+  tree store
+    = fold_build2_loc (loc, MODIFY_EXPR, void_type_node, mem_arg2, intres);
+  return build2_loc (loc, COMPOUND_EXPR, boolean_type_node, store, ovfres);
+}
+
 /* Fold a call to built-in function FNDECL with 0 arguments.
    IGNORE is true if the result of the function call is ignored.  This
    function returns NULL_TREE if no simplification was possible.  */
@@ -10359,6 +10415,29 @@  fold_builtin_3 (location_t loc, tree fnd
     case BUILT_IN_EXPECT:
       return fold_builtin_expect (loc, arg0, arg1, arg2);
 
+    case BUILT_IN_ADD_OVERFLOW:
+    case BUILT_IN_SUB_OVERFLOW:
+    case BUILT_IN_MUL_OVERFLOW:
+    case BUILT_IN_SADD_OVERFLOW:
+    case BUILT_IN_SADDL_OVERFLOW:
+    case BUILT_IN_SADDLL_OVERFLOW:
+    case BUILT_IN_SSUB_OVERFLOW:
+    case BUILT_IN_SSUBL_OVERFLOW:
+    case BUILT_IN_SSUBLL_OVERFLOW:
+    case BUILT_IN_SMUL_OVERFLOW:
+    case BUILT_IN_SMULL_OVERFLOW:
+    case BUILT_IN_SMULLL_OVERFLOW:
+    case BUILT_IN_UADD_OVERFLOW:
+    case BUILT_IN_UADDL_OVERFLOW:
+    case BUILT_IN_UADDLL_OVERFLOW:
+    case BUILT_IN_USUB_OVERFLOW:
+    case BUILT_IN_USUBL_OVERFLOW:
+    case BUILT_IN_USUBLL_OVERFLOW:
+    case BUILT_IN_UMUL_OVERFLOW:
+    case BUILT_IN_UMULL_OVERFLOW:
+    case BUILT_IN_UMULLL_OVERFLOW:
+      return fold_builtin_arith_overflow (loc, fcode, arg0, arg1, arg2);
+
     default:
       break;
     }
--- gcc/builtins.def.jj	2014-07-08 11:35:59.000000000 +0200
+++ gcc/builtins.def	2014-10-31 08:23:57.202451020 +0100
@@ -665,6 +665,30 @@  DEF_C94_BUILTIN        (BUILT_IN_ISWXDIG
 DEF_C94_BUILTIN        (BUILT_IN_TOWLOWER, "towlower", BT_FN_WINT_WINT, ATTR_PURE_NOTHROW_LEAF_LIST)
 DEF_C94_BUILTIN        (BUILT_IN_TOWUPPER, "towupper", BT_FN_WINT_WINT, ATTR_PURE_NOTHROW_LEAF_LIST)
 
+/* Category: integer overflow checking builtins.  */
+DEF_GCC_BUILTIN        (BUILT_IN_ADD_OVERFLOW, "add_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
+DEF_GCC_BUILTIN        (BUILT_IN_SUB_OVERFLOW, "sub_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
+DEF_GCC_BUILTIN        (BUILT_IN_MUL_OVERFLOW, "mul_overflow", BT_FN_BOOL_VAR, ATTR_NOTHROW_TYPEGENERIC_LEAF)
+/* Clang compatibility.  */
+DEF_GCC_BUILTIN        (BUILT_IN_SADD_OVERFLOW, "sadd_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SADDL_OVERFLOW, "saddl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SADDLL_OVERFLOW, "saddll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUB_OVERFLOW, "ssub_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUBL_OVERFLOW, "ssubl_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SSUBLL_OVERFLOW, "ssubll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMUL_OVERFLOW, "smul_overflow", BT_FN_BOOL_INT_INT_INTPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMULL_OVERFLOW, "smull_overflow", BT_FN_BOOL_LONG_LONG_LONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_SMULLL_OVERFLOW, "smulll_overflow", BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADD_OVERFLOW, "uadd_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADDL_OVERFLOW, "uaddl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UADDLL_OVERFLOW, "uaddll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUB_OVERFLOW, "usub_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUBL_OVERFLOW, "usubl_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_USUBLL_OVERFLOW, "usubll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMUL_OVERFLOW, "umul_overflow", BT_FN_BOOL_UINT_UINT_UINTPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMULL_OVERFLOW, "umull_overflow", BT_FN_BOOL_ULONG_ULONG_ULONGPTR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_UMULLL_OVERFLOW, "umulll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
+
 /* Category: miscellaneous builtins.  */
 DEF_LIB_BUILTIN        (BUILT_IN_ABORT, "abort", BT_FN_VOID, ATTR_NORETURN_NOTHROW_LEAF_LIST)
 DEF_LIB_BUILTIN        (BUILT_IN_ABS, "abs", BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
--- gcc/builtin-types.def.jj	2014-10-15 12:28:19.000000000 +0200
+++ gcc/builtin-types.def	2014-10-31 08:25:08.801128373 +0100
@@ -126,7 +126,10 @@  DEF_PRIMITIVE_TYPE (BT_I16, builtin_type
 DEF_PRIMITIVE_TYPE (BT_BND, pointer_bounds_type_node)
 
 DEF_POINTER_TYPE (BT_PTR_CONST_STRING, BT_CONST_STRING)
+DEF_POINTER_TYPE (BT_PTR_UINT, BT_UINT)
 DEF_POINTER_TYPE (BT_PTR_LONG, BT_LONG)
+DEF_POINTER_TYPE (BT_PTR_ULONG, BT_ULONG)
+DEF_POINTER_TYPE (BT_PTR_LONGLONG, BT_LONGLONG)
 DEF_POINTER_TYPE (BT_PTR_ULONGLONG, BT_ULONGLONG)
 DEF_POINTER_TYPE (BT_PTR_PTR, BT_PTR)
 
@@ -435,6 +438,18 @@  DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I16
 DEF_FUNCTION_TYPE_3 (BT_FN_INT_PTRPTR_SIZE_SIZE, BT_INT, BT_PTR_PTR, BT_SIZE, BT_SIZE)
 DEF_FUNCTION_TYPE_3 (BT_FN_PTR_CONST_PTR_CONST_PTR_SIZE, BT_PTR, BT_CONST_PTR, BT_CONST_PTR, BT_SIZE)
 DEF_FUNCTION_TYPE_3 (BT_FN_VOID_CONST_PTR_BND_CONST_PTR, BT_VOID, BT_CONST_PTR, BT_BND, BT_CONST_PTR)
+DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_INT_INT_INTPTR, BT_BOOL, BT_INT, BT_INT,
+		     BT_INT_PTR)
+DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_LONG_LONG_LONGPTR, BT_BOOL, BT_LONG, BT_LONG,
+		     BT_PTR_LONG)
+DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_LONGLONG_LONGLONG_LONGLONGPTR, BT_BOOL,
+		     BT_LONGLONG, BT_LONGLONG, BT_PTR_LONGLONG)
+DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_UINT_UINT_UINTPTR, BT_BOOL, BT_UINT, BT_UINT,
+		     BT_PTR_UINT)
+DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_ULONG_ULONG_ULONGPTR, BT_BOOL, BT_ULONG,
+		     BT_ULONG, BT_PTR_ULONG)
+DEF_FUNCTION_TYPE_3 (BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, BT_BOOL,
+		     BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG)
 
 DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR,
 		     BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR)
@@ -532,6 +547,7 @@  DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PT
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT)
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_PTR_VAR, BT_PTR)
+DEF_FUNCTION_TYPE_VAR_0 (BT_FN_BOOL_VAR, BT_BOOL)
 
 DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_VALIST_REF_VAR,
 			 BT_VOID, BT_VALIST_REF)
--- gcc/expr.c.jj	2014-10-30 14:42:23.000000000 +0100
+++ gcc/expr.c	2014-10-30 18:00:24.922852651 +0100
@@ -165,7 +165,6 @@  static void emit_single_push_insn (machi
 #endif
 static void do_tablejump (rtx, machine_mode, rtx, rtx, rtx, int);
 static rtx const_vector_from_tree (tree);
-static void write_complex_part (rtx, rtx, bool);
 
 /* This macro is used to determine whether move_by_pieces should be called
    to perform a structure copy.  */
@@ -3018,7 +3017,7 @@  set_storage_via_setmem (rtx object, rtx
 /* Write to one of the components of the complex value CPLX.  Write VAL to
    the real part if IMAG_P is false, and the imaginary part if its true.  */
 
-static void
+void
 write_complex_part (rtx cplx, rtx val, bool imag_p)
 {
   machine_mode cmode;
--- gcc/expr.h.jj	2014-10-30 14:42:23.000000000 +0100
+++ gcc/expr.h	2014-10-30 18:01:18.409633404 +0100
@@ -340,6 +340,7 @@  extern rtx_insn *emit_move_insn_1 (rtx,
 
 extern rtx_insn *emit_move_complex_push (machine_mode, rtx, rtx);
 extern rtx_insn *emit_move_complex_parts (rtx, rtx);
+extern void write_complex_part (rtx, rtx, bool);
 extern rtx emit_move_resolve_push (machine_mode, rtx);
 
 /* Push a block of length SIZE (perhaps variable)
--- gcc/function.c.jj	2014-10-30 14:42:28.000000000 +0100
+++ gcc/function.c	2014-10-30 16:54:05.219777275 +0100
@@ -2017,9 +2017,14 @@  aggregate_value_p (const_tree exp, const
       case CALL_EXPR:
 	{
 	  tree fndecl = get_callee_fndecl (fntype);
-	  fntype = (fndecl
-		    ? TREE_TYPE (fndecl)
-		    : TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype))));
+	  if (fndecl)
+	    fntype = TREE_TYPE (fndecl);
+	  else if (CALL_EXPR_FN (fntype))
+	    fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype)));
+	  else
+	    /* For internal functions, assume nothing needs to be
+	       returned in memory.  */
+	    return 0;
 	}
 	break;
       case FUNCTION_DECL:
--- gcc/gimple-fold.c.jj	2014-10-29 09:49:56.000000000 +0100
+++ gcc/gimple-fold.c	2014-11-10 13:19:37.487851440 +0100
@@ -2604,6 +2604,47 @@  gimple_fold_builtin (gimple_stmt_iterato
   return false;
 }
 
+/* Return true if ARG0 CODE ARG1 in infinite signed precision operation
+   doesn't fit into TYPE.  The test for overflow should be regardless of
+   -fwrapv, and even for unsigned types.  */
+
+bool
+arith_overflowed_p (enum tree_code code, const_tree type,
+		    const_tree arg0, const_tree arg1)
+{
+  typedef FIXED_WIDE_INT (WIDE_INT_MAX_PRECISION * 2) widest2_int;
+  typedef generic_wide_int <wi::extended_tree <WIDE_INT_MAX_PRECISION * 2> >
+    widest2_int_cst;
+  widest2_int warg0 = widest2_int_cst (arg0);
+  widest2_int warg1 = widest2_int_cst (arg1);
+  widest2_int wres;
+  switch (code)
+    {
+    case PLUS_EXPR: wres = wi::add (warg0, warg1); break;
+    case MINUS_EXPR: wres = wi::sub (warg0, warg1); break;
+    case MULT_EXPR: wres = wi::mul (warg0, warg1); break;
+    default: gcc_unreachable ();
+    }
+  signop sign = TYPE_SIGN (type);
+  if (sign == UNSIGNED && wi::neg_p (wres))
+    return true;
+  return wi::min_precision (wres, sign) > TYPE_PRECISION (type);
+}
+
+/* Helper for {ADD,SUB,MUL}_OVERFLOW folding.  Find in *TP if
+   there are any uses of data (SSA_NAME) other than REALPART_EXPR
+   referencing it.  */
+
+static tree
+find_non_realpart_uses (tree *tp, int *walk_subtrees, void *data)
+{
+  if (TYPE_P (*tp) || TREE_CODE (*tp) == REALPART_EXPR)
+    *walk_subtrees = 0;
+  if (*tp == (tree) data)
+    return *tp;
+  return NULL_TREE;
+}
+
 /* Attempt to fold a call statement referenced by the statement iterator GSI.
    The statement may be replaced by another statement, e.g., if the call
    simplifies to a constant value. Return true if any changes were made.
@@ -2732,6 +2773,8 @@  gimple_fold_call (gimple_stmt_iterator *
     {
       enum tree_code subcode = ERROR_MARK;
       tree result = NULL_TREE;
+      bool cplx_result = false;
+      tree overflow = NULL_TREE;
       switch (gimple_call_internal_fn (stmt))
 	{
 	case IFN_BUILTIN_EXPECT:
@@ -2762,6 +2805,18 @@  gimple_fold_call (gimple_stmt_iterator *
 	case IFN_UBSAN_CHECK_MUL:
 	  subcode = MULT_EXPR;
 	  break;
+	case IFN_ADD_OVERFLOW:
+	  subcode = PLUS_EXPR;
+	  cplx_result = true;
+	  break;
+	case IFN_SUB_OVERFLOW:
+	  subcode = MINUS_EXPR;
+	  cplx_result = true;
+	  break;
+	case IFN_MUL_OVERFLOW:
+	  subcode = MULT_EXPR;
+	  cplx_result = true;
+	  break;
 	default:
 	  break;
 	}
@@ -2769,30 +2824,149 @@  gimple_fold_call (gimple_stmt_iterator *
 	{
 	  tree arg0 = gimple_call_arg (stmt, 0);
 	  tree arg1 = gimple_call_arg (stmt, 1);
+	  tree type = TREE_TYPE (arg0);
+	  if (cplx_result)
+	    {
+	      tree lhs = gimple_call_lhs (stmt);
+	      if (lhs == NULL_TREE)
+		type = NULL_TREE;
+	      else
+		type = TREE_TYPE (TREE_TYPE (lhs));
+	    }
+	  if (type == NULL_TREE)
+	    ;
 	  /* x = y + 0; x = y - 0; x = y * 0; */
-	  if (integer_zerop (arg1))
-	    result = subcode == MULT_EXPR
-		     ? build_zero_cst (TREE_TYPE (arg0))
-		     : arg0;
+	  else if (integer_zerop (arg1))
+	    result = subcode == MULT_EXPR ? integer_zero_node : arg0;
 	  /* x = 0 + y; x = 0 * y; */
 	  else if (subcode != MINUS_EXPR && integer_zerop (arg0))
-	    result = subcode == MULT_EXPR
-		     ? build_zero_cst (TREE_TYPE (arg0))
-		     : arg1;
+	    result = subcode == MULT_EXPR ? integer_zero_node : arg1;
 	  /* x = y - y; */
 	  else if (subcode == MINUS_EXPR && operand_equal_p (arg0, arg1, 0))
-	    result = build_zero_cst (TREE_TYPE (arg0));
+	    result = integer_zero_node;
 	  /* x = y * 1; x = 1 * y; */
-	  else if (subcode == MULT_EXPR)
+	  else if (subcode == MULT_EXPR && integer_onep (arg1))
+	    result = arg0;
+	  else if (subcode == MULT_EXPR && integer_onep (arg0))
+	    result = arg1;
+	  else if (TREE_CODE (arg0) == INTEGER_CST
+		   && TREE_CODE (arg1) == INTEGER_CST)
+	    {
+	      if (cplx_result)
+		result = int_const_binop (subcode, fold_convert (type, arg0),
+					  fold_convert (type, arg1));
+	      else
+		result = int_const_binop (subcode, arg0, arg1);
+	      if (result && arith_overflowed_p (subcode, type, arg0, arg1))
+		{
+		  if (cplx_result)
+		    overflow = build_one_cst (type);
+		  else
+		    result = NULL_TREE;
+		}
+	    }
+	  if (result)
+	    {
+	      if (result == integer_zero_node)
+		result = build_zero_cst (type);
+	      else if (cplx_result && TREE_TYPE (result) != type)
+		{
+		  if (TREE_CODE (result) == INTEGER_CST)
+		    {
+		      if (arith_overflowed_p (PLUS_EXPR, type, result,
+					      integer_zero_node))
+			overflow = build_one_cst (type);
+		    }
+		  else if ((!TYPE_UNSIGNED (TREE_TYPE (result))
+			    && TYPE_UNSIGNED (type))
+			   || (TYPE_PRECISION (type)
+			       < (TYPE_PRECISION (TREE_TYPE (result))
+				  + (TYPE_UNSIGNED (TREE_TYPE (result))
+				     && !TYPE_UNSIGNED (type)))))
+		    result = NULL_TREE;
+		  if (result)
+		    result = fold_convert (type, result);
+		}
+	    }
+
+	  /* If the IMAGPART_EXPR of the result is never used, but
+	     REALPART_EXPR is, optimize the {ADD,SUB,MUL}_OVERFLOW
+	     builtins into plain unsigned {PLUS,MINUS,MULT}_EXPR,
+	     and if needed reset debug uses.  */
+	  if (result == NULL_TREE && cplx_result
+	      && gimple_in_ssa_p (cfun) && type)
 	    {
-	      if (integer_onep (arg1))
-		result = arg0;
-	      else if (integer_onep (arg0))
-		result = arg1;
+	      tree lhs = gimple_call_lhs (stmt);
+	      imm_use_iterator imm_iter;
+	      use_operand_p use_p;
+	      bool has_debug_uses = false;
+	      bool has_realpart_uses = false;
+	      bool has_other_uses = false;
+	      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
+		{
+		  gimple use_stmt = USE_STMT (use_p);
+		  if (is_gimple_debug (use_stmt))
+		    has_debug_uses = true;
+		  else if (is_gimple_assign (use_stmt)
+			   && (gimple_assign_rhs_code (use_stmt)
+			       == REALPART_EXPR)
+			   && (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0)
+			       == lhs))
+		    has_realpart_uses = true;
+		  else
+		    {
+		      has_other_uses = true;
+		      break;
+		    }
+		}
+	      if (has_realpart_uses && !has_other_uses)
+		{
+		  location_t loc = gimple_location (stmt);
+		  tree utype = type;
+		  if (!TYPE_UNSIGNED (type))
+		    utype
+		      = build_nonstandard_integer_type (TYPE_PRECISION (type),
+							1);
+		  result
+		    = fold_build2_loc (loc, subcode, utype,
+				       fold_convert_loc (loc, utype, arg0),
+				       fold_convert_loc (loc, utype, arg1));
+		  result = fold_convert_loc (loc, type, result);
+		  if (has_debug_uses)
+		    {
+		      gimple use_stmt;
+		      FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, lhs)
+			{
+			  if (!gimple_debug_bind_p (use_stmt))
+			    continue;
+			  tree v = gimple_debug_bind_get_value (use_stmt);
+			  if (walk_tree (&v, find_non_realpart_uses,
+					 lhs, NULL))
+			    {
+			      gimple_debug_bind_reset_value (use_stmt);
+			      update_stmt (use_stmt);
+			    }
+			}
+		    }
+		}
 	    }
 	}
       if (result)
 	{
+	  if (TREE_CODE (result) == INTEGER_CST && TREE_OVERFLOW (result))
+	    result = drop_tree_overflow (result);
+	  if (cplx_result)
+	    {
+	      if (overflow == NULL_TREE)
+		overflow = build_zero_cst (TREE_TYPE (result));
+	      tree ctype = build_complex_type (TREE_TYPE (result));
+	      if (TREE_CODE (result) == INTEGER_CST
+		  && TREE_CODE (overflow) == INTEGER_CST)
+		result = build_complex (ctype, result, overflow);
+	      else
+		result = build2_loc (gimple_location (stmt), COMPLEX_EXPR,
+				     ctype, result, overflow);
+	    }
 	  if (!update_call_from_tree (gsi, result))
 	    gimplify_and_update_call_from_tree (gsi, result);
 	  changed = true;
--- gcc/gimple-fold.h.jj	2014-10-29 09:49:56.000000000 +0100
+++ gcc/gimple-fold.h	2014-11-05 16:41:09.883123348 +0100
@@ -32,6 +32,8 @@  extern tree maybe_fold_and_comparisons (
 					enum tree_code, tree, tree);
 extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
 				       enum tree_code, tree, tree);
+extern bool arith_overflowed_p (enum tree_code, const_tree, const_tree,
+				const_tree);
 extern tree no_follow_ssa_edges (tree);
 extern tree follow_single_use_edges (tree);
 extern tree gimple_fold_stmt_to_constant_1 (gimple, tree (*) (tree));
--- gcc/gimplify.c.jj	2014-10-29 09:49:56.000000000 +0100
+++ gcc/gimplify.c	2014-10-30 17:19:53.849074948 +0100
@@ -2277,6 +2277,9 @@  gimplify_call_expr (tree *expr_p, gimple
   /* Gimplify internal functions created in the FEs.  */
   if (CALL_EXPR_FN (*expr_p) == NULL_TREE)
     {
+      if (want_value)
+	return GS_ALL_DONE;
+
       nargs = call_expr_nargs (*expr_p);
       enum internal_fn ifn = CALL_EXPR_IFN (*expr_p);
       auto_vec<tree> vargs (nargs);
@@ -4631,22 +4634,41 @@  gimplify_modify_expr (tree *expr_p, gimp
     {
       /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
 	 instead of a GIMPLE_ASSIGN.  */
-      tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
-      CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
-      STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
-      tree fndecl = get_callee_fndecl (*from_p);
-      if (fndecl
-	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
-	  && call_expr_nargs (*from_p) == 3)
-	assign = gimple_build_call_internal (IFN_BUILTIN_EXPECT, 3,
-					     CALL_EXPR_ARG (*from_p, 0),
-					     CALL_EXPR_ARG (*from_p, 1),
-					     CALL_EXPR_ARG (*from_p, 2));
+      if (CALL_EXPR_FN (*from_p) == NULL_TREE)
+	{
+	  /* Gimplify internal functions created in the FEs.  */
+	  int nargs = call_expr_nargs (*from_p), i;
+	  enum internal_fn ifn = CALL_EXPR_IFN (*from_p);
+	  auto_vec<tree> vargs (nargs);
+
+	  for (i = 0; i < nargs; i++)
+	    {
+	      gimplify_arg (&CALL_EXPR_ARG (*from_p, i), pre_p,
+			    EXPR_LOCATION (*from_p));
+	      vargs.quick_push (CALL_EXPR_ARG (*from_p, i));
+	    }
+	  assign = gimple_build_call_internal_vec (ifn, vargs);
+	  gimple_set_location (assign, EXPR_LOCATION (*expr_p));
+	}
       else
 	{
-	  assign = gimple_build_call_from_tree (*from_p);
-	  gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
+	  tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
+	  CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
+	  STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
+	  tree fndecl = get_callee_fndecl (*from_p);
+	  if (fndecl
+	      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
+	      && call_expr_nargs (*from_p) == 3)
+	    assign = gimple_build_call_internal (IFN_BUILTIN_EXPECT, 3,
+						 CALL_EXPR_ARG (*from_p, 0),
+						 CALL_EXPR_ARG (*from_p, 1),
+						 CALL_EXPR_ARG (*from_p, 2));
+	  else
+	    {
+	      assign = gimple_build_call_from_tree (*from_p);
+	      gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
+	    }
 	}
       notice_special_calls (assign);
       if (!gimple_call_noreturn_p (assign))
--- gcc/internal-fn.c.jj	2014-10-30 14:42:22.000000000 +0100
+++ gcc/internal-fn.c	2014-11-10 17:59:49.440129794 +0100
@@ -207,32 +207,494 @@  expand_ASAN_CHECK (gimple stmt ATTRIBUTE
   gcc_unreachable ();
 }
 
+/* Helper function for expand_addsub_overflow.  Return 1
+   if ARG interpreted as signed in its precision is known to be always
+   positive or 2 if ARG is known to be always negative, or 3 if ARG may
+   be positive or negative.  */
+
+static int
+get_range_pos_neg (tree arg)
+{
+  if (arg == error_mark_node)
+    return 3;
+
+  int prec = TYPE_PRECISION (TREE_TYPE (arg));
+  int cnt = 0;
+  if (TREE_CODE (arg) == INTEGER_CST)
+    {
+      wide_int w = wi::sext (arg, prec);
+      if (wi::neg_p (w))
+	return 2;
+      else
+	return 1;
+    }
+  while (CONVERT_EXPR_P (arg)
+	 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
+	 && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
+    {
+      arg = TREE_OPERAND (arg, 0);
+      /* Narrower value zero extended into wider type
+	 will always result in positive values.  */
+      if (TYPE_UNSIGNED (TREE_TYPE (arg))
+	  && TYPE_PRECISION (TREE_TYPE (arg)) < prec)
+	return 1;
+      prec = TYPE_PRECISION (TREE_TYPE (arg));
+      if (++cnt > 30)
+	return 3;
+    }
+
+  if (TREE_CODE (arg) != SSA_NAME)
+    return 3;
+  wide_int arg_min, arg_max;
+  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+    {
+      gimple g = SSA_NAME_DEF_STMT (arg);
+      if (is_gimple_assign (g)
+	  && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
+	{
+	  tree t = gimple_assign_rhs1 (g);
+	  if (INTEGRAL_TYPE_P (TREE_TYPE (t))
+	      && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
+	    {
+	      if (TYPE_UNSIGNED (TREE_TYPE (t))
+		  && TYPE_PRECISION (TREE_TYPE (t)) < prec)
+		return 1;
+	      prec = TYPE_PRECISION (TREE_TYPE (t));
+	      arg = t;
+	      if (++cnt > 30)
+		return 3;
+	      continue;
+	    }
+	}
+      return 3;
+    }
+  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
+    {
+      /* For unsigned values, the "positive" range comes
+	 below the "negative" range.  */
+      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+	return 1;
+      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+	return 2;
+    }
+  else
+    {
+      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+	return 1;
+      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+	return 2;
+    }
+  return 3;
+}
+
+/* Return minimum precision needed to represent all values
+   of ARG in SIGNed integral type.  */
+
+static int
+get_min_precision (tree arg, signop sign)
+{
+  int prec = TYPE_PRECISION (TREE_TYPE (arg));
+  int cnt = 0;
+  signop orig_sign = sign;
+  if (TREE_CODE (arg) == INTEGER_CST)
+    {
+      int p;
+      if (TYPE_SIGN (TREE_TYPE (arg)) != sign)
+	{
+	  widest_int w = wi::to_widest (arg);
+	  w = wi::ext (w, prec, sign);
+	  p = wi::min_precision (w, sign);
+	}
+      else
+	p = wi::min_precision (arg, sign);
+      return MIN (p, prec);
+    }
+  while (CONVERT_EXPR_P (arg)
+	 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
+	 && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
+    {
+      arg = TREE_OPERAND (arg, 0);
+      if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
+	{
+	  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
+	    sign = UNSIGNED;
+	  else if (sign == UNSIGNED && get_range_pos_neg (arg) != 1)
+	    return prec + (orig_sign != sign);
+	  prec = TYPE_PRECISION (TREE_TYPE (arg));
+	}
+      if (++cnt > 30)
+	return prec + (orig_sign != sign);
+    }
+  if (TREE_CODE (arg) != SSA_NAME)
+    return prec + (orig_sign != sign);
+  wide_int arg_min, arg_max;
+  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+    {
+      gimple g = SSA_NAME_DEF_STMT (arg);
+      if (is_gimple_assign (g)
+	  && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
+	{
+	  tree t = gimple_assign_rhs1 (g);
+	  if (INTEGRAL_TYPE_P (TREE_TYPE (t))
+	      && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
+	    {
+	      arg = t;
+	      if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
+		{
+		  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
+		    sign = UNSIGNED;
+		  else if (sign == UNSIGNED && get_range_pos_neg (arg) != 1)
+		    return prec + (orig_sign != sign);
+		  prec = TYPE_PRECISION (TREE_TYPE (arg));
+		}
+	      if (++cnt > 30)
+		return prec + (orig_sign != sign);
+	      continue;
+	    }
+	}
+      return prec + (orig_sign != sign);
+    }
+  if (sign == TYPE_SIGN (TREE_TYPE (arg)))
+    {
+      int p1 = wi::min_precision (arg_min, sign);
+      int p2 = wi::min_precision (arg_max, sign);
+      p1 = MAX (p1, p2);
+      prec = MIN (prec, p1);
+    }
+  else if (sign == UNSIGNED && !wi::neg_p (arg_min, SIGNED))
+    {
+      int p = wi::min_precision (arg_max, SIGNED);
+      prec = MIN (prec, p);
+    }
+  return prec + (orig_sign != sign);
+}
+
+/* Helper for expand_*_overflow.  Store RES into the __real__ part
+   of TARGET.  If RES has larger MODE than __real__ part of TARGET,
+   set the __imag__ part to 1 if RES doesn't fit into it.  */
+
+static void
+expand_arith_overflow_result_store (tree lhs, rtx target,
+				    machine_mode mode, rtx res)
+{
+  machine_mode tgtmode = GET_MODE_INNER (GET_MODE (target));
+  rtx lres = res;
+  if (tgtmode != mode)
+    {
+      rtx_code_label *done_label = gen_label_rtx ();
+      int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
+      lres = convert_modes (tgtmode, mode, res, uns);
+      gcc_assert (GET_MODE_PRECISION (tgtmode) < GET_MODE_PRECISION (mode));
+      emit_cmp_and_jump_insns (res, convert_modes (mode, tgtmode, lres, uns),
+			       EQ, NULL_RTX, mode, false, done_label,
+			       PROB_VERY_LIKELY);
+      write_complex_part (target, const1_rtx, true);
+      emit_label (done_label);
+    }
+  write_complex_part (target, lres, false);
+}
+
 /* 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)
+static void
+expand_addsub_overflow (location_t loc, tree_code code, tree lhs,
+			tree arg0, tree arg1, bool unsr_p, bool uns0_p,
+			bool uns1_p, bool is_ubsan)
 {
-  rtx res, op0, op1;
-  tree lhs, fn, arg0, arg1;
-  rtx_code_label *done_label, *do_error;
-  rtx 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 ();
+  rtx res, target = NULL_RTX;
+  tree fn;
+  rtx_code_label *done_label = gen_label_rtx ();
+  rtx_code_label *do_error = gen_label_rtx ();
   do_pending_stack_adjust ();
-  op0 = expand_normal (arg0);
-  op1 = expand_normal (arg1);
-
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
   machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
+  int prec = GET_MODE_PRECISION (mode);
+  rtx sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
+  bool do_xor = false;
+
+  if (is_ubsan)
+    gcc_assert (!unsr_p && !uns0_p && !uns1_p);
+
   if (lhs)
-    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+    {
+      target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+      if (!is_ubsan)
+	write_complex_part (target, const0_rtx, true);
+    }
+
+  /* We assume both operands and result have the same precision
+     here (GET_MODE_BITSIZE (mode)), S stands for signed type
+     with that precision, U for unsigned type with that precision,
+     sgn for unsigned most significant bit in that precision.
+     s1 is signed first operand, u1 is unsigned first operand,
+     s2 is signed second operand, u2 is unsigned second operand,
+     sr is signed result, ur is unsigned result and the following
+     rules say how to compute result (which is always result of
+     the operands as if both were unsigned, cast to the right
+     signedness) and how to compute whether operation overflowed.
+
+     s1 + s2 -> sr
+	res = (S) ((U) s1 + (U) s2)
+	ovf = s2 < 0 ? res > s1 : res < s1 (or jump on overflow)
+     s1 - s2 -> sr
+	res = (S) ((U) s1 - (U) s2)
+	ovf = s2 < 0 ? res < s1 : res > s2 (or jump on overflow)
+     u1 + u2 -> ur
+	res = u1 + u2
+	ovf = res < u1 (or jump on carry, but RTL opts will handle it)
+     u1 - u2 -> ur
+	res = u1 - u2
+	ovf = res > u1 (or jump on carry, but RTL opts will handle it)
+     s1 + u2 -> sr
+	res = (S) ((U) s1 + u2)
+	ovf = ((U) res ^ sgn) < u2
+     s1 + u2 -> ur
+	t1 = (S) (u2 ^ sgn)
+	t2 = s1 + t1
+	res = (U) t2 ^ sgn
+	ovf = t1 < 0 ? t2 > s1 : t2 < s1 (or jump on overflow)
+     s1 - u2 -> sr
+	res = (S) ((U) s1 - u2)
+	ovf = u2 > ((U) s1 ^ sgn)
+     s1 - u2 -> ur
+	res = (U) s1 - u2
+	ovf = s1 < 0 || u2 > (U) s1
+     u1 - s2 -> sr
+	res = u1 - (U) s2
+ 	ovf = u1 >= ((U) s2 ^ sgn)
+     u1 - s2 -> ur
+	t1 = u1 ^ sgn
+	t2 = t1 - (U) s2
+	res = t2 ^ sgn
+	ovf = s2 < 0 ? (S) t2 < (S) t1 : (S) t2 > (S) t1 (or jump on overflow)
+     s1 + s2 -> ur
+	res = (U) s1 + (U) s2
+	ovf = s2 < 0 ? (s1 | (S) res) < 0) : (s1 & (S) res) < 0)
+     u1 + u2 -> sr
+	res = (S) (u1 + u2)
+	ovf = (U) res < u2 || res < 0
+     u1 - u2 -> sr
+	res = (S) (u1 - u2)
+	ovf = u1 >= u2 ? res < 0 : res >= 0
+     s1 - s2 -> ur
+	res = (U) s1 - (U) s2
+	ovf = s2 >= 0 ? ((s1 | (S) res) < 0) : ((s1 & (S) res) < 0)  */
 
-  enum insn_code icode
-    = optab_handler (code == PLUS_EXPR ? addv4_optab : subv4_optab, mode);
+  if (code == PLUS_EXPR && uns0_p && !uns1_p)
+    {
+      /* PLUS_EXPR is commutative, if operand signedness differs,
+	 canonicalize to the first operand being signed and second
+	 unsigned to simplify following code.  */
+      rtx tem = op1;
+      op1 = op0;
+      op0 = tem;
+      tree t = arg1;
+      arg1 = arg0;
+      arg0 = t;
+      uns0_p = 0;
+      uns1_p = 1;
+    }
+
+  /* u1 +- u2 -> ur  */
+  if (uns0_p && uns1_p && unsr_p)
+    {
+      /* Compute the operation.  On RTL level, the addition is always
+	 unsigned.  */
+      res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
+			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
+      rtx tem = op0;
+      /* For PLUS_EXPR, the operation is commutative, so we can pick
+	 operand to compare against.  For prec <= BITS_PER_WORD, I think
+	 preferring REG operand is better over CONST_INT, because
+	 the CONST_INT might enlarge the instruction or CSE would need
+	 to figure out we'd already loaded it into a register before.
+	 For prec > BITS_PER_WORD, I think CONST_INT might be more beneficial,
+	 as then the multi-word comparison can be perhaps simplified.  */
+      if (code == PLUS_EXPR
+	  && (prec <= BITS_PER_WORD
+	      ? (CONST_SCALAR_INT_P (op0) && REG_P (op1))
+	      : CONST_SCALAR_INT_P (op1)))
+	tem = op1;
+      emit_cmp_and_jump_insns (res, tem, code == PLUS_EXPR ? GEU : LEU,
+			       NULL_RTX, mode, false, done_label,
+			       PROB_VERY_LIKELY);
+      goto do_error_label;
+    }
+
+  /* s1 +- u2 -> sr  */
+  if (!uns0_p && uns1_p && !unsr_p)
+    {
+      /* Compute the operation.  On RTL level, the addition is always
+	 unsigned.  */
+      res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
+			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
+      rtx tem = expand_binop (mode, add_optab,
+			      code == PLUS_EXPR ? res : op0, sgn,
+			      NULL_RTX, false, OPTAB_LIB_WIDEN);
+      emit_cmp_and_jump_insns (tem, op1, GEU, NULL_RTX, mode, false,
+			       done_label, PROB_VERY_LIKELY);
+      goto do_error_label;
+    }
+
+  /* s1 + u2 -> ur  */
+  if (code == PLUS_EXPR && !uns0_p && uns1_p && unsr_p)
+    {
+      op1 = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
+			  OPTAB_LIB_WIDEN);
+      /* As we've changed op1, we have to avoid using the value range
+	 for the original argument.  */
+      arg1 = error_mark_node;
+      do_xor = true;
+      goto do_signed;
+    }
+
+  /* u1 - s2 -> ur  */
+  if (code == MINUS_EXPR && uns0_p && !uns1_p && unsr_p)
+    {
+      op0 = expand_binop (mode, add_optab, op0, sgn, NULL_RTX, false,
+			  OPTAB_LIB_WIDEN);
+      /* As we've changed op0, we have to avoid using the value range
+	 for the original argument.  */
+      arg0 = error_mark_node;
+      do_xor = true;
+      goto do_signed;
+    }
+
+  /* s1 - u2 -> ur  */
+  if (code == MINUS_EXPR && !uns0_p && uns1_p && unsr_p)
+    {
+      /* Compute the operation.  On RTL level, the addition is always
+	 unsigned.  */
+      res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
+			  OPTAB_LIB_WIDEN);
+      int pos_neg = get_range_pos_neg (arg0);
+      if (pos_neg == 2)
+	/* If ARG0 is known to be always negative, this is always overflow.  */
+	emit_jump (do_error);
+      else if (pos_neg == 3)
+	/* If ARG0 is not known to be always positive, check at runtime.  */
+	emit_cmp_and_jump_insns (op0, const0_rtx, LT, NULL_RTX, mode, false,
+				 do_error, PROB_VERY_UNLIKELY);
+      emit_cmp_and_jump_insns (op1, op0, LEU, NULL_RTX, mode, false,
+			       done_label, PROB_VERY_LIKELY);
+      goto do_error_label;
+    }
+
+  /* u1 - s2 -> sr  */
+  if (code == MINUS_EXPR && uns0_p && !uns1_p && !unsr_p)
+    {
+      /* Compute the operation.  On RTL level, the addition is always
+	 unsigned.  */
+      res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
+			  OPTAB_LIB_WIDEN);
+      rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
+			      OPTAB_LIB_WIDEN);
+      emit_cmp_and_jump_insns (op0, tem, LTU, NULL_RTX, mode, false,
+			       done_label, PROB_VERY_LIKELY);
+      goto do_error_label;
+    }
+
+  /* u1 + u2 -> sr  */
+  if (code == PLUS_EXPR && uns0_p && uns1_p && !unsr_p)
+    {
+      /* 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);
+      emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode, false,
+			       do_error, PROB_VERY_UNLIKELY);
+      rtx tem = op1;
+      /* The operation is commutative, so we can pick operand to compare
+	 against.  For prec <= BITS_PER_WORD, I think preferring REG operand
+	 is better over CONST_INT, because the CONST_INT might enlarge the
+	 instruction or CSE would need to figure out we'd already loaded it
+	 into a register before.  For prec > BITS_PER_WORD, I think CONST_INT
+	 might be more beneficial, as then the multi-word comparison can be
+	 perhaps simplified.  */
+      if (prec <= BITS_PER_WORD
+	  ? (CONST_SCALAR_INT_P (op1) && REG_P (op0))
+	  : CONST_SCALAR_INT_P (op0))
+	tem = op0;
+      emit_cmp_and_jump_insns (res, tem, GEU, NULL_RTX, mode, false,
+			       done_label, PROB_VERY_LIKELY);
+      goto do_error_label;
+    }
+
+  /* s1 +- s2 -> ur  */
+  if (!uns0_p && !uns1_p && unsr_p)
+    {
+      /* Compute the operation.  On RTL level, the addition is always
+	 unsigned.  */
+      res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
+			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
+      int pos_neg = get_range_pos_neg (arg1);
+      if (code == PLUS_EXPR)
+	{
+	  int pos_neg0 = get_range_pos_neg (arg0);
+	  if (pos_neg0 != 3 && pos_neg == 3)
+	    {
+	      rtx tem = op1;
+	      op1 = op0;
+	      op0 = tem;
+	      pos_neg = pos_neg0;
+	    }
+	}
+      rtx tem;
+      if (pos_neg != 3)
+	{
+	  tem = expand_binop (mode, ((pos_neg == 1) ^ (code == MINUS_EXPR))
+				    ? and_optab : ior_optab,
+			      op0, res, NULL_RTX, false, OPTAB_LIB_WIDEN);
+	  emit_cmp_and_jump_insns (tem, const0_rtx, GE, NULL_RTX, mode, false,
+				   done_label, PROB_VERY_LIKELY);
+	}
+      else
+	{
+	  rtx_code_label *do_ior_label = gen_label_rtx ();
+	  emit_cmp_and_jump_insns (op1, const0_rtx,
+				   code == MINUS_EXPR ? GE : LT, NULL_RTX,
+				   mode, false, do_ior_label, PROB_EVEN);
+	  tem = expand_binop (mode, and_optab, op0, res, NULL_RTX, false,
+			      OPTAB_LIB_WIDEN);
+	  emit_cmp_and_jump_insns (tem, const0_rtx, GE, NULL_RTX, mode, false,
+				   done_label, PROB_VERY_LIKELY);
+	  emit_jump (do_error);
+	  emit_label (do_ior_label);
+	  tem = expand_binop (mode, ior_optab, op0, res, NULL_RTX, false,
+			      OPTAB_LIB_WIDEN);
+	  emit_cmp_and_jump_insns (tem, const0_rtx, GE, NULL_RTX, mode, false,
+				   done_label, PROB_VERY_LIKELY);
+	}
+      goto do_error_label;
+    }
+
+  /* u1 - u2 -> sr  */
+  if (code == MINUS_EXPR && uns0_p && uns1_p && !unsr_p)
+    {
+      /* Compute the operation.  On RTL level, the addition is always
+	 unsigned.  */
+      res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
+			  OPTAB_LIB_WIDEN);
+      rtx_code_label *op0_geu_op1 = gen_label_rtx ();
+      emit_cmp_and_jump_insns (op0, op1, GEU, NULL_RTX, mode, false,
+			       op0_geu_op1, PROB_EVEN);
+      emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode, false,
+			       done_label, PROB_VERY_LIKELY);
+      emit_jump (do_error);
+      emit_label (op0_geu_op1);
+      emit_cmp_and_jump_insns (res, const0_rtx, GE, NULL_RTX, mode, false,
+			       done_label, PROB_VERY_LIKELY);
+      goto do_error_label;
+    }
+
+  gcc_assert (!uns0_p && !uns1_p && !unsr_p);
+
+  /* s1 +- s2 -> sr  */
+ do_signed: ;
+  enum insn_code icode;
+  icode = optab_handler (code == PLUS_EXPR ? addv4_optab : subv4_optab, mode);
   if (icode != CODE_FOR_nothing)
     {
       struct expand_operand ops[4];
@@ -288,14 +750,7 @@  ubsan_expand_si_overflow_addsub_check (t
 	;
       else if (code == PLUS_EXPR && TREE_CODE (arg0) == SSA_NAME)
 	{
-	  wide_int arg0_min, arg0_max;
-	  if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
-	    {
-	      if (!wi::neg_p (arg0_min, TYPE_SIGN (TREE_TYPE (arg0))))
-		pos_neg = 1;
-	      else if (wi::neg_p (arg0_max, TYPE_SIGN (TREE_TYPE (arg0))))
-		pos_neg = 2;
-	    }
+	  pos_neg = get_range_pos_neg (arg0);
 	  if (pos_neg != 3)
 	    {
 	      rtx tem = op0;
@@ -304,16 +759,7 @@  ubsan_expand_si_overflow_addsub_check (t
 	    }
 	}
       if (pos_neg == 3 && !CONST_INT_P (op1) && TREE_CODE (arg1) == SSA_NAME)
-	{
-	  wide_int arg1_min, arg1_max;
-	  if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
-	    {
-	      if (!wi::neg_p (arg1_min, TYPE_SIGN (TREE_TYPE (arg1))))
-		pos_neg = 1;
-	      else if (wi::neg_p (arg1_max, TYPE_SIGN (TREE_TYPE (arg1))))
-		pos_neg = 2;
-	    }
-	}
+	pos_neg = get_range_pos_neg (arg1);
 
       /* If the op1 is negative, we have to use a different check.  */
       if (pos_neg == 3)
@@ -341,34 +787,49 @@  ubsan_expand_si_overflow_addsub_check (t
 				 PROB_VERY_LIKELY);
     }
 
+ do_error_label:
   emit_label (do_error);
-  /* Expand the ubsan builtin call.  */
-  push_temp_slots ();
-  fn = ubsan_build_overflow_builtin (code, gimple_location (stmt),
-				     TREE_TYPE (arg0), arg0, arg1);
-  expand_normal (fn);
-  pop_temp_slots ();
-  do_pending_stack_adjust ();
+  if (is_ubsan)
+    {
+      /* Expand the ubsan builtin call.  */
+      push_temp_slots ();
+      fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0),
+					 arg0, arg1);
+      expand_normal (fn);
+      pop_temp_slots ();
+      do_pending_stack_adjust ();
+    }
+  else if (lhs)
+    write_complex_part (target, const1_rtx, true);
 
   /* We're done.  */
   emit_label (done_label);
 
   if (lhs)
-    emit_move_insn (target, res);
+    {
+      if (is_ubsan)
+	emit_move_insn (target, res);
+      else
+	{
+	  if (do_xor)
+	    res = expand_binop (mode, add_optab, res, sgn, NULL_RTX, false,
+				OPTAB_LIB_WIDEN);
+
+	  expand_arith_overflow_result_store (lhs, target, mode, res);
+	}
+    }
 }
 
 /* Add negate overflow checking to the statement STMT.  */
 
-void
-ubsan_expand_si_overflow_neg_check (gimple stmt)
+static void
+expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan)
 {
   rtx res, op1;
-  tree lhs, fn, arg1;
+  tree fn;
   rtx_code_label *done_label, *do_error;
   rtx target = NULL_RTX;
 
-  lhs = gimple_call_lhs (stmt);
-  arg1 = gimple_call_arg (stmt, 1);
   done_label = gen_label_rtx ();
   do_error = gen_label_rtx ();
 
@@ -377,7 +838,11 @@  ubsan_expand_si_overflow_neg_check (gimp
 
   machine_mode mode = TYPE_MODE (TREE_TYPE (arg1));
   if (lhs)
-    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+    {
+      target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+      if (!is_ubsan)
+	write_complex_part (target, const0_rtx, true);
+    }
 
   enum insn_code icode = optab_handler (negv3_optab, mode);
   if (icode != CODE_FOR_nothing)
@@ -419,34 +884,44 @@  ubsan_expand_si_overflow_neg_check (gimp
     }
 
   emit_label (do_error);
-  /* Expand the ubsan builtin call.  */
-  push_temp_slots ();
-  fn = ubsan_build_overflow_builtin (NEGATE_EXPR, gimple_location (stmt),
-				     TREE_TYPE (arg1), arg1, NULL_TREE);
-  expand_normal (fn);
-  pop_temp_slots ();
-  do_pending_stack_adjust ();
+  if (is_ubsan)
+    {
+      /* Expand the ubsan builtin call.  */
+      push_temp_slots ();
+      fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1),
+					 arg1, NULL_TREE);
+      expand_normal (fn);
+      pop_temp_slots ();
+      do_pending_stack_adjust ();
+    }
+  else if (lhs)
+    write_complex_part (target, const1_rtx, true);
 
   /* We're done.  */
   emit_label (done_label);
 
   if (lhs)
-    emit_move_insn (target, res);
+    {
+      if (is_ubsan)
+	emit_move_insn (target, res);
+      else
+	expand_arith_overflow_result_store (lhs, target, mode, res);
+    }
 }
 
 /* Add mul overflow checking to the statement STMT.  */
 
-void
-ubsan_expand_si_overflow_mul_check (gimple stmt)
+static void
+expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
+		     bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan)
 {
   rtx res, op0, op1;
-  tree lhs, fn, arg0, arg1;
+  tree fn, type;
   rtx_code_label *done_label, *do_error;
   rtx target = NULL_RTX;
+  signop sign;
+  enum insn_code icode;
 
-  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 ();
 
@@ -455,10 +930,243 @@  ubsan_expand_si_overflow_mul_check (gimp
   op1 = expand_normal (arg1);
 
   machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
+  bool uns = unsr_p;
   if (lhs)
-    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+    {
+      target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+      if (!is_ubsan)
+	write_complex_part (target, const0_rtx, true);
+    }
+
+  if (is_ubsan)
+    gcc_assert (!unsr_p && !uns0_p && !uns1_p);
+
+  /* We assume both operands and result have the same precision
+     here (GET_MODE_BITSIZE (mode)), S stands for signed type
+     with that precision, U for unsigned type with that precision,
+     sgn for unsigned most significant bit in that precision.
+     s1 is signed first operand, u1 is unsigned first operand,
+     s2 is signed second operand, u2 is unsigned second operand,
+     sr is signed result, ur is unsigned result and the following
+     rules say how to compute result (which is always result of
+     the operands as if both were unsigned, cast to the right
+     signedness) and how to compute whether operation overflowed.
+     main_ovf (false) stands for jump on signed multiplication
+     overflow or the main algorithm with uns == false.
+     main_ovf (true) stands for jump on unsigned multiplication
+     overflow or the main algorithm with uns == true.
+
+     s1 * s2 -> sr
+	res = (S) ((U) s1 * (U) s2)
+	ovf = main_ovf (false)
+     u1 * u2 -> ur
+	res = u1 * u2
+	ovf = main_ovf (true)
+     s1 * u2 -> ur
+	res = (U) s1 * u2
+	ovf = (s1 < 0 && u2) || main_ovf (true)
+     u1 * u2 -> sr
+	res = (S) (u1 * u2)
+	ovf = res < 0 || main_ovf (true)
+     s1 * u2 -> sr
+	res = (S) ((U) s1 * u2)
+	ovf = (S) u2 >= 0 ? main_ovf (false)
+			  : (s1 != 0 && (s1 != -1 || u2 != (U) res))
+     s1 * s2 -> ur
+	t1 = (s1 & s2) < 0 ? (-(U) s1) : ((U) s1)
+	t2 = (s1 & s2) < 0 ? (-(U) s2) : ((U) s2)
+	res = t1 * t2
+	ovf = (s1 ^ s2) < 0 ? (s1 && s2) : main_ovf (true)  */
+
+  if (uns0_p && !uns1_p)
+    {
+      /* Multiplication is commutative, if operand signedness differs,
+	 canonicalize to the first operand being signed and second
+	 unsigned to simplify following code.  */
+      rtx tem = op1;
+      op1 = op0;
+      op0 = tem;
+      tree t = arg1;
+      arg1 = arg0;
+      arg0 = t;
+      uns0_p = 0;
+      uns1_p = 1;
+    }
+
+  int pos_neg0 = get_range_pos_neg (arg0);
+  int pos_neg1 = get_range_pos_neg (arg1);
+
+  /* s1 * u2 -> ur  */
+  if (!uns0_p && uns1_p && unsr_p)
+    {
+      switch (pos_neg0)
+	{
+	case 1:
+	  /* If s1 is non-negative, just perform normal u1 * u2 -> ur.  */
+	  goto do_main;
+	case 2:
+	  /* If s1 is negative, avoid the main code, just multiply and
+	     signal overflow if op1 is not 0.  */
+	  struct separate_ops ops;
+	  ops.code = MULT_EXPR;
+	  ops.type = TREE_TYPE (arg1);
+	  ops.op0 = make_tree (ops.type, op0);
+	  ops.op1 = make_tree (ops.type, op1);
+	  ops.op2 = NULL_TREE;
+	  ops.location = loc;
+	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
+	  emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, mode,
+				   false, done_label, PROB_VERY_LIKELY);
+	  goto do_error_label;
+	case 3:
+	  rtx_code_label *do_main_label;
+	  do_main_label = gen_label_rtx ();
+	  emit_cmp_and_jump_insns (op0, const0_rtx, GE, NULL_RTX, mode,
+				   false, do_main_label, PROB_VERY_LIKELY);
+	  emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, mode,
+				   false, do_main_label, PROB_VERY_LIKELY);
+	  write_complex_part (target, const1_rtx, true);
+	  emit_label (do_main_label);
+	  goto do_main;
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  /* u1 * u2 -> sr  */
+  if (uns0_p && uns1_p && !unsr_p)
+    {
+      uns = true;
+      /* Rest of handling of this case after res is computed.  */
+      goto do_main;
+    }
+
+  /* s1 * u2 -> sr  */
+  if (!uns0_p && uns1_p && !unsr_p)
+    {
+      switch (pos_neg1)
+	{
+	case 1:
+	  goto do_main;
+	case 2:
+	  /* If (S) u2 is negative (i.e. u2 is larger than maximum of S,
+	     avoid the main code, just multiply and signal overflow
+	     unless 0 * u2 or -1 * ((U) Smin).  */
+	  struct separate_ops ops;
+	  ops.code = MULT_EXPR;
+	  ops.type = TREE_TYPE (arg1);
+	  ops.op0 = make_tree (ops.type, op0);
+	  ops.op1 = make_tree (ops.type, op1);
+	  ops.op2 = NULL_TREE;
+	  ops.location = loc;
+	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
+	  emit_cmp_and_jump_insns (op0, const0_rtx, EQ, NULL_RTX, mode,
+				   false, done_label, PROB_VERY_LIKELY);
+	  emit_cmp_and_jump_insns (op0, constm1_rtx, NE, NULL_RTX, mode,
+				   false, do_error, PROB_VERY_UNLIKELY);
+	  int prec;
+	  prec = GET_MODE_PRECISION (mode);
+	  rtx sgn;
+	  sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
+	  emit_cmp_and_jump_insns (op1, sgn, EQ, NULL_RTX, mode,
+				   false, done_label, PROB_VERY_LIKELY);
+	  goto do_error_label;
+	case 3:
+	  /* Rest of handling of this case after res is computed.  */
+	  goto do_main;
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  /* s1 * s2 -> ur  */
+  if (!uns0_p && !uns1_p && unsr_p)
+    {
+      rtx tem, tem2;
+      switch (pos_neg0 | pos_neg1)
+	{
+	case 1: /* Both operands known to be non-negative.  */
+	  goto do_main;
+	case 2: /* Both operands known to be negative.  */
+	  op0 = expand_unop (mode, neg_optab, op0, NULL_RTX, false);
+	  op1 = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
+	  /* Avoid looking at arg0/arg1 ranges, as we've changed
+	     the arguments.  */
+	  arg0 = error_mark_node;
+	  arg1 = error_mark_node;
+	  goto do_main;
+	case 3:
+	  if ((pos_neg0 ^ pos_neg1) == 3)
+	    {
+	      /* If one operand is known to be negative and the other
+		 non-negative, this overflows always, unless the non-negative
+		 one is 0.  Just do normal multiply and set overflow
+		 unless one of the operands is 0.  */
+	      struct separate_ops ops;
+	      ops.code = MULT_EXPR;
+	      ops.type
+		= build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
+						  1);
+	      ops.op0 = make_tree (ops.type, op0);
+	      ops.op1 = make_tree (ops.type, op1);
+	      ops.op2 = NULL_TREE;
+	      ops.location = loc;
+	      res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
+	      tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
+				  OPTAB_LIB_WIDEN);
+	      emit_cmp_and_jump_insns (tem, const0_rtx, EQ, NULL_RTX, mode,
+				       false, done_label, PROB_VERY_LIKELY);
+	      goto do_error_label;
+	    }
+	  /* The general case, do all the needed comparisons at runtime.  */
+	  rtx_code_label *do_main_label, *after_negate_label;
+	  rtx rop0, rop1;
+	  rop0 = gen_reg_rtx (mode);
+	  rop1 = gen_reg_rtx (mode);
+	  emit_move_insn (rop0, op0);
+	  emit_move_insn (rop1, op1);
+	  op0 = rop0;
+	  op1 = rop1;
+	  do_main_label = gen_label_rtx ();
+	  after_negate_label = gen_label_rtx ();
+	  tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
+			      OPTAB_LIB_WIDEN);
+	  emit_cmp_and_jump_insns (tem, const0_rtx, GE, NULL_RTX, mode, false,
+				   after_negate_label, PROB_VERY_LIKELY);
+	  /* Both arguments negative here, negate them and continue with
+	     normal unsigned overflow checking multiplication.  */
+	  emit_move_insn (op0, expand_unop (mode, neg_optab, op0,
+					    NULL_RTX, false));
+	  emit_move_insn (op1, expand_unop (mode, neg_optab, op1,
+					    NULL_RTX, false));
+	  /* Avoid looking at arg0/arg1 ranges, as we might have changed
+	     the arguments.  */
+	  arg0 = error_mark_node;
+	  arg1 = error_mark_node;
+	  emit_jump (do_main_label);
+	  emit_label (after_negate_label);
+	  tem2 = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
+			       OPTAB_LIB_WIDEN);
+	  emit_cmp_and_jump_insns (tem2, const0_rtx, GE, NULL_RTX, mode, false,
+				   do_main_label, PROB_VERY_LIKELY);
+	  /* One argument is negative here, the other positive.  This
+	     overflows always, unless one of the arguments is 0.  But
+	     if e.g. s2 is 0, (U) s1 * 0 doesn't overflow, whatever s1
+	     is, thus we can keep do_main code oring in overflow as is.  */
+	  emit_cmp_and_jump_insns (tem, const0_rtx, EQ, NULL_RTX, mode, false,
+				   do_main_label, PROB_VERY_LIKELY);
+	  write_complex_part (target, const1_rtx, true);
+	  emit_label (do_main_label);
+	  goto do_main;
+	default:
+	  gcc_unreachable ();
+	}
+    }
 
-  enum insn_code icode = optab_handler (mulv4_optab, mode);
+ do_main:
+  type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode), uns);
+  sign = uns ? UNSIGNED : SIGNED;
+  icode = optab_handler (uns ? umulv4_optab : mulv4_optab, mode);
   if (icode != CODE_FOR_nothing)
     {
       struct expand_operand ops[4];
@@ -489,59 +1197,69 @@  ubsan_expand_si_overflow_mul_check (gimp
   if (icode == CODE_FOR_nothing)
     {
       struct separate_ops ops;
-      machine_mode hmode
-	= mode_for_size (GET_MODE_PRECISION (mode) / 2, MODE_INT, 1);
-      ops.op0 = arg0;
-      ops.op1 = arg1;
+      int prec = GET_MODE_PRECISION (mode);
+      machine_mode hmode = mode_for_size (prec / 2, MODE_INT, 1);
+      ops.op0 = make_tree (type, op0);
+      ops.op1 = make_tree (type, op1);
       ops.op2 = NULL_TREE;
-      ops.location = gimple_location (stmt);
+      ops.location = loc;
       if (GET_MODE_2XWIDER_MODE (mode) != VOIDmode
 	  && targetm.scalar_mode_supported_p (GET_MODE_2XWIDER_MODE (mode)))
 	{
 	  machine_mode wmode = GET_MODE_2XWIDER_MODE (mode);
 	  ops.code = WIDEN_MULT_EXPR;
 	  ops.type
-	    = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), 0);
+	    = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
 
 	  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);
+	  rtx hipart = expand_shift (RSHIFT_EXPR, wmode, res, prec,
+				     NULL_RTX, uns);
 	  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);
+	  if (uns)
+	    /* For the unsigned multiplication, there was overflow if
+	       HIPART is non-zero.  */
+	    emit_cmp_and_jump_insns (hipart, const0_rtx, EQ, NULL_RTX, mode,
+				     false, done_label, PROB_VERY_LIKELY);
+	  else
+	    {
+	      rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 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 if (hmode != BLKmode
-	       && 2 * GET_MODE_PRECISION (hmode) == GET_MODE_PRECISION (mode))
+      else if (hmode != BLKmode && 2 * GET_MODE_PRECISION (hmode) == prec)
 	{
 	  rtx_code_label *large_op0 = gen_label_rtx ();
 	  rtx_code_label *small_op0_large_op1 = gen_label_rtx ();
 	  rtx_code_label *one_small_one_large = gen_label_rtx ();
 	  rtx_code_label *both_ops_large = gen_label_rtx ();
-	  rtx_code_label *after_hipart_neg = gen_label_rtx ();
-	  rtx_code_label *after_lopart_neg = gen_label_rtx ();
+	  rtx_code_label *after_hipart_neg = uns ? NULL : gen_label_rtx ();
+	  rtx_code_label *after_lopart_neg = uns ? NULL : gen_label_rtx ();
 	  rtx_code_label *do_overflow = gen_label_rtx ();
-	  rtx_code_label *hipart_different = gen_label_rtx ();
+	  rtx_code_label *hipart_different = uns ? NULL : gen_label_rtx ();
 
 	  unsigned int hprec = GET_MODE_PRECISION (hmode);
 	  rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
-				      NULL_RTX, 0);
+				      NULL_RTX, uns);
 	  hipart0 = gen_lowpart (hmode, hipart0);
 	  rtx lopart0 = gen_lowpart (hmode, op0);
-	  rtx signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
-				       NULL_RTX, 0);
+	  rtx signbit0 = const0_rtx;
+	  if (!uns)
+	    signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
+				     NULL_RTX, 0);
 	  rtx hipart1 = expand_shift (RSHIFT_EXPR, mode, op1, hprec,
-				      NULL_RTX, 0);
+				      NULL_RTX, uns);
 	  hipart1 = gen_lowpart (hmode, hipart1);
 	  rtx lopart1 = gen_lowpart (hmode, op1);
-	  rtx signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
-				       NULL_RTX, 0);
+	  rtx signbit1 = const0_rtx;
+	  if (!uns)
+	    signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
+				     NULL_RTX, 0);
 
 	  res = gen_reg_rtx (mode);
 
@@ -559,40 +1277,29 @@  ubsan_expand_si_overflow_mul_check (gimp
 	  int op0_sign = 1;
 	  int op1_sign = 1;
 
-	  if (TREE_CODE (arg0) == SSA_NAME)
-	    {
-	      wide_int arg0_min, arg0_max;
-	      if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
-		{
-		  unsigned int mprec0 = wi::min_precision (arg0_min, SIGNED);
-		  unsigned int mprec1 = wi::min_precision (arg0_max, SIGNED);
-		  if (mprec0 <= hprec && mprec1 <= hprec)
-		    op0_small_p = true;
-		  else if (mprec0 <= hprec + 1 && mprec1 <= hprec + 1)
-		    op0_medium_p = true;
-		  if (!wi::neg_p (arg0_min, TYPE_SIGN (TREE_TYPE (arg0))))
-		    op0_sign = 0;
-		  else if (wi::neg_p (arg0_max, TYPE_SIGN (TREE_TYPE (arg0))))
-		    op0_sign = -1;
-		}
-	    }
-	  if (TREE_CODE (arg1) == SSA_NAME)
-	    {
-	      wide_int arg1_min, arg1_max;
-	      if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
-		{
-		  unsigned int mprec0 = wi::min_precision (arg1_min, SIGNED);
-		  unsigned int mprec1 = wi::min_precision (arg1_max, SIGNED);
-		  if (mprec0 <= hprec && mprec1 <= hprec)
-		    op1_small_p = true;
-		  else if (mprec0 <= hprec + 1 && mprec1 <= hprec + 1)
-		    op1_medium_p = true;
-		  if (!wi::neg_p (arg1_min, TYPE_SIGN (TREE_TYPE (arg1))))
-		    op1_sign = 0;
-		  else if (wi::neg_p (arg1_max, TYPE_SIGN (TREE_TYPE (arg1))))
-		    op1_sign = -1;
-		}
-	    }
+	  if (pos_neg0 == 1)
+	    op0_sign = 0;
+	  else if (pos_neg0 == 2)
+	    op0_sign = -1;
+	  if (pos_neg1 == 1)
+	    op1_sign = 0;
+	  else if (pos_neg1 == 2)
+	    op1_sign = -1;
+
+	  unsigned int mprec0 = prec;
+	  if (arg0 != error_mark_node)
+	    mprec0 = get_min_precision (arg0, sign);
+	  if (mprec0 <= hprec)
+	    op0_small_p = true;
+	  else if (!uns && mprec0 <= hprec + 1)
+	    op0_medium_p = true;
+	  unsigned int mprec1 = prec;
+	  if (arg1 != error_mark_node)
+	    mprec1 = get_min_precision (arg1, sign);
+	  if (mprec1 <= hprec)
+	    op1_small_p = true;
+	  else if (!uns && mprec1 <= hprec + 1)
+	    op1_medium_p = true;
 
 	  int smaller_sign = 1;
 	  int larger_sign = 1;
@@ -621,24 +1328,27 @@  ubsan_expand_si_overflow_mul_check (gimp
 				     false, small_op0_large_op1,
 				     PROB_UNLIKELY);
 
-	  /* If both op0 and op1 are sign extended from hmode to mode,
-	     the multiplication will never overflow.  We can do just one
-	     hmode x hmode => mode widening multiplication.  */
+	  /* If both op0 and op1 are sign (!uns) or zero (uns) extended from
+	     hmode to mode, the multiplication will never overflow.  We can
+	     do just one hmode x hmode => mode widening multiplication.  */
+	  rtx lopart0s = lopart0, lopart1s = lopart1;
 	  if (GET_CODE (lopart0) == SUBREG)
 	    {
-	      SUBREG_PROMOTED_VAR_P (lopart0) = 1;
-	      SUBREG_PROMOTED_SET (lopart0, 0);
+	      lopart0s = shallow_copy_rtx (lopart0);
+	      SUBREG_PROMOTED_VAR_P (lopart0s) = 1;
+	      SUBREG_PROMOTED_SET (lopart0s, uns ? SRP_UNSIGNED : SRP_SIGNED);
 	    }
 	  if (GET_CODE (lopart1) == SUBREG)
 	    {
-	      SUBREG_PROMOTED_VAR_P (lopart1) = 1;
-	      SUBREG_PROMOTED_SET (lopart1, 0);
+	      lopart1s = shallow_copy_rtx (lopart1);
+	      SUBREG_PROMOTED_VAR_P (lopart1s) = 1;
+	      SUBREG_PROMOTED_SET (lopart1s, uns ? SRP_UNSIGNED : SRP_SIGNED);
 	    }
-	  tree halfstype = build_nonstandard_integer_type (hprec, 0);
-	  ops.op0 = make_tree (halfstype, lopart0);
-	  ops.op1 = make_tree (halfstype, lopart1);
+	  tree halfstype = build_nonstandard_integer_type (hprec, uns);
+	  ops.op0 = make_tree (halfstype, lopart0s);
+	  ops.op1 = make_tree (halfstype, lopart1s);
 	  ops.code = WIDEN_MULT_EXPR;
-	  ops.type = TREE_TYPE (arg0);
+	  ops.type = type;
 	  rtx thisres
 	    = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
 	  emit_move_insn (res, thisres);
@@ -646,9 +1356,9 @@  ubsan_expand_si_overflow_mul_check (gimp
 
 	  emit_label (small_op0_large_op1);
 
-	  /* If op0 is sign extended from hmode to mode, but op1 is not,
-	     just swap the arguments and handle it as op1 sign extended,
-	     op0 not.  */
+	  /* If op0 is sign (!uns) or zero (uns) extended from hmode to mode,
+	     but op1 is not, just swap the arguments and handle it as op1
+	     sign/zero extended, op0 not.  */
 	  rtx larger = gen_reg_rtx (mode);
 	  rtx hipart = gen_reg_rtx (hmode);
 	  rtx lopart = gen_reg_rtx (hmode);
@@ -663,9 +1373,9 @@  ubsan_expand_si_overflow_mul_check (gimp
 	    emit_cmp_and_jump_insns (signbit1, hipart1, NE, NULL_RTX, hmode,
 				     false, both_ops_large, PROB_UNLIKELY);
 
-	  /* If op1 is sign extended from hmode to mode, but op0 is not,
-	     prepare larger, hipart and lopart pseudos and handle it together
-	     with small_op0_large_op1.  */
+	  /* If op1 is sign (!uns) or zero (uns) extended from hmode to mode,
+	     but op0 is not, prepare larger, hipart and lopart pseudos and
+	     handle it together with small_op0_large_op1.  */
 	  emit_move_insn (larger, op0);
 	  emit_move_insn (hipart, hipart0);
 	  emit_move_insn (lopart, lopart1);
@@ -690,33 +1400,38 @@  ubsan_expand_si_overflow_mul_check (gimp
 	  rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
 	  emit_move_insn (loxhi, tem);
 
-	  /* if (hipart < 0) loxhi -= lopart << (bitsize / 2);  */
-	  if (larger_sign == 0)
-	    emit_jump (after_hipart_neg);
-	  else if (larger_sign != -1)
-	    emit_cmp_and_jump_insns (hipart, const0_rtx, GE, NULL_RTX, hmode,
-				     false, after_hipart_neg, PROB_EVEN);
-
-	  tem = convert_modes (mode, hmode, lopart, 1);
-	  tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
-	  tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
-				     1, OPTAB_DIRECT);
-	  emit_move_insn (loxhi, tem);
-
-	  emit_label (after_hipart_neg);
-
-	  /* if (lopart < 0) loxhi -= larger;  */
-	  if (smaller_sign == 0)
-	    emit_jump (after_lopart_neg);
-	  else if (smaller_sign != -1)
-	    emit_cmp_and_jump_insns (lopart, const0_rtx, GE, NULL_RTX, hmode,
-				     false, after_lopart_neg, PROB_EVEN);
-
-	  tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
-				     1, OPTAB_DIRECT);
-	  emit_move_insn (loxhi, tem);
+	  if (!uns)
+	    {
+	      /* if (hipart < 0) loxhi -= lopart << (bitsize / 2);  */
+	      if (larger_sign == 0)
+		emit_jump (after_hipart_neg);
+	      else if (larger_sign != -1)
+		emit_cmp_and_jump_insns (hipart, const0_rtx, GE, NULL_RTX,
+					 hmode, false, after_hipart_neg,
+					 PROB_EVEN);
+
+	      tem = convert_modes (mode, hmode, lopart, 1);
+	      tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
+	      tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
+					 1, OPTAB_DIRECT);
+	      emit_move_insn (loxhi, tem);
+
+	      emit_label (after_hipart_neg);
+
+	      /* if (lopart < 0) loxhi -= larger;  */
+	      if (smaller_sign == 0)
+		emit_jump (after_lopart_neg);
+	      else if (smaller_sign != -1)
+		emit_cmp_and_jump_insns (lopart, const0_rtx, GE, NULL_RTX,
+					 hmode, false, after_lopart_neg,
+					 PROB_EVEN);
+
+	      tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
+					 1, OPTAB_DIRECT);
+	      emit_move_insn (loxhi, tem);
 
-	  emit_label (after_lopart_neg);
+	      emit_label (after_lopart_neg);
+	    }
 
 	  /* loxhi += (uns) lo0xlo1 >> (bitsize / 2);  */
 	  tem = expand_shift (RSHIFT_EXPR, mode, lo0xlo1, hprec, NULL_RTX, 1);
@@ -725,13 +1440,16 @@  ubsan_expand_si_overflow_mul_check (gimp
 	  emit_move_insn (loxhi, tem);
 
 	  /* if (loxhi >> (bitsize / 2)
-		 == (hmode) loxhi >> (bitsize / 2 - 1))  */
+		 == (hmode) loxhi >> (bitsize / 2 - 1))  (if !uns)
+	     if (loxhi >> (bitsize / 2) == 0		 (if uns).  */
 	  rtx hipartloxhi = expand_shift (RSHIFT_EXPR, mode, loxhi, hprec,
 					  NULL_RTX, 0);
 	  hipartloxhi = gen_lowpart (hmode, hipartloxhi);
-	  rtx lopartloxhi = gen_lowpart (hmode, loxhi);
-	  rtx signbitloxhi = expand_shift (RSHIFT_EXPR, hmode, lopartloxhi,
-					   hprec - 1, NULL_RTX, 0);
+	  rtx signbitloxhi = const0_rtx;
+	  if (!uns)
+	    signbitloxhi = expand_shift (RSHIFT_EXPR, hmode,
+					 gen_lowpart (hmode, loxhi),
+					 hprec - 1, NULL_RTX, 0);
 
 	  emit_cmp_and_jump_insns (signbitloxhi, hipartloxhi, NE, NULL_RTX,
 				   hmode, false, do_overflow,
@@ -750,82 +1468,131 @@  ubsan_expand_si_overflow_mul_check (gimp
 
 	  emit_label (both_ops_large);
 
-	  /* If both operands are large (not sign extended from hmode),
-	     then perform the full multiplication which will be the result
-	     of the operation.  The only cases which don't overflow are
-	     some cases where both hipart0 and highpart1 are 0 or -1.  */
+	  /* If both operands are large (not sign (!uns) or zero (uns)
+	     extended from hmode), then perform the full multiplication
+	     which will be the result of the operation.
+	     The only cases which don't overflow are for signed multiplication
+	     some cases where both hipart0 and highpart1 are 0 or -1.
+	     For unsigned multiplication when high parts are both non-zero
+	     this overflows always.  */
 	  ops.code = MULT_EXPR;
-	  ops.op0 = make_tree (TREE_TYPE (arg0), op0);
-	  ops.op1 = make_tree (TREE_TYPE (arg0), op1);
+	  ops.op0 = make_tree (type, op0);
+	  ops.op1 = make_tree (type, op1);
 	  tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
 	  emit_move_insn (res, tem);
 
-	  if (!op0_medium_p)
+	  if (!uns)
 	    {
-	      tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
-					 NULL_RTX, 1, OPTAB_DIRECT);
-	      emit_cmp_and_jump_insns (tem, const1_rtx, GTU, NULL_RTX, hmode,
-				       true, do_error, PROB_VERY_UNLIKELY);
-	    }
-
-	  if (!op1_medium_p)
-	    {
-	      tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
-					 NULL_RTX, 1, OPTAB_DIRECT);
-	      emit_cmp_and_jump_insns (tem, const1_rtx, GTU, NULL_RTX, hmode,
-				       true, do_error, PROB_VERY_UNLIKELY);
-	    }
-
-	  /* At this point hipart{0,1} are both in [-1, 0].  If they are the
-	     same, overflow happened if res is negative, if they are different,
-	     overflow happened if res is positive.  */
-	  if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
-	    emit_jump (hipart_different);
-	  else if (op0_sign == 1 || op1_sign == 1)
-	    emit_cmp_and_jump_insns (hipart0, hipart1, NE, NULL_RTX, hmode,
-				     true, hipart_different, PROB_EVEN);
-
-	  emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode, false,
-				   do_error, PROB_VERY_UNLIKELY);
-	  emit_jump (done_label);
+	      if (!op0_medium_p)
+		{
+		  tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
+					     NULL_RTX, 1, OPTAB_DIRECT);
+		  emit_cmp_and_jump_insns (tem, const1_rtx, GTU, NULL_RTX,
+					   hmode, true, do_error,
+					   PROB_VERY_UNLIKELY);
+		}
 
-	  emit_label (hipart_different);
+	      if (!op1_medium_p)
+		{
+		  tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
+					     NULL_RTX, 1, OPTAB_DIRECT);
+		  emit_cmp_and_jump_insns (tem, const1_rtx, GTU, NULL_RTX,
+					   hmode, true, do_error,
+					   PROB_VERY_UNLIKELY);
+		}
 
-	  emit_cmp_and_jump_insns (res, const0_rtx, GE, NULL_RTX, mode, false,
-				   do_error, PROB_VERY_UNLIKELY);
-	  emit_jump (done_label);
+	      /* At this point hipart{0,1} are both in [-1, 0].  If they are
+		 the same, overflow happened if res is negative, if they are
+		 different, overflow happened if res is positive.  */
+	      if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
+		emit_jump (hipart_different);
+	      else if (op0_sign == 1 || op1_sign == 1)
+		emit_cmp_and_jump_insns (hipart0, hipart1, NE, NULL_RTX, hmode,
+					 true, hipart_different, PROB_EVEN);
+
+	      emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode,
+				       false, do_error, PROB_VERY_UNLIKELY);
+	      emit_jump (done_label);
+
+	      emit_label (hipart_different);
+
+	      emit_cmp_and_jump_insns (res, const0_rtx, GE, NULL_RTX, mode,
+				       false, do_error, PROB_VERY_UNLIKELY);
+	      emit_jump (done_label);
+	    }
 
 	  emit_label (do_overflow);
 
 	  /* Overflow, do full multiplication and fallthru into do_error.  */
-	  ops.op0 = make_tree (TREE_TYPE (arg0), op0);
-	  ops.op1 = make_tree (TREE_TYPE (arg0), op1);
+	  ops.op0 = make_tree (type, op0);
+	  ops.op1 = make_tree (type, op1);
 	  tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
 	  emit_move_insn (res, tem);
 	}
       else
 	{
+	  gcc_assert (!is_ubsan);
 	  ops.code = MULT_EXPR;
-	  ops.type = TREE_TYPE (arg0);
+	  ops.type = type;
 	  res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
 	  emit_jump (done_label);
 	}
     }
 
+ do_error_label:
   emit_label (do_error);
-  /* Expand the ubsan builtin call.  */
-  push_temp_slots ();
-  fn = ubsan_build_overflow_builtin (MULT_EXPR, gimple_location (stmt),
-				     TREE_TYPE (arg0), arg0, arg1);
-  expand_normal (fn);
-  pop_temp_slots ();
-  do_pending_stack_adjust ();
+  if (is_ubsan)
+    {
+      /* Expand the ubsan builtin call.  */
+      push_temp_slots ();
+      fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (arg0),
+					 arg0, arg1);
+      expand_normal (fn);
+      pop_temp_slots ();
+      do_pending_stack_adjust ();
+    }
+  else if (lhs)
+    write_complex_part (target, const1_rtx, true);
 
   /* We're done.  */
   emit_label (done_label);
 
+  /* u1 * u2 -> sr  */
+  if (uns0_p && uns1_p && !unsr_p)
+    {
+      rtx_code_label *all_done_label = gen_label_rtx ();
+      emit_cmp_and_jump_insns (res, const0_rtx, GE, NULL_RTX, mode,
+			       false, all_done_label, PROB_VERY_LIKELY);
+      write_complex_part (target, const1_rtx, true);
+      emit_label (all_done_label);
+    }
+
+  /* s1 * u2 -> sr  */
+  if (!uns0_p && uns1_p && !unsr_p && pos_neg1 == 3)
+    {
+      rtx_code_label *all_done_label = gen_label_rtx ();
+      rtx_code_label *set_noovf = gen_label_rtx ();
+      emit_cmp_and_jump_insns (op1, const0_rtx, GE, NULL_RTX, mode,
+			       false, all_done_label, PROB_VERY_LIKELY);
+      write_complex_part (target, const1_rtx, true);
+      emit_cmp_and_jump_insns (op0, const0_rtx, EQ, NULL_RTX, mode,
+			       false, set_noovf, PROB_VERY_LIKELY);
+      emit_cmp_and_jump_insns (op0, constm1_rtx, NE, NULL_RTX, mode,
+			       false, all_done_label, PROB_VERY_UNLIKELY);
+      emit_cmp_and_jump_insns (op1, res, NE, NULL_RTX, mode,
+			       false, all_done_label, PROB_VERY_UNLIKELY);
+      emit_label (set_noovf);
+      write_complex_part (target, const0_rtx, true);
+      emit_label (all_done_label);
+    }
+
   if (lhs)
-    emit_move_insn (target, res);
+    {
+      if (is_ubsan)
+	emit_move_insn (target, res);
+      else
+	expand_arith_overflow_result_store (lhs, target, mode, res);
+    }
 }
 
 /* Expand UBSAN_CHECK_ADD call STMT.  */
@@ -833,7 +1600,12 @@  ubsan_expand_si_overflow_mul_check (gimp
 static void
 expand_UBSAN_CHECK_ADD (gimple stmt)
 {
-  ubsan_expand_si_overflow_addsub_check (PLUS_EXPR, stmt);
+  location_t loc = gimple_location (stmt);
+  tree lhs = gimple_call_lhs (stmt);
+  tree arg0 = gimple_call_arg (stmt, 0);
+  tree arg1 = gimple_call_arg (stmt, 1);
+  expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1,
+			  false, false, false, true);
 }
 
 /* Expand UBSAN_CHECK_SUB call STMT.  */
@@ -841,10 +1613,15 @@  expand_UBSAN_CHECK_ADD (gimple stmt)
 static void
 expand_UBSAN_CHECK_SUB (gimple stmt)
 {
-  if (integer_zerop (gimple_call_arg (stmt, 0)))
-    ubsan_expand_si_overflow_neg_check (stmt);
+  location_t loc = gimple_location (stmt);
+  tree lhs = gimple_call_lhs (stmt);
+  tree arg0 = gimple_call_arg (stmt, 0);
+  tree arg1 = gimple_call_arg (stmt, 1);
+  if (integer_zerop (arg0))
+    expand_neg_overflow (loc, lhs, arg1, true);
   else
-    ubsan_expand_si_overflow_addsub_check (MINUS_EXPR, stmt);
+    expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1,
+			    false, false, false, true);
 }
 
 /* Expand UBSAN_CHECK_MUL call STMT.  */
@@ -852,7 +1629,208 @@  expand_UBSAN_CHECK_SUB (gimple stmt)
 static void
 expand_UBSAN_CHECK_MUL (gimple stmt)
 {
-  ubsan_expand_si_overflow_mul_check (stmt);
+  location_t loc = gimple_location (stmt);
+  tree lhs = gimple_call_lhs (stmt);
+  tree arg0 = gimple_call_arg (stmt, 0);
+  tree arg1 = gimple_call_arg (stmt, 1);
+  expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true);
+}
+
+/* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion.  */
+
+static void
+expand_arith_overflow (enum tree_code code, gimple stmt)
+{
+  tree lhs = gimple_call_lhs (stmt);
+  if (lhs == NULL_TREE)
+    return;
+  tree arg0 = gimple_call_arg (stmt, 0);
+  tree arg1 = gimple_call_arg (stmt, 1);
+  tree type = TREE_TYPE (TREE_TYPE (lhs));
+  int uns0_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
+  int uns1_p = TYPE_UNSIGNED (TREE_TYPE (arg1));
+  int unsr_p = TYPE_UNSIGNED (type);
+  int prec0 = TYPE_PRECISION (TREE_TYPE (arg0));
+  int prec1 = TYPE_PRECISION (TREE_TYPE (arg1));
+  int precres = TYPE_PRECISION (type);
+  location_t loc = gimple_location (stmt);
+  if (!uns0_p && get_range_pos_neg (arg0) == 1)
+    uns0_p = true;
+  if (!uns1_p && get_range_pos_neg (arg1) == 1)
+    uns1_p = true;
+  int pr = get_min_precision (arg0, uns0_p ? UNSIGNED : SIGNED);
+  prec0 = MIN (prec0, pr);
+  pr = get_min_precision (arg1, uns1_p ? UNSIGNED : SIGNED);
+  prec1 = MIN (prec1, pr);
+
+  /* If uns0_p && uns1_p, precop is minimum needed precision
+     of unsigned type to hold the exact result, otherwise
+     precop is minimum needed precision of signed type to
+     hold the exact result.  */
+  int precop;
+  if (code == MULT_EXPR)
+    precop = prec0 + prec1 + (uns0_p != uns1_p);
+  else
+    {
+      if (uns0_p == uns1_p)
+	precop = MAX (prec0, prec1) + 1;
+      else if (uns0_p)
+	precop = MAX (prec0 + 1, prec1) + 1;
+      else
+	precop = MAX (prec0, prec1 + 1) + 1;
+    }
+  int orig_precres = precres;
+
+  do
+    {
+      if ((uns0_p && uns1_p)
+	  ? ((precop + !unsr_p) <= precres
+	     /* u1 - u2 -> ur can overflow, no matter what precision
+		the result has.  */
+	     && (code != MINUS_EXPR || !unsr_p))
+	  : (!unsr_p && precop <= precres))
+	{
+	  /* The infinity precision result will always fit into result.  */
+	  rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+	  write_complex_part (target, const0_rtx, true);
+	  enum machine_mode mode = TYPE_MODE (type);
+	  struct separate_ops ops;
+	  ops.code = code;
+	  ops.type = type;
+	  ops.op0 = fold_convert_loc (loc, type, arg0);
+	  ops.op1 = fold_convert_loc (loc, type, arg1);
+	  ops.op2 = NULL_TREE;
+	  ops.location = loc;
+	  rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
+	  expand_arith_overflow_result_store (lhs, target, mode, tem);
+	  return;
+	}
+
+#ifdef WORD_REGISTER_OPERATIONS
+      /* For sub-word operations, if target doesn't have them, start
+	 with precres widening right away, otherwise do it only
+	 if the most simple cases can't be used.  */
+      if (orig_precres == precres && precres < BITS_PER_WORD)
+	;
+      else
+#endif
+      if ((uns0_p && uns1_p && unsr_p && prec0 <= precres && prec1 <= precres)
+	  || ((!uns0_p || !uns1_p) && !unsr_p
+	      && prec0 + uns0_p <= precres
+	      && prec1 + uns1_p <= precres))
+	{
+	  arg0 = fold_convert_loc (loc, type, arg0);
+	  arg1 = fold_convert_loc (loc, type, arg1);
+	  switch (code)
+	    {
+	    case MINUS_EXPR:
+	      if (integer_zerop (arg0) && !unsr_p)
+		expand_neg_overflow (loc, lhs, arg1, false);
+	      /* FALLTHRU */
+	    case PLUS_EXPR:
+	      expand_addsub_overflow (loc, code, lhs, arg0, arg1,
+				      unsr_p, unsr_p, unsr_p, false);
+	      return;
+	    case MULT_EXPR:
+	      expand_mul_overflow (loc, lhs, arg0, arg1,
+				   unsr_p, unsr_p, unsr_p, false);
+	      return;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+
+      /* For sub-word operations, retry with a wider type first.  */
+      if (orig_precres == precres && precop <= BITS_PER_WORD)
+	{
+#ifdef WORD_REGISTER_OPERATIONS
+	  int p = BITS_PER_WORD;
+#else
+	  int p = precop;
+#endif
+	  enum machine_mode m = smallest_mode_for_size (p, MODE_INT);
+	  tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
+							uns0_p && uns1_p
+							&& unsr_p);
+	  p = TYPE_PRECISION (optype);
+	  if (p > precres)
+	    {
+	      precres = p;
+	      unsr_p = TYPE_UNSIGNED (optype);
+	      type = optype;
+	      continue;
+	    }
+	}
+
+      if (prec0 <= precres && prec1 <= precres)
+	{
+	  tree types[2];
+	  if (unsr_p)
+	    {
+	      types[0] = build_nonstandard_integer_type (precres, 0);
+	      types[1] = type;
+	    }
+	  else
+	    {
+	      types[0] = type;
+	      types[1] = build_nonstandard_integer_type (precres, 1);
+	    }
+	  arg0 = fold_convert_loc (loc, types[uns0_p], arg0);
+	  arg1 = fold_convert_loc (loc, types[uns1_p], arg1);
+	  if (code != MULT_EXPR)
+	    expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
+				    uns0_p, uns1_p, false);
+	  else
+	    expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
+				 uns0_p, uns1_p, false);
+	  return;
+	}
+
+      /* Retry with a wider type.  */
+      if (orig_precres == precres)
+	{
+	  int p = MAX (prec0, prec1);
+	  enum machine_mode m = smallest_mode_for_size (p, MODE_INT);
+	  tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
+							uns0_p && uns1_p
+							&& unsr_p);
+	  p = TYPE_PRECISION (optype);
+	  if (p > precres)
+	    {
+	      precres = p;
+	      unsr_p = TYPE_UNSIGNED (optype);
+	      type = optype;
+	      continue;
+	    }
+	}
+
+      gcc_unreachable ();
+    }
+  while (1);
+}
+
+/* Expand ADD_OVERFLOW STMT.  */
+
+static void
+expand_ADD_OVERFLOW (gimple stmt)
+{
+  expand_arith_overflow (PLUS_EXPR, stmt);
+}
+
+/* Expand SUB_OVERFLOW STMT.  */
+
+static void
+expand_SUB_OVERFLOW (gimple stmt)
+{
+  expand_arith_overflow (MINUS_EXPR, stmt);
+}
+
+/* Expand MUL_OVERFLOW STMT.  */
+
+static void
+expand_MUL_OVERFLOW (gimple stmt)
+{
+  expand_arith_overflow (MULT_EXPR, stmt);
 }
 
 /* This should get folded in tree-vectorizer.c.  */
--- gcc/internal-fn.def.jj	2014-10-10 19:42:22.000000000 +0200
+++ gcc/internal-fn.def	2014-10-30 15:27:28.173658758 +0100
@@ -57,3 +57,6 @@  DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_
 DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".W...")
+DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
--- gcc/tree-vrp.c.jj	2014-10-31 09:49:52.000000000 +0100
+++ gcc/tree-vrp.c	2014-11-10 09:42:38.190965111 +0100
@@ -3753,6 +3753,113 @@  extract_range_from_comparison (value_ran
     set_value_range_to_truthvalue (vr, type);
 }
 
+/* Helper function for simplify_internal_call_using_ranges and
+   extract_range_basic.  Return true if OP0 SUBCODE OP1 for
+   SUBCODE {PLUS,MINUS,MULT}_EXPR is known to never overflow or
+   always overflow.  Set *OVF to true if it is known to always
+   overflow.  */
+
+static bool
+check_for_binary_op_overflow (enum tree_code subcode, tree type,
+			      tree op0, tree op1, bool *ovf)
+{
+  value_range_t vr0 = VR_INITIALIZER;
+  value_range_t vr1 = VR_INITIALIZER;
+  if (TREE_CODE (op0) == SSA_NAME)
+    vr0 = *get_value_range (op0);
+  else if (TREE_CODE (op0) == INTEGER_CST)
+    set_value_range_to_value (&vr0, op0, NULL);
+  else
+    set_value_range_to_varying (&vr0);
+
+  if (TREE_CODE (op1) == SSA_NAME)
+    vr1 = *get_value_range (op1);
+  else if (TREE_CODE (op1) == INTEGER_CST)
+    set_value_range_to_value (&vr1, op1, NULL);
+  else
+    set_value_range_to_varying (&vr1);
+
+  if (!range_int_cst_p (&vr0)
+      || TREE_OVERFLOW (vr0.min)
+      || TREE_OVERFLOW (vr0.max))
+    {
+      vr0.min = vrp_val_min (TREE_TYPE (op0));
+      vr0.max = vrp_val_max (TREE_TYPE (op0));
+    }
+  if (!range_int_cst_p (&vr1)
+      || TREE_OVERFLOW (vr1.min)
+      || TREE_OVERFLOW (vr1.max))
+    {
+      vr1.min = vrp_val_min (TREE_TYPE (op1));
+      vr1.max = vrp_val_max (TREE_TYPE (op1));
+    }
+  *ovf = arith_overflowed_p (subcode, type, vr0.min,
+			     subcode == MINUS_EXPR ? vr1.max : vr1.min);
+  if (arith_overflowed_p (subcode, type, vr0.max,
+			  subcode == MINUS_EXPR ? vr1.min : vr1.max) != *ovf)
+    return false;
+  if (subcode == MULT_EXPR)
+    {
+      if (arith_overflowed_p (subcode, type, vr0.min, vr1.max) != *ovf
+	  || arith_overflowed_p (subcode, type, vr0.max, vr1.min) != *ovf)
+	return false;
+    }
+  if (*ovf)
+    {
+      /* So far we found that there is an overflow on the boundaries.
+	 That doesn't prove that there is an overflow even for all values
+	 in between the boundaries.  For that compute widest_int range
+	 of the result and see if it doesn't overlap the range of
+	 type.  */
+      widest_int wmin, wmax;
+      widest_int w[4];
+      int i;
+      w[0] = wi::to_widest (vr0.min);
+      w[1] = wi::to_widest (vr0.max);
+      w[2] = wi::to_widest (vr1.min);
+      w[3] = wi::to_widest (vr1.max);
+      for (i = 0; i < 4; i++)
+	{
+	  widest_int wt;
+	  switch (subcode)
+	    {
+	    case PLUS_EXPR:
+	      wt = wi::add (w[i & 1], w[2 + (i & 2) / 2]);
+	      break;
+	    case MINUS_EXPR:
+	      wt = wi::sub (w[i & 1], w[2 + (i & 2) / 2]);
+	      break;
+	    case MULT_EXPR:
+	      wt = wi::mul (w[i & 1], w[2 + (i & 2) / 2]);
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	  if (i == 0)
+	    {
+	      wmin = wt;
+	      wmax = wt;
+	    }
+	  else
+	    {
+	      wmin = wi::smin (wmin, wt);
+	      wmax = wi::smax (wmax, wt);
+	    }
+	}
+      /* The result of op0 CODE op1 is known to be in range
+	 [wmin, wmax].  */
+      widest_int wtmin = wi::to_widest (vrp_val_min (type));
+      widest_int wtmax = wi::to_widest (vrp_val_max (type));
+      /* If all values in [wmin, wmax] are smaller than
+	 [wtmin, wtmax] or all are larger than [wtmin, wtmax],
+	 the arithmetic operation will always overflow.  */
+      if (wi::lts_p (wmax, wtmin) || wi::gts_p (wmin, wtmax))
+	return true;
+      return false;
+    }
+  return true;
+}
+
 /* Try to derive a nonnegative or nonzero range out of STMT relying
    primarily on generic routines in fold in conjunction with range data.
    Store the result in *VR */
@@ -3942,8 +4049,7 @@  extract_range_basic (value_range_t *vr,
 	  break;
 	}
     }
-  else if (is_gimple_call (stmt)
-	   && gimple_call_internal_p (stmt))
+  else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
     {
       enum tree_code subcode = ERROR_MARK;
       switch (gimple_call_internal_fn (stmt))
@@ -3983,6 +4089,84 @@  extract_range_basic (value_range_t *vr,
 	  return;
 	}
     }
+  /* Handle extraction of the two results (result of arithmetics and
+     a flag whether arithmetics overflowed) from {ADD,SUB,MUL}_OVERFLOW
+     internal function.  */
+  else if (is_gimple_assign (stmt)
+	   && (gimple_assign_rhs_code (stmt) == REALPART_EXPR
+	       || gimple_assign_rhs_code (stmt) == IMAGPART_EXPR)
+	   && INTEGRAL_TYPE_P (type))
+    {
+      enum tree_code code = gimple_assign_rhs_code (stmt);
+      tree op = gimple_assign_rhs1 (stmt);
+      if (TREE_CODE (op) == code && TREE_CODE (TREE_OPERAND (op, 0)) == SSA_NAME)
+	{
+	  gimple g = SSA_NAME_DEF_STMT (TREE_OPERAND (op, 0));
+	  if (is_gimple_call (g) && gimple_call_internal_p (g))
+	    {
+	      enum tree_code subcode = ERROR_MARK;
+	      switch (gimple_call_internal_fn (g))
+		{
+		case IFN_ADD_OVERFLOW:
+		  subcode = PLUS_EXPR;
+		  break;
+		case IFN_SUB_OVERFLOW:
+		  subcode = MINUS_EXPR;
+		  break;
+		case IFN_MUL_OVERFLOW:
+		  subcode = MULT_EXPR;
+		  break;
+		default:
+		  break;
+		}
+	      if (subcode != ERROR_MARK)
+		{
+		  tree op0 = gimple_call_arg (g, 0);
+		  tree op1 = gimple_call_arg (g, 1);
+		  if (code == IMAGPART_EXPR)
+		    {
+		      bool ovf = false;
+		      if (check_for_binary_op_overflow (subcode, type,
+							op0, op1, &ovf))
+			set_value_range_to_value (vr,
+						  build_int_cst (type, ovf),
+						  NULL);
+		      else
+			set_value_range (vr, VR_RANGE, build_int_cst (type, 0),
+					 build_int_cst (type, 1), NULL);
+		    }
+		  else if (types_compatible_p (type, TREE_TYPE (op0))
+			   && types_compatible_p (type, TREE_TYPE (op1)))
+		    {
+		      bool saved_flag_wrapv = flag_wrapv;
+		      /* Pretend the arithmetics is wrapping.  If there is
+			 any overflow, IMAGPART_EXPR will be set.  */
+		      flag_wrapv = 1;
+		      extract_range_from_binary_expr (vr, subcode, type,
+						      op0, op1);
+		      flag_wrapv = saved_flag_wrapv;
+		    }
+		  else
+		    {
+		      value_range_t vr0 = VR_INITIALIZER;
+		      value_range_t vr1 = VR_INITIALIZER;
+		      bool saved_flag_wrapv = flag_wrapv;
+		      /* Pretend the arithmetics is wrapping.  If there is
+			 any overflow, IMAGPART_EXPR will be set.  */
+		      flag_wrapv = 1;
+		      extract_range_from_unary_expr (&vr0, NOP_EXPR,
+						     type, op0);
+		      extract_range_from_unary_expr (&vr1, NOP_EXPR,
+						     type, op1);
+		      extract_range_from_binary_expr_1 (vr, subcode, type,
+							&vr0, &vr1);
+		      flag_wrapv = saved_flag_wrapv;
+		    }
+		  return;
+		}
+	    }
+	}
+    }
   if (INTEGRAL_TYPE_P (type)
       && gimple_stmt_nonnegative_warnv_p (stmt, &sop))
     set_value_range_to_nonnegative (vr, type,
@@ -9476,87 +9660,100 @@  static bool
 simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
 {
   enum tree_code subcode;
+  bool is_ubsan = false;
+  bool ovf = false;
   switch (gimple_call_internal_fn (stmt))
     {
     case IFN_UBSAN_CHECK_ADD:
       subcode = PLUS_EXPR;
+      is_ubsan = true;
       break;
     case IFN_UBSAN_CHECK_SUB:
       subcode = MINUS_EXPR;
+      is_ubsan = true;
       break;
     case IFN_UBSAN_CHECK_MUL:
       subcode = MULT_EXPR;
+      is_ubsan = true;
+      break;
+    case IFN_ADD_OVERFLOW:
+      subcode = PLUS_EXPR;
+      break;
+    case IFN_SUB_OVERFLOW:
+      subcode = MINUS_EXPR;
+      break;
+    case IFN_MUL_OVERFLOW:
+      subcode = MULT_EXPR;
       break;
     default:
       return false;
     }
 
-  value_range_t vr0 = VR_INITIALIZER;
-  value_range_t vr1 = VR_INITIALIZER;
   tree op0 = gimple_call_arg (stmt, 0);
   tree op1 = gimple_call_arg (stmt, 1);
-
-  if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *get_value_range (op0);
-  else if (TREE_CODE (op0) == INTEGER_CST)
-    set_value_range_to_value (&vr0, op0, NULL);
-  else
-    set_value_range_to_varying (&vr0);
-
-  if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *get_value_range (op1);
-  else if (TREE_CODE (op1) == INTEGER_CST)
-    set_value_range_to_value (&vr1, op1, NULL);
+  tree type;
+  if (is_ubsan)
+    type = TREE_TYPE (op0);
+  else if (gimple_call_lhs (stmt) == NULL_TREE)
+    return false;
   else
-    set_value_range_to_varying (&vr1);
+    type = TREE_TYPE (TREE_TYPE (gimple_call_lhs (stmt)));
+  if (!check_for_binary_op_overflow (subcode, type, op0, op1, &ovf)
+      || (is_ubsan && ovf))
+    return false;
 
-  if (!range_int_cst_p (&vr0))
-    {
-      /* If one range is VR_ANTI_RANGE, VR_VARYING etc.,
-	 optimize at least x = y + 0; x = y - 0; x = y * 0;
-	 and x = y * 1; which never overflow.  */
-      if (!range_int_cst_p (&vr1))
-	return false;
-      if (tree_int_cst_sgn (vr1.min) == -1)
-	return false;
-      if (compare_tree_int (vr1.max, subcode == MULT_EXPR) == 1)
-	return false;
-    }
-  else if (!range_int_cst_p (&vr1))
-    {
-      /* If one range is VR_ANTI_RANGE, VR_VARYING etc.,
-	 optimize at least x = 0 + y; x = 0 * y; and x = 1 * y;
-	 which never overflow.  */
-      if (subcode == MINUS_EXPR)
-	return false;
-      if (!range_int_cst_p (&vr0))
-	return false;
-      if (tree_int_cst_sgn (vr0.min) == -1)
-	return false;
-      if (compare_tree_int (vr0.max, subcode == MULT_EXPR) == 1)
-	return false;
-    }
+  gimple g;
+  location_t loc = gimple_location (stmt);
+  if (is_ubsan)
+    g = gimple_build_assign_with_ops (subcode, gimple_call_lhs (stmt),
+				      op0, op1);
   else
     {
-      tree r1 = int_const_binop (subcode, vr0.min,
-				 subcode == MINUS_EXPR ? vr1.max : vr1.min);
-      tree r2 = int_const_binop (subcode, vr0.max,
-				 subcode == MINUS_EXPR ? vr1.min : vr1.max);
-      if (r1 == NULL_TREE || TREE_OVERFLOW (r1)
-	  || r2 == NULL_TREE || TREE_OVERFLOW (r2))
-	return false;
-      if (subcode == MULT_EXPR)
-	{
-	  tree r3 = int_const_binop (subcode, vr0.min, vr1.max);
-	  tree r4 = int_const_binop (subcode, vr0.max, vr1.min);
-	  if (r3 == NULL_TREE || TREE_OVERFLOW (r3)
-	      || r4 == NULL_TREE || TREE_OVERFLOW (r4))
-	    return false;
+      int prec = TYPE_PRECISION (type);
+      tree utype = type;
+      if (ovf
+	  || !useless_type_conversion_p (type, TREE_TYPE (op0))
+	  || !useless_type_conversion_p (type, TREE_TYPE (op1)))
+	utype = build_nonstandard_integer_type (prec, 1);
+      if (TREE_CODE (op0) == INTEGER_CST)
+	op0 = fold_convert (utype, op0);
+      else if (!useless_type_conversion_p (utype, TREE_TYPE (op0)))
+	{
+	  g = gimple_build_assign_with_ops (NOP_EXPR,
+					    make_ssa_name (utype, NULL),
+					    op0, NULL_TREE);
+	  gimple_set_location (g, loc);
+	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	  op0 = gimple_assign_lhs (g);
 	}
+      if (TREE_CODE (op1) == INTEGER_CST)
+	op1 = fold_convert (utype, op1);
+      else if (!useless_type_conversion_p (utype, TREE_TYPE (op1)))
+	{
+	  g = gimple_build_assign_with_ops (NOP_EXPR,
+					    make_ssa_name (utype, NULL),
+					    op1, NULL_TREE);
+	  gimple_set_location (g, loc);
+	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	  op1 = gimple_assign_lhs (g);
+	}
+      g = gimple_build_assign_with_ops (subcode, make_ssa_name (utype, NULL),
+					op0, op1);
+      gimple_set_location (g, loc);
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      if (utype != type)
+	{
+	  g = gimple_build_assign_with_ops (NOP_EXPR,
+					    make_ssa_name (type, NULL),
+					    gimple_assign_lhs (g), NULL_TREE);
+	  gimple_set_location (g, loc);
+	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	}
+      g = gimple_build_assign_with_ops (COMPLEX_EXPR, gimple_call_lhs (stmt),
+					gimple_assign_lhs (g),
+					build_int_cst (type, ovf));
     }
-
-  gimple g = gimple_build_assign_with_ops (subcode, gimple_call_lhs (stmt),
-					   op0, op1);
+  gimple_set_location (g, loc);
   gsi_replace (gsi, g, false);
   return true;
 }
--- gcc/optabs.def.jj	2014-10-28 14:40:00.000000000 +0100
+++ gcc/optabs.def	2014-11-03 10:52:06.311865217 +0100
@@ -190,6 +190,7 @@  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 (umulv4_optab, "umulv$I$a4")
 OPTAB_D (negv3_optab, "negv$I$a3")
 OPTAB_D (addptr3_optab, "addptr$a3")
 
--- gcc/config/i386/i386.md.jj	2014-10-30 14:42:30.000000000 +0100
+++ gcc/config/i386/i386.md	2014-11-04 10:11:37.272678588 +0100
@@ -6644,6 +6644,99 @@  (define_insn "*mulv<mode>4_1"
 		  (const_string "4")]
 	      (const_string "<MODE_SIZE>")))])
 
+(define_expand "umulv<mode>4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+		   (eq:CCO (mult:<DWI>
+			      (zero_extend:<DWI>
+				 (match_operand:SWI48 1
+						      "nonimmediate_operand"))
+			      (zero_extend:<DWI>
+				 (match_operand:SWI48 2
+						      "nonimmediate_operand")))
+			   (zero_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)))
+	      (clobber (match_scratch:SWI48 4))])
+   (set (pc) (if_then_else
+	       (eq (reg:CCO FLAGS_REG) (const_int 0))
+	       (label_ref (match_operand 3))
+	       (pc)))]
+  ""
+{
+  if (MEM_P (operands[1]) && MEM_P (operands[2]))
+    operands[1] = force_reg (<MODE>mode, operands[1]);
+})
+
+(define_insn "*umulv<mode>4"
+  [(set (reg:CCO FLAGS_REG)
+	(eq:CCO (mult:<DWI>
+		   (zero_extend:<DWI>
+		      (match_operand:SWI48 1 "nonimmediate_operand" "%0"))
+		   (zero_extend:<DWI>
+		      (match_operand:SWI48 2 "nonimmediate_operand" "rm")))
+		(zero_extend:<DWI>
+		   (mult:SWI48 (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SWI48 0 "register_operand" "=a")
+	(mult:SWI48 (match_dup 1) (match_dup 2)))
+   (clobber (match_scratch:SWI48 3 "=d"))]
+  "!(MEM_P (operands[1]) && MEM_P (operands[2]))"
+  "mul{<imodesuffix>}\t%2"
+  [(set_attr "type" "imul")
+   (set_attr "length_immediate" "0")
+   (set (attr "athlon_decode")
+     (if_then_else (eq_attr "cpu" "athlon")
+       (const_string "vector")
+       (const_string "double")))
+   (set_attr "amdfam10_decode" "double")
+   (set_attr "bdver1_decode" "direct")
+   (set_attr "mode" "<MODE>")])
+
+(define_expand "<u>mulvqi4"
+  [(parallel [(set (reg:CCO FLAGS_REG)
+		   (eq:CCO (mult:HI
+			      (any_extend:HI
+				 (match_operand:QI 1 "nonimmediate_operand"))
+			      (any_extend:HI
+				 (match_operand:QI 2 "nonimmediate_operand")))
+			   (any_extend:HI
+			      (mult:QI (match_dup 1) (match_dup 2)))))
+	      (set (match_operand:QI 0 "register_operand")
+		   (mult:QI (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)))]
+  "TARGET_QIMODE_MATH"
+{
+  if (MEM_P (operands[1]) && MEM_P (operands[2]))
+    operands[1] = force_reg (QImode, operands[1]);
+})
+
+(define_insn "*<u>mulvqi4"
+  [(set (reg:CCO FLAGS_REG)
+	(eq:CCO (mult:HI
+		   (any_extend:HI
+		      (match_operand:QI 1 "nonimmediate_operand" "%0"))
+		   (any_extend:HI
+		      (match_operand:QI 2 "nonimmediate_operand" "qm")))
+		(any_extend:HI
+		   (mult:QI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:QI 0 "register_operand" "=a")
+	(mult:QI (match_dup 1) (match_dup 2)))]
+  "TARGET_QIMODE_MATH
+   && !(MEM_P (operands[1]) && MEM_P (operands[2]))"
+  "<sgnprefix>mul{b}\t%2"
+  [(set_attr "type" "imul")
+   (set_attr "length_immediate" "0")
+   (set (attr "athlon_decode")
+     (if_then_else (eq_attr "cpu" "athlon")
+	(const_string "vector")
+	(const_string "direct")))
+   (set_attr "amdfam10_decode" "direct")
+   (set_attr "bdver1_decode" "direct")
+   (set_attr "mode" "QI")])
+
 (define_expand "<u>mul<mode><dwi>3"
   [(parallel [(set (match_operand:<DWI> 0 "register_operand")
 		   (mult:<DWI>
--- gcc/doc/extend.texi.jj	2014-10-10 08:19:20.000000000 +0200
+++ gcc/doc/extend.texi	2014-11-07 18:00:59.768652854 +0100
@@ -76,6 +76,8 @@  extensions, accepted by GCC in C90 mode
 * Offsetof::            Special syntax for implementing @code{offsetof}.
 * __sync Builtins::     Legacy built-in functions for atomic memory access.
 * __atomic Builtins::   Atomic built-in functions with memory model.
+* Integer Overflow Builtins:: Built-in functions to perform arithmetics and
+                        arithmetic overflow checking.
 * x86 specific memory model extensions for transactional memory:: x86 memory models.
 * Object Size Checking:: Built-in functions for limited buffer overflow
                         checking.
@@ -8444,6 +8446,65 @@  alignment.  A value of 0 indicates typic
 compiler may also ignore this parameter.
 @end deftypefn
 
+@node Integer Overflow Builtins
+@section Built-in functions to perform arithmetics and arithmetic overflow checking.
+
+The following built-in functions allow performing simple arithmetic operations
+together with checking whether the operations overflowed.
+
+@deftypefn {Built-in Function} bool __builtin_add_overflow (@var{type1} a, @var{type2} b, @var{type3} *res)
+@deftypefnx {Built-in Function} bool __builtin_sadd_overflow (int a, int b, int *res)
+@deftypefnx {Built-in Function} bool __builtin_saddl_overflow (long int a, long int b, long int *res)
+@deftypefnx {Built-in Function} bool __builtin_saddll_overflow (long long int a, long long int b, long int *res)
+@deftypefnx {Built-in Function} bool __builtin_uadd_overflow (unsigned int a, unsigned int b, unsigned int *res)
+@deftypefnx {Built-in Function} bool __builtin_uaddl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
+@deftypefnx {Built-in Function} bool __builtin_uaddll_overflow (unsigned long long int a, unsigned long long int b, unsigned long int *res)
+
+These built-in functions promote the first two operands into infinite precision signed
+type and perform addition on those promoted operands.  The result is then
+cast to the type the third pointer argument points to and stored there.
+If the stored result is equal to the infinite precision result, the built-in
+functions return false, otherwise they return true.  As the addition is
+performed in infinite signed precision, these built-in functions have fully defined
+behavior for all argument values.
+
+The first built-in function allows arbitrary integral types for operands and
+the result type must be pointer to some integer type, the rest of the built-in
+functions have explicit integer types.
+
+The compiler will attempt to use hardware instructions to implement
+these built-in functions where possible, like conditional jump on overflow
+after addition, conditional jump on carry etc.
+
+@end deftypefn
+
+@deftypefn {Built-in Function} bool __builtin_sub_overflow (@var{type1} a, @var{type2} b, @var{type3} *res)
+@deftypefnx {Built-in Function} bool __builtin_ssub_overflow (int a, int b, int *res)
+@deftypefnx {Built-in Function} bool __builtin_ssubl_overflow (long int a, long int b, long int *res)
+@deftypefnx {Built-in Function} bool __builtin_ssubll_overflow (long long int a, long long int b, long int *res)
+@deftypefnx {Built-in Function} bool __builtin_usub_overflow (unsigned int a, unsigned int b, unsigned int *res)
+@deftypefnx {Built-in Function} bool __builtin_usubl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
+@deftypefnx {Built-in Function} bool __builtin_usubll_overflow (unsigned long long int a, unsigned long long int b, unsigned long int *res)
+
+These built-in functions are similar to the add overflow checking built-in
+functions above, except they perform subtraction, subtract the second argument
+from the first one, instead of addition.
+
+@end deftypefn
+
+@deftypefn {Built-in Function} bool __builtin_mul_overflow (@var{type1} a, @var{type2} b, @var{type3} *res)
+@deftypefnx {Built-in Function} bool __builtin_smul_overflow (int a, int b, int *res)
+@deftypefnx {Built-in Function} bool __builtin_smull_overflow (long int a, long int b, long int *res)
+@deftypefnx {Built-in Function} bool __builtin_smulll_overflow (long long int a, long long int b, long int *res)
+@deftypefnx {Built-in Function} bool __builtin_umul_overflow (unsigned int a, unsigned int b, unsigned int *res)
+@deftypefnx {Built-in Function} bool __builtin_umull_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
+@deftypefnx {Built-in Function} bool __builtin_umulll_overflow (unsigned long long int a, unsigned long long int b, unsigned long int *res)
+
+These built-in functions are similar to the add overflow checking built-in
+functions above, except they perform multiplication, instead of addition.
+
+@end deftypefn
+
 @node x86 specific memory model extensions for transactional memory
 @section x86 specific memory model extensions for transactional memory
 
--- gcc/c-family/c-common.c.jj	2014-10-30 14:42:20.000000000 +0100
+++ gcc/c-family/c-common.c	2014-11-10 14:45:05.066375016 +0100
@@ -9577,6 +9577,30 @@  check_builtin_function_arguments (tree f
 	}
       return false;
 
+    case BUILT_IN_ADD_OVERFLOW:
+    case BUILT_IN_SUB_OVERFLOW:
+    case BUILT_IN_MUL_OVERFLOW:
+      if (builtin_function_validate_nargs (fndecl, nargs, 3))
+	{
+	  unsigned i;
+	  for (i = 0; i < 2; i++)
+	    if (!INTEGRAL_TYPE_P (TREE_TYPE (args[i])))
+	      {
+		error ("argument %u in call to function %qE does not have "
+		       "integral type", i + 1, fndecl);
+		return false;
+	      }
+	  if (TREE_CODE (TREE_TYPE (args[2])) != POINTER_TYPE
+	      || TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) != INTEGER_TYPE)
+	    {
+	      error ("argument 3 in call to function %qE does not have "
+		     "pointer to integer type", fndecl);
+	      return false;
+	    }
+	  return true;
+	}
+      return false;
+
     default:
       return true;
     }
--- gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c.jj	2014-11-10 14:46:19.707055522 +0100
+++ gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c	2014-11-10 14:46:14.251304496 +0100
@@ -0,0 +1,49 @@ 
+/* { dg-do compile } */
+
+int
+f1 (void)
+{
+  int x = __builtin_add_overflow ();	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_sub_overflow ();	/* { dg-error "not enough arguments to function" } */
+  x += __builtin_mul_overflow ();	/* { dg-error "not enough arguments to function" } */
+  return x;
+}
+
+int
+f2 (int a, int b, int *c, int d)
+{
+  int x = __builtin_add_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_sub_overflow (a, b, c, d, d, d);	/* { dg-error "too many arguments to function" } */
+  x += __builtin_mul_overflow (a, b, c, d);	/* { dg-error "too many arguments to function" } */
+  return x;
+}
+
+enum E { e0 = 0, e1 = 1 };
+
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+
+int
+f3 (float fa, int a, _Complex long int ca, double fb, void *pb, int b, enum E eb, bool bb, int *c)
+{
+  int x = __builtin_add_overflow (fa, b, c);	/* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */
+  x += __builtin_sub_overflow (ca, b, c);	/* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */
+  x += __builtin_mul_overflow (a, fb, c);	/* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */
+  x += __builtin_add_overflow (a, pb, c);	/* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */
+  x += __builtin_sub_overflow (a, eb, c);
+  x += __builtin_mul_overflow (a, bb, c);
+  return x;
+}
+
+int
+f4 (float *fp, double *dp, _Complex int *cp, enum E *ep, bool *bp, long long int *llp)
+{
+  int x = __builtin_add_overflow (1, 2, fp);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
+  x += __builtin_sub_overflow (1, 2, dp);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
+  x += __builtin_mul_overflow (1, 2, cp);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
+  x += __builtin_add_overflow (1, 2, ep);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
+  x += __builtin_sub_overflow (1, 2, bp);	/* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
+  x += __builtin_mul_overflow (1, 2, llp);
+  return x;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-10.c.jj	2014-11-05 11:04:22.654982970 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-10.c	2014-11-07 19:10:26.130018889 +0100
@@ -0,0 +1,19 @@ 
+/* Test __builtin_{add,sub}_overflow on {,un}signed long int.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+typedef signed long int S;
+typedef unsigned long int U;
+#define COND 1
+#define SHIFT ((__SIZEOF_LONG__ - 1) * __CHAR_BIT__)
+#define S_MAX __LONG_MAX__
+#define S_MIN (-__LONG_MAX__ - 1)
+#if __SIZEOF_LONG_LONG__ > __SIZEOF_LONG__
+typedef long long int W;
+#elif __SIZEOF_INT128__ > __SIZEOF_LONG__
+typedef __int128 W;
+#else
+#undef COND
+#define COND 0
+#endif
+#include "builtin-arith-overflow-7.c"
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-11.c.jj	2014-11-05 11:05:36.909635260 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-11.c	2014-11-07 19:10:26.131018871 +0100
@@ -0,0 +1,17 @@ 
+/* Test __builtin_{add,sub}_overflow on {,un}signed long long int.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+typedef signed long long int S;
+typedef unsigned long long int U;
+#define COND 1
+#define SHIFT ((__SIZEOF_LONG_LONG__ - 1) * __CHAR_BIT__)
+#define S_MAX __LONG_LONG_MAX__
+#define S_MIN (-__LONG_LONG_MAX__ - 1)
+#if __SIZEOF_INT128__ > __SIZEOF_LONG_LONG__
+typedef __int128 W;
+#else
+#undef COND
+#define COND 0
+#endif
+#include "builtin-arith-overflow-7.c"
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-12.c.jj	2014-11-07 19:19:14.087548729 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-12.c	2014-11-07 19:19:44.940993939 +0100
@@ -0,0 +1,17 @@ 
+/* Test __builtin_{add,sub,mul_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-12.h"
+
+TESTS (int, INT_MIN, INT_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (int, INT_MIN, INT_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-12.h.jj	2014-11-07 19:11:25.549953828 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-12.h	2014-11-10 13:41:24.000000000 +0100
@@ -0,0 +1,80 @@ 
+#include "builtin-arith-overflow.h"
+
+#define TESTS(type, min, max) \
+T (100, signed type, unsigned type, unsigned type, -1, 0, 0, mul, 0) \
+T (101, signed type, unsigned type, unsigned type, -1, 1, (unsigned type) -1, mul, 1) \
+T (102, unsigned type, signed type, unsigned type, 12, -3, (unsigned type) -36, mul, 1) \
+T (103, signed type, unsigned type, unsigned type, 3, 4, 12, mul, 0) \
+T (104, unsigned type, signed type, unsigned type, (unsigned type) -1 / 12, 12, (unsigned type) -1 / 12 * 12, mul, 0) \
+T (105, unsigned type, signed type, unsigned type, (unsigned type) -1 / 12, 13, (unsigned type) -1 / 12 * 13, mul, 1) \
+T (106, unsigned type, unsigned type, signed type, 0, 0, 0, mul, 0) \
+T (107, unsigned type, unsigned type, signed type, max / 31, 31, (signed type) ((unsigned type) max / 31 * 31), mul, 0) \
+T (108, unsigned type, unsigned type, signed type, max / 31, 32, (signed type) ((unsigned type) max / 31 * 32), mul, 1) \
+T (109, unsigned type, unsigned type, signed type, max / 31, 65, (signed type) ((unsigned type) max / 31 * 65), mul, 1) \
+T (110, signed type, unsigned type, signed type, -1, 7, -7, mul, 0) \
+T (111, unsigned type, signed type, signed type, 2, min / 2, min, mul, 0) \
+T (112, signed type, unsigned type, signed type, max / 12, 13, (signed type) ((unsigned type) max / 12 * 13), mul, 1) \
+T (113, unsigned type, signed type, signed type, (unsigned type) max + 19, 0, 0, mul, 0) \
+T (114, signed type, unsigned type, signed type, 0, (unsigned type) max + 1, 0, mul, 0) \
+T (115, unsigned type, signed type, signed type, (unsigned type) max + 1, -1, min, mul, 0) \
+T (116, signed type, unsigned type, signed type, -1, (unsigned type) max + 2, max, mul, 1) \
+T (117, signed type, signed type, unsigned type, min / 64, -64, (unsigned type) min, mul, 0) \
+T (118, signed type, signed type, unsigned type, min / 32, -33, ((unsigned type) max + 1) / 32 * 33, mul, 0) \
+T (119, signed type, signed type, unsigned type, min / 32, -65, ((unsigned type) max + 1) / 32 * 65, mul, 1) \
+T (120, signed type, signed type, unsigned type, -1, -1, 1, mul, 0) \
+T (121, signed type, signed type, unsigned type, 0, 0, 0, mul, 0) \
+T (122, signed type, signed type, unsigned type, 0, -6, 0, mul, 0) \
+T (123, signed type, signed type, unsigned type, -15, 0, 0, mul, 0) \
+T (124, signed type, signed type, unsigned type, -1, 1, ~(unsigned type) 0, mul, 1) \
+T (125, signed type, signed type, unsigned type, -17, 5, (unsigned type) -17 * 5, mul, 1) \
+T (126, signed type, signed type, unsigned type, 7, max / 7, max / 7 * 7, mul, 0) \
+T (127, signed type, signed type, unsigned type, max / 7, 8, (unsigned type) max / 7 * 8, mul, 0) \
+T (128, signed type, signed type, unsigned type, 15, max / 7, (unsigned type) max / 7 * 15, mul, 1) \
+T (129, signed type, unsigned type, signed type, min, 5, min + 5, add, 0) \
+T (130, unsigned type, signed type, signed type, ~(unsigned type) 0, min, max, add, 0) \
+T (131, signed type, unsigned type, signed type, max, 1, min, add, 1) \
+T (132, unsigned type, signed type, signed type, max / 2, max / 2 + 1, max, add, 0) \
+T (133, signed type, unsigned type, signed type, max / 2 + 1, max / 2 + 1, min, add, 1) \
+T (134, signed type, unsigned type, unsigned type, min, ~(unsigned type) 0, max, add, 0) \
+T (135, unsigned type, signed type, unsigned type, ~(unsigned type) 0, min + 1, (unsigned type) max + 1, add, 0) \
+T (136, signed type, unsigned type, unsigned type, 1, ~(unsigned type) 0, 0, add, 1) \
+T (137, unsigned type, signed type, unsigned type, 2, -3, ~(unsigned type) 0, add, 1) \
+T (138, signed type, unsigned type, signed type, min, 1, max, sub, 1) \
+T (139, signed type, unsigned type, signed type, min + 1, 1, min, sub, 0) \
+T (140, signed type, unsigned type, signed type, max, (unsigned type) max + 1, -1, sub, 0) \
+T (141, signed type, unsigned type, signed type, max, ~(unsigned type) 0, min, sub, 0) \
+T (142, signed type, unsigned type, signed type, max - 1, ~(unsigned type) 0, max, sub, 1) \
+T (143, signed type, unsigned type, unsigned type, -1, 0, ~(unsigned type) 0, sub, 1) \
+T (144, signed type, unsigned type, unsigned type, -1, ~(unsigned type) 0, 0, sub, 1) \
+T (145, signed type, unsigned type, unsigned type, min, 0, min, sub, 1) \
+T (146, signed type, unsigned type, unsigned type, max, max, 0, sub, 0) \
+T (147, signed type, unsigned type, unsigned type, max, (unsigned type) max + 1, -1, sub, 1) \
+T (148, signed type, unsigned type, unsigned type, max - 1, max, -1, sub, 1) \
+T (149, unsigned type, signed type, signed type, 0, max, -max, sub, 0) \
+T (150, unsigned type, signed type, signed type, (unsigned type) max + 1, 0, min, sub, 1) \
+T (151, unsigned type, signed type, signed type, (unsigned type) max + 1, 1, max, sub, 0) \
+T (152, unsigned type, unsigned type, signed type, 0, (unsigned type) max + 1, min, add, 1) \
+T (153, signed type, signed type, unsigned type, -1, 0, -1, add, 1) \
+T (154, unsigned type, signed type, unsigned type, 5, 6, -1, sub, 1) \
+T (155, unsigned type, signed type, unsigned type, ~(unsigned type) 0, max, (unsigned type) max + 1, sub, 0) \
+T (156, unsigned type, signed type, unsigned type, (unsigned type) max + 1, min, 0, sub, 1) \
+T (157, signed type, signed type, unsigned type, 3, -2, 1, add, 0) \
+T (158, signed type, signed type, unsigned type, 3, -4, -1, add, 1) \
+T (159, signed type, signed type, unsigned type, -3, -4, -7, add, 1) \
+T (160, signed type, signed type, unsigned type, -5, 4, -1, add, 1) \
+T (161, signed type, signed type, unsigned type, -5, 5, 0, add, 0) \
+T (162, signed type, signed type, unsigned type, min, 1, min + 1, add, 1) \
+T (163, unsigned type, unsigned type, signed type, max, 1, min, add, 1) \
+T (164, unsigned type, unsigned type, signed type, max - 1, 1, max, add, 0) \
+T (165, unsigned type, unsigned type, signed type, ~(unsigned type) 0, ~(unsigned type) 0, ~(unsigned type) 0 - 1, add, 1) \
+T (166, unsigned type, unsigned type, signed type, (unsigned type) max + 3, 2, min, sub, 1) \
+T (167, unsigned type, unsigned type, signed type, (unsigned type) max + 2, 2, max, sub, 0) \
+T (168, unsigned type, unsigned type, signed type, (unsigned type) max + 2, (unsigned type) max + 3, -1, sub, 0) \
+T (169, unsigned type, unsigned type, signed type, 0, (unsigned type) max + 1, min, sub, 0) \
+T (170, unsigned type, unsigned type, signed type, 0, (unsigned type) max + 2, max, sub, 1) \
+T (171, signed type, signed type, unsigned type, 3, 2, 1, sub, 0) \
+T (172, signed type, signed type, unsigned type, 3, 4, -1, sub, 1) \
+T (173, signed type, signed type, unsigned type, -3, 4, -7, sub, 1) \
+T (174, signed type, signed type, unsigned type, -5, -4, -1, sub, 1) \
+T (175, signed type, signed type, unsigned type, -5, -5, 0, sub, 0) \
+T (176, signed type, signed type, unsigned type, min, -1, min + 1, sub, 1)
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-13.c.jj	2014-11-07 19:19:58.402751898 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-13.c	2014-11-07 19:20:22.219323644 +0100
@@ -0,0 +1,17 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-12.h"
+
+TESTS (long, LONG_MIN, LONG_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (long, LONG_MIN, LONG_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-14.c.jj	2014-11-07 19:20:57.193695507 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-14.c	2014-11-07 19:21:45.937818318 +0100
@@ -0,0 +1,17 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-12.h"
+
+TESTS (long long, LLONG_MIN, LLONG_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (long long, LLONG_MIN, LLONG_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-15.c.jj	2014-11-07 19:21:00.023643833 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-15.c	2014-11-07 19:22:46.606727387 +0100
@@ -0,0 +1,17 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-12.h"
+
+TESTS (char, SCHAR_MIN, SCHAR_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (char, SCHAR_MIN, SCHAR_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-16.c.jj	2014-11-07 19:21:03.116588279 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-16.c	2014-11-07 19:22:39.406856377 +0100
@@ -0,0 +1,17 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-12.h"
+
+TESTS (short, SHRT_MIN, SHRT_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (short, SHRT_MIN, SHRT_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-17.c.jj	2014-11-07 19:22:21.781173435 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-17.c	2014-11-07 19:22:57.811526120 +0100
@@ -0,0 +1,20 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run { target int128 } } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-12.h"
+
+#define INT128_MAX ((signed __int128) (((unsigned __int128) 1 << (__SIZEOF_INT128__ * __CHAR_BIT__ - 1)) - 1))
+#define INT128_MIN (-INT128_MAX - 1)
+
+TESTS (__int128, INT128_MIN, INT128_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (__int128, INT128_MIN, INT128_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-18.c.jj	2014-11-10 15:28:16.953257135 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-18.c	2014-11-10 17:06:18.342709092 +0100
@@ -0,0 +1,36 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow.h"
+
+#ifdef __SIZEOF_INT128__
+#define WTYPE __int128
+#else
+#define WTYPE long long int
+#endif
+
+#define TESTS \
+T (100, signed char, signed char, unsigned WTYPE, -1, 0, -1, add, 1) \
+T (101, unsigned char, unsigned char, unsigned WTYPE, 5, 5, 10, add, 0) \
+T (102, signed char, unsigned short, unsigned WTYPE, 5, 5, 0, sub, 0) \
+T (103, signed char, unsigned short, unsigned WTYPE, 5, 6, -1, sub, 1) \
+T (104, signed char, signed char, unsigned WTYPE, -1, -1, 1, mul, 0) \
+T (105, unsigned char, signed char, unsigned WTYPE, 17, -2, -34, mul, 1) \
+T (106, unsigned WTYPE, signed WTYPE, signed char, 5, -2, -10, mul, 0) \
+T (107, long long int, long long int, unsigned char, -3, 5, 2, add, 0) \
+T (108, long long int, int, unsigned char, -5, 3, -2, add, 1) \
+T (109, int, WTYPE, unsigned char, -3, 5, 2, add, 0) \
+T (110, unsigned char, unsigned char, unsigned WTYPE, SCHAR_MAX - 1, (unsigned char) SCHAR_MAX + 4, -5, sub, 1)
+
+TESTS
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-1.c.jj	2014-11-03 18:40:54.074461851 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-1.c	2014-11-07 19:10:26.131018871 +0100
@@ -0,0 +1,24 @@ 
+/* Test __builtin_{add,sub,mul,{s,u}add,{s,u}sub,{s,u}mul}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-1.h"
+
+#define U(s, op) s##op
+TESTS (int, INT_MIN, INT_MAX)
+#undef U
+#define U(s, op) op
+TESTS (int, INT_MIN, INT_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (int, INT_MIN, INT_MAX)
+#undef U
+#define U(s, op) s##op
+  TESTS (int, INT_MIN, INT_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-1.h.jj	2014-11-03 18:36:56.604776189 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-1.h	2014-11-03 19:22:18.789374761 +0100
@@ -0,0 +1,37 @@ 
+#include "builtin-arith-overflow.h"
+
+#define TESTS(type, min, max) \
+ST (100, signed type, 2, 3, 5, U(s, add), 0) \
+ST (101, signed type, max, -1, max - 1, U(s, add), 0) \
+ST (102, signed type, max, 0, max, U(s, add), 0) \
+ST (103, signed type, 1, max, min, U(s, add), 1) \
+ST (104, signed type, 0, min, min, U(s, sub), 1) \
+ST (110, signed type, 2, 3, -1, U(s, sub), 0) \
+ST (111, signed type, max, -1, min, U(s, sub), 1) \
+ST (112, signed type, max, 0, max, U(s, sub), 0) \
+ST (113, signed type, 1, max, min + 2, U(s, sub), 0) \
+ST (114, signed type, max, -1, min, U(s, sub), 1) \
+ST (120, signed type, 2, 3, 6, U(s, mul), 0) \
+ST (122, signed type, min, -1, min, U(s, mul), 1) \
+ST (123, signed type, max, 0, 0, U(s, mul), 0) \
+ST (124, signed type, 1, max, max, U(s, mul), 0) \
+ST (125, signed type, max, 2, -2, U(s, mul), 1) \
+ST (126, signed type, max / 25, 25, max / 25 * 25, U(s, mul), 0) \
+ST (127, signed type, max / 25 + 1, 25, max / 25 * 25 + (unsigned type) 25, U(s, mul), 1) \
+ST (150, unsigned type, 2, 3, 5, U(u, add), 0) \
+ST (151, unsigned type, -1, -1, -2, U(u, add), 1) \
+ST (152, unsigned type, -1, 0, -1, U(u, add), 0) \
+ST (153, unsigned type, 1, -1, 0, U(u, add), 1) \
+ST (154, unsigned type, 0, min, min, U(u, sub), 1) \
+ST (160, unsigned type, 2, 3, -1, U(u, sub), 1) \
+ST (161, unsigned type, -1, -1, 0, U(u, sub), 0) \
+ST (162, unsigned type, -1, 0, -1, U(u, sub), 0) \
+ST (163, unsigned type, 1, -1, 2, U(u, sub), 1) \
+ST (164, unsigned type, 15, 14, 1, U(u, sub), 0) \
+ST (170, unsigned type, 2, 3, 6, U(u, mul), 0) \
+ST (171, unsigned type, max, 3, 3 * (unsigned type) max, U(u, mul), 1) \
+ST (172, unsigned type, -1, 0, 0, U(u, mul), 0) \
+ST (173, unsigned type, 1, -1, -1, U(u, mul), 0) \
+ST (174, unsigned type, -1, 2, -2, U(u, mul), 1) \
+ST (175, unsigned type, ((unsigned type) -1) / 25, 25, ((unsigned type) -1) / 25 * 25, U(u, mul), 0) \
+ST (176, unsigned type, ((unsigned type) -1) / 25 + 1, 25, ((unsigned type) -1) / 25 * 25 + (unsigned type) 25, U(u, mul), 1)
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-2.c.jj	2014-11-03 18:44:53.490111010 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-2.c	2014-11-07 19:10:26.131018871 +0100
@@ -0,0 +1,24 @@ 
+/* Test __builtin_{add,sub,mul,{s,u}addl,{s,u}subl,{s,u}mull}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-1.h"
+
+#define U(s, op) s##op##l
+TESTS (long, LONG_MIN, LONG_MAX)
+#undef U
+#define U(s, op) op
+TESTS (long, LONG_MIN, LONG_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (long, LONG_MIN, LONG_MAX)
+#undef U
+#define U(s, op) s##op##l
+  TESTS (long, LONG_MIN, LONG_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-3.c.jj	2014-11-03 18:45:41.585236605 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-3.c	2014-11-07 19:10:26.132018853 +0100
@@ -0,0 +1,24 @@ 
+/* Test __builtin_{add,sub,mul,{s,u}addll,{s,u}subll,{s,u}mulll}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-1.h"
+
+#define U(s, op) s##op##ll
+TESTS (long long, LLONG_MIN, LLONG_MAX)
+#undef U
+#define U(s, op) op
+TESTS (long long, LLONG_MIN, LLONG_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (long long, LLONG_MIN, LLONG_MAX)
+#undef U
+#define U(s, op) s##op##ll
+  TESTS (long long, LLONG_MIN, LLONG_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-4.c.jj	2014-11-03 19:09:34.330185643 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-4.c	2014-11-07 19:10:26.132018853 +0100
@@ -0,0 +1,18 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-1.h"
+
+#define U(s, op) op
+TESTS (char, SCHAR_MIN, SCHAR_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (char, SCHAR_MIN, SCHAR_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-5.c.jj	2014-11-03 19:11:00.427620935 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-5.c	2014-11-07 19:10:26.132018853 +0100
@@ -0,0 +1,18 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-1.h"
+
+#define U(s, op) op
+TESTS (short, SHRT_MIN, SHRT_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (short, SHRT_MIN, SHRT_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-6.c.jj	2014-11-03 19:27:55.763293162 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-6.c	2014-11-07 19:10:26.133018835 +0100
@@ -0,0 +1,21 @@ 
+/* Test __builtin_{add,sub,mul}_overflow.  */
+/* { dg-do run { target int128 } } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#include "builtin-arith-overflow-1.h"
+
+#define INT128_MAX ((signed __int128) (((unsigned __int128) 1 << (__SIZEOF_INT128__ * __CHAR_BIT__ - 1)) - 1))
+#define INT128_MIN (-INT128_MAX - 1)
+
+#define U(s, op) op
+TESTS (__int128, INT128_MIN, INT128_MAX)
+
+#undef T
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) t##n##b ();
+
+int
+main ()
+{
+  TESTS (__int128, INT128_MIN, INT128_MAX)
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-7.c.jj	2014-11-05 10:55:31.370621720 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-7.c	2014-11-07 19:10:26.133018835 +0100
@@ -0,0 +1,80 @@ 
+/* Test __builtin_{add,sub}_overflow on {,un}signed char.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+#define UCHAR_MAX ((unsigned char) ~0)
+#ifndef SHIFT
+typedef signed char S;
+typedef unsigned char U;
+typedef int W;
+#define SHIFT 0
+#define S_MAX __SCHAR_MAX__
+#define S_MIN (-__SCHAR_MAX__ - 1)
+#define COND (__SIZEOF_INT__ > 1)
+#endif
+
+#define F(n, t1, t2, tr, b) \
+__attribute__((noinline, noclone)) tr		\
+n (t1 x, t2 y, int *ovf)			\
+{						\
+  tr res;					\
+  *ovf = __builtin_##b##_overflow (x, y, &res);	\
+  return res;					\
+}
+
+F (spses, S, S, S, add)
+F (upueu, U, U, U, add)
+F (spseu, S, S, U, add)
+F (upues, U, U, S, add)
+F (spues, S, U, S, add)
+F (upses, U, S, S, add)
+F (spueu, S, U, U, add)
+F (upseu, U, S, U, add)
+F (ssses, S, S, S, sub)
+F (usueu, U, U, U, sub)
+F (ssseu, S, S, U, sub)
+F (usues, U, U, S, sub)
+F (ssues, S, U, S, sub)
+F (usses, U, S, S, sub)
+F (ssueu, S, U, U, sub)
+F (usseu, U, S, U, sub)
+
+int
+main ()
+{
+#if COND
+  int i, j;
+  for (i = 0; i < UCHAR_MAX; i++)
+    for (j = 0; j < UCHAR_MAX; j++)
+      {
+	S s1 = ((W) i << SHIFT) + S_MIN;
+	U u1 = ((W) i << SHIFT);
+	S s2 = ((W) j << SHIFT) + S_MIN;
+	U u2 = ((W) j << SHIFT);
+	W w;
+	int ovf;
+#define T(n, t1, t2, tr, op) \
+	w = ((W) t1##1) op ((W) t2##2);		\
+	if (n (t1##1, t2##2, &ovf) != (tr) w	\
+	    || ovf != (w != (tr) w))		\
+	  __builtin_abort ();
+	T (spses, s, s, S, +)
+	T (upueu, u, u, U, +)
+	T (spseu, s, s, U, +)
+	T (upues, u, u, S, +)
+	T (spues, s, u, S, +)
+	T (upses, u, s, S, +)
+	T (spueu, s, u, U, +)
+	T (upseu, u, s, U, +)
+	T (ssses, s, s, S, -)
+	T (usueu, u, u, U, -)
+	T (ssseu, s, s, U, -)
+	T (usues, u, u, S, -)
+	T (ssues, s, u, S, -)
+	T (usses, u, s, S, -)
+	T (ssueu, s, u, U, -)
+	T (usseu, u, s, U, -)
+      }
+#endif
+  return 0;
+}
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-8.c.jj	2014-11-05 10:56:19.418748918 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-8.c	2014-11-07 19:10:26.134018817 +0100
@@ -0,0 +1,23 @@ 
+/* Test __builtin_{add,sub}_overflow on {,un}signed short.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+typedef signed short int S;
+typedef unsigned short int U;
+#define COND 1
+#define SHIFT ((__SIZEOF_SHORT__ - 1) * __CHAR_BIT__)
+#define S_MAX __SHRT_MAX__
+#define S_MIN (-__SHRT_MAX__ - 1)
+#if __SIZEOF_INT__ > __SIZEOF_SHORT__
+typedef int W;
+#elif __SIZEOF_LONG__ > __SIZEOF_SHORT__
+typedef long int W;
+#elif __SIZEOF_LONG_LONG__ > __SIZEOF_SHORT__
+typedef long long int W;
+#elif __SIZEOF_INT128__ > __SIZEOF_SHORT__
+typedef __int128 W;
+#else
+#undef COND
+#define COND 0
+#endif
+#include "builtin-arith-overflow-7.c"
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-9.c.jj	2014-11-05 11:03:40.760743270 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-9.c	2014-11-07 19:10:26.134018817 +0100
@@ -0,0 +1,21 @@ 
+/* Test __builtin_{add,sub}_overflow on {,un}signed int.  */
+/* { dg-do run } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+
+typedef signed int S;
+typedef unsigned int U;
+#define COND 1
+#define SHIFT ((__SIZEOF_INT__ - 1) * __CHAR_BIT__)
+#define S_MAX __INT_MAX__
+#define S_MIN (-__INT_MAX__ - 1)
+#if __SIZEOF_LONG__ > __SIZEOF_INT__
+typedef long int W;
+#elif __SIZEOF_LONG_LONG__ > __SIZEOF_INT__
+typedef long long int W;
+#elif __SIZEOF_INT128__ > __SIZEOF_INT__
+typedef __int128 W;
+#else
+#undef COND
+#define COND 0
+#endif
+#include "builtin-arith-overflow-7.c"
--- gcc/testsuite/c-c++-common/torture/builtin-arith-overflow.h.jj	2014-11-03 18:36:53.701831741 +0100
+++ gcc/testsuite/c-c++-common/torture/builtin-arith-overflow.h	2014-11-03 19:05:15.441885624 +0100
@@ -0,0 +1,94 @@ 
+#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)
+#define LONG_MAX __LONG_MAX__
+#define LONG_MIN (-__LONG_MAX__ - 1)
+#define LLONG_MAX __LONG_LONG_MAX__
+#define LLONG_MIN (-__LONG_LONG_MAX__ - 1)
+
+int v;
+
+__attribute__((noinline, noclone)) void
+bar (void)
+{
+  v++;
+}
+
+#define T(n, t1, t2, tr, v1, v2, vr, b, o) \
+__attribute__((noinline, noclone)) tr		\
+t##n##_1##b (t1 x, t2 y)			\
+{						\
+  tr r;						\
+  if (__builtin_##b##_overflow (x, y, &r))	\
+    bar ();					\
+  return r;					\
+}						\
+						\
+__attribute__((noinline, noclone)) tr		\
+t##n##_2##b (t2 y)				\
+{						\
+  t1 x = (v1);					\
+  tr r;						\
+  if (__builtin_##b##_overflow (x, y, &r))	\
+    bar ();					\
+  return r;					\
+}						\
+						\
+__attribute__((noinline, noclone)) tr		\
+t##n##_3##b (t2 y)				\
+{						\
+  tr r;						\
+  if (__builtin_##b##_overflow ((t1) (v1), y,	\
+				&r))		\
+    bar ();					\
+  return r;					\
+}						\
+						\
+__attribute__((noinline, noclone)) tr		\
+t##n##_4##b (t1 x)				\
+{						\
+  t2 y = (v2);					\
+  tr r;						\
+  if (__builtin_##b##_overflow (x, y, &r))	\
+    bar ();					\
+  return r;					\
+}						\
+						\
+__attribute__((noinline, noclone)) tr		\
+t##n##_5##b (t1 x)				\
+{						\
+  tr r;						\
+  if (__builtin_##b##_overflow (x, (t2) (v2),	\
+				&r))		\
+    bar ();					\
+  return r;					\
+}						\
+						\
+__attribute__((noinline, noclone)) void		\
+t##n##b (void)					\
+{						\
+  t1 x = (v1);					\
+  t2 y = (v2);					\
+  tr r1, r2;					\
+  v = 0;					\
+  if (t##n##_1##b (x, y) != (tr) (vr)		\
+      || t##n##_2##b (y) != (tr) (vr)		\
+      || t##n##_3##b (y) != (tr) (vr)		\
+      || t##n##_4##b (x) != (tr) (vr)		\
+      || t##n##_5##b (x) != (tr) (vr))		\
+    __builtin_abort ();				\
+  if (__builtin_##b##_overflow (x, y, &r1))	\
+    bar ();					\
+  if (r1 != (tr) (vr))				\
+    __builtin_abort ();				\
+  if (__builtin_##b##_overflow ((t1) (v1),	\
+				(t2) (v2), &r2))\
+    bar ();					\
+  if (r2 != (tr) (vr) || v != 7 * o)		\
+    __builtin_abort ();				\
+}
+#define ST(n, t, v1, v2, vr, b, o) \
+T (n, t, t, t, v1, v2, vr, b, o)
--- gcc/testsuite/gcc.dg/builtin-arith-overflow-1.c.jj	2014-11-07 16:41:14.558730074 +0100
+++ gcc/testsuite/gcc.dg/builtin-arith-overflow-1.c	2014-11-07 17:27:16.631821188 +0100
@@ -0,0 +1,132 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -g" } */
+
+/* SUB_OVERFLOW should be folded into unsigned subtraction,
+   because ovf is never used.  */
+__attribute__((noinline, noclone)) int
+fn1 (int x, unsigned int y)
+{
+  int res;
+  int ovf = __builtin_sub_overflow (x, y, &res);
+  int res2 = res;
+  int res3 = res2 - 2;
+  (void) ovf;
+  return res;
+}
+
+/* MUL_OVERFLOW should be folded into unsigned multiplication,
+   because ovf is never used.  */
+__attribute__((noinline, noclone)) int
+fn2 (char x, long int y)
+{
+  short int res;
+  int ovf = __builtin_mul_overflow (x, y, &res);
+  int res2 = res;
+  int res3 = res2 - 2;
+  (void) ovf;
+  return res;
+}
+
+#if __SIZEOF_INT__ > __SIZEOF_SHORT__ && __SIZEOF_INT__ > 1
+/* ADD_OVERFLOW should be folded into unsigned addition,
+   because it never overflows.  */
+__attribute__((noinline, noclone)) int
+fn3 (char x, unsigned short y, int *ovf)
+{
+  int res;
+  *ovf = __builtin_add_overflow (x, y, &res);
+  return res;
+}
+#endif
+
+/* MUL_OVERFLOW should be folded into unsigned multiplication,
+   because it never overflows.  */
+__attribute__((noinline, noclone)) long int
+fn4 (long int x, long int y, int *ovf)
+{
+  long int res;
+  x &= 65535;
+  y = (y & 65535) - 32768;
+  *ovf = __builtin_mul_overflow (x, y, &res);
+  return res;
+}
+
+#if __SIZEOF_INT__ > 1
+/* MUL_OVERFLOW should be folded into unsigned multiplication,
+   because it always overflows.  */
+__attribute__((noinline, noclone)) signed char
+fn5 (long int x, long int y, int *ovf)
+{
+  signed char res;
+  x = (x & 63) + (__SCHAR_MAX__ / 4);
+  y = (y & 3) + 5;
+  *ovf = __builtin_mul_overflow (x, y, &res);
+  return res;
+}
+#endif
+
+/* ADD_OVERFLOW should be folded into unsigned additrion,
+   because it never overflows.  */
+__attribute__((noinline, noclone)) unsigned char
+fn6 (unsigned char x, unsigned char y, int *ovf)
+{
+  unsigned char res;
+  x = (x & 63) + ((unsigned char) ~0 - 66);
+  y = (y & 3);
+  *ovf = __builtin_add_overflow (x, y, &res);
+  return res;
+}
+
+/* ADD_OVERFLOW should be folded into unsigned additrion,
+   because it always overflows.  */
+__attribute__((noinline, noclone)) unsigned char
+fn7 (unsigned char x, unsigned char y, int *ovf)
+{
+  unsigned char res;
+  x = (x & 15) + ((unsigned char) ~0 - 15);
+  y = (y & 3) + 16;
+  *ovf = __builtin_add_overflow (x, y, &res);
+  return res;
+}
+
+int
+main ()
+{
+  int ovf;
+  if (fn1 (-10, __INT_MAX__) != (int) (-10U - __INT_MAX__)
+      || fn2 (0, 0) != 0
+      || fn2 (32, 16383) != (short int) 524256ULL)
+    __builtin_abort ();
+#if __SIZEOF_INT__ > __SIZEOF_SHORT__ && __SIZEOF_INT__ > 1
+  if (fn3 (__SCHAR_MAX__, (unsigned short) ~0, &ovf) != (int) (__SCHAR_MAX__ + (unsigned short) ~0)
+      || ovf
+      || fn3 (-__SCHAR_MAX__ - 1, 0, &ovf) != (int) (-__SCHAR_MAX__ - 1)
+      || ovf)
+    __builtin_abort ();
+#endif
+  if (fn4 (65535, 0, &ovf) != 65535L * -32768 || ovf)
+    __builtin_abort ();
+#if __SIZEOF_INT__ > 1
+  if (fn5 (0, 0, &ovf) != (signed char) (__SCHAR_MAX__ / 4 * 5)
+      || !ovf
+      || fn5 (63, 3, &ovf) != (signed char) ((__SCHAR_MAX__ / 4 + 63) * 8)
+      || !ovf)
+    __builtin_abort ();
+#endif
+  if (fn6 (0, 0, &ovf) != (unsigned char) ~0 - 66
+      || ovf
+      || fn6 (63, 3, &ovf) != (unsigned char) ~0
+      || ovf)
+    __builtin_abort ();
+  if (fn7 (0, 0, &ovf) != 0
+      || !ovf
+      || fn7 (63, 3, &ovf) != 18
+      || !ovf)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "ADD_OVERFLOW" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "SUB_OVERFLOW" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "MUL_OVERFLOW" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
--- gcc/testsuite/gcc.dg/builtin-arith-overflow-2.c.jj	2014-11-07 17:06:35.695212103 +0100
+++ gcc/testsuite/gcc.dg/builtin-arith-overflow-2.c	2014-11-10 18:04:00.819605719 +0100
@@ -0,0 +1,110 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* MUL_OVERFLOW should not be folded into unsigned multiplication,
+   because it sometimes overflows and sometimes does not.  */
+__attribute__((noinline, noclone)) long int
+fn1 (long int x, long int y, int *ovf)
+{
+  long int res;
+  x &= 65535;
+  y = (y & 65535) - (__LONG_MAX__ / 65535 + 32768);
+  *ovf = __builtin_mul_overflow (x, y, &res);
+  return res;
+}
+
+/* MUL_OVERFLOW should not be folded into unsigned multiplication,
+   because it sometimes overflows and sometimes does not.  */
+__attribute__((noinline, noclone)) signed char
+fn2 (long int x, long int y, int *ovf)
+{
+  signed char res;
+  x = (x & 63) + (__SCHAR_MAX__ / 4);
+  y = (y & 3) + 4;
+  *ovf = __builtin_mul_overflow (x, y, &res);
+  return res;
+}
+
+/* ADD_OVERFLOW should be folded into unsigned additrion,
+   because it sometimes overflows and sometimes does not.  */
+__attribute__((noinline, noclone)) unsigned char
+fn3 (unsigned char x, unsigned char y, int *ovf)
+{
+  unsigned char res;
+  x = (x & 63) + ((unsigned char) ~0 - 65);
+  y = (y & 3);
+  *ovf = __builtin_add_overflow (x, y, &res);
+  return res;
+}
+
+/* ADD_OVERFLOW should be folded into unsigned additrion,
+   because it sometimes overflows and sometimes does not.  */
+__attribute__((noinline, noclone)) unsigned char
+fn4 (unsigned char x, unsigned char y, int *ovf)
+{
+  unsigned char res;
+  x = (x & 15) + ((unsigned char) ~0 - 16);
+  y = (y & 3) + 16;
+  *ovf = __builtin_add_overflow (x, y, &res);
+  return res;
+}
+
+/* MUL_OVERFLOW should not be folded into unsigned multiplication,
+   because it sometimes overflows and sometimes does not.  */
+__attribute__((noinline, noclone)) long int
+fn5 (long int x, unsigned long int y, int *ovf)
+{
+  long int res;
+  y = -65536UL + (y & 65535);
+  *ovf = __builtin_mul_overflow (x, y, &res);
+  return res;
+}
+
+int
+main ()
+{
+  int ovf;
+  if (fn1 (0, 0, &ovf) != 0
+      || ovf
+      || fn1 (65535, 0, &ovf) != (long int) ((__LONG_MAX__ / 65535 + 32768UL) * -65535UL)
+      || !ovf)
+    __builtin_abort ();
+  if (fn2 (0, 0, &ovf) != (signed char) (__SCHAR_MAX__ / 4 * 4U)
+      || ovf
+      || fn2 (0, 1, &ovf) != (signed char) (__SCHAR_MAX__ / 4 * 5U)
+      || !ovf)
+    __builtin_abort ();
+  if (fn3 (0, 0, &ovf) != (unsigned char) ~0 - 65
+      || ovf
+      || fn3 (63, 2, &ovf) != (unsigned char) ~0
+      || ovf
+      || fn3 (62, 3, &ovf) != (unsigned char) ~0
+      || ovf
+      || fn3 (63, 3, &ovf) != 0
+      || !ovf)
+    __builtin_abort ();
+  if (fn4 (0, 0, &ovf) != (unsigned char) ~0
+      || ovf
+      || fn4 (1, 0, &ovf) != 0
+      || !ovf
+      || fn4 (0, 1, &ovf) != 0
+      || !ovf
+      || fn4 (63, 3, &ovf) != 17
+      || !ovf)
+    __builtin_abort ();
+  if (fn5 (0, 0, &ovf) != 0
+      || ovf
+      || fn5 (1, 0, &ovf) != -65536L
+      || !ovf
+      || fn5 (2, 32768, &ovf) != -65536L
+      || !ovf
+      || fn5 (4, 32768 + 16384 + 8192, &ovf) != -32768L
+      || !ovf)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 0 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "MUL_OVERFLOW" 3 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */