Commit a86451b9 by Jakub Jelinek Committed by Jakub Jelinek

internal-fn.c (expand_arith_set_overflow): New function.

	* internal-fn.c (expand_arith_set_overflow): New function.
	(expand_addsub_overflow, expand_neg_overflow, expand_mul_overflow):
	Use it.
	(expand_arith_overflow_result_store): Likewise.  Handle precision
	smaller than mode precision.
	* tree-vrp.c (extract_range_basic): For imag part, handle
	properly signed 1-bit precision result.
	* doc/extend.texi (__builtin_add_overflow): Document that last
	argument can't be pointer to enumerated or boolean type.
	(__builtin_add_overflow_p): Document that last argument can't
	have enumerated or boolean type.

	* c-common.c (check_builtin_function_arguments): Require last
	argument of BUILT_IN_*_OVERFLOW_P to have INTEGER_TYPE type.
	Adjust wording of diagnostics for BUILT_IN_*_OVERLFLOW
	if the last argument is pointer to enumerated or boolean type.

	* c-c++-common/builtin-arith-overflow-1.c (generic_wrong_type, f3,
	f4): Adjust expected diagnostics.
	* c-c++-common/torture/builtin-arith-overflow.h (TP): New macro.
	(T): If OVFP is defined, redefine to TP.
	* c-c++-common/torture/builtin-arith-overflow-12.c: Adjust comment.
	* c-c++-common/torture/builtin-arith-overflow-p-1.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-2.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-3.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-4.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-5.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-6.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-7.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-8.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-9.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-10.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-11.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-12.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-13.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-14.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-15.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-16.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-17.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-18.c: New test.
	* c-c++-common/torture/builtin-arith-overflow-p-19.c: New test.
	* g++.dg/ext/builtin-arith-overflow-1.C: Pass 0 instead of C
	as last argument to __builtin_add_overflow_p.

From-SVN: r237754
parent 43535362
2016-06-24 Jakub Jelinek <jakub@redhat.com>
* internal-fn.c (expand_arith_set_overflow): New function.
(expand_addsub_overflow, expand_neg_overflow, expand_mul_overflow):
Use it.
(expand_arith_overflow_result_store): Likewise. Handle precision
smaller than mode precision.
* tree-vrp.c (extract_range_basic): For imag part, handle
properly signed 1-bit precision result.
* doc/extend.texi (__builtin_add_overflow): Document that last
argument can't be pointer to enumerated or boolean type.
(__builtin_add_overflow_p): Document that last argument can't
have enumerated or boolean type.
2016-06-23 Michael Meissner <meissner@linux.vnet.ibm.com> 2016-06-23 Michael Meissner <meissner@linux.vnet.ibm.com>
Bill Schmidt <wschmidt@linux.vnet.ibm.com> Bill Schmidt <wschmidt@linux.vnet.ibm.com>
......
2016-06-24 Jakub Jelinek <jakub@redhat.com>
* c-common.c (check_builtin_function_arguments): Require last
argument of BUILT_IN_*_OVERFLOW_P to have INTEGER_TYPE type.
Adjust wording of diagnostics for BUILT_IN_*_OVERLFLOW
if the last argument is pointer to enumerated or boolean type.
2016-06-22 David Malcolm <dmalcolm@redhat.com> 2016-06-22 David Malcolm <dmalcolm@redhat.com>
PR c/70339 PR c/70339
......
...@@ -9983,10 +9983,22 @@ check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc, ...@@ -9983,10 +9983,22 @@ check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc,
return false; return false;
} }
if (TREE_CODE (TREE_TYPE (args[2])) != POINTER_TYPE if (TREE_CODE (TREE_TYPE (args[2])) != POINTER_TYPE
|| TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) != INTEGER_TYPE) || !INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (args[2]))))
{ {
error_at (ARG_LOCATION (2), "argument 3 in call to function %qE " error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
"does not have pointer to integer type", fndecl); "does not have pointer to integral type", fndecl);
return false;
}
else if (TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) == ENUMERAL_TYPE)
{
error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
"has pointer to enumerated type", fndecl);
return false;
}
else if (TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) == BOOLEAN_TYPE)
{
error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
"has pointer to boolean type", fndecl);
return false; return false;
} }
return true; return true;
...@@ -10006,6 +10018,18 @@ check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc, ...@@ -10006,6 +10018,18 @@ check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc,
"%qE does not have integral type", i + 1, fndecl); "%qE does not have integral type", i + 1, fndecl);
return false; return false;
} }
if (TREE_CODE (TREE_TYPE (args[2])) == ENUMERAL_TYPE)
{
error_at (ARG_LOCATION (2), "argument 3 in call to function "
"%qE has enumerated type", fndecl);
return false;
}
else if (TREE_CODE (TREE_TYPE (args[2])) == BOOLEAN_TYPE)
{
error_at (ARG_LOCATION (2), "argument 3 in call to function "
"%qE has boolean type", fndecl);
return false;
}
return true; return true;
} }
return false; return false;
......
...@@ -9833,8 +9833,8 @@ performed in infinite signed precision, these built-in functions have fully defi ...@@ -9833,8 +9833,8 @@ performed in infinite signed precision, these built-in functions have fully defi
behavior for all argument values. behavior for all argument values.
The first built-in function allows arbitrary integral types for operands and 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 the result type must be pointer to some integral type other than enumerated or
functions have explicit integer types. Boolean type, the rest of the built-in functions have explicit integer types.
The compiler will attempt to use hardware instructions to implement The compiler will attempt to use hardware instructions to implement
these built-in functions where possible, like conditional jump on overflow these built-in functions where possible, like conditional jump on overflow
...@@ -9879,7 +9879,8 @@ would overflow. ...@@ -9879,7 +9879,8 @@ would overflow.
These built-in functions are similar to @code{__builtin_add_overflow}, These built-in functions are similar to @code{__builtin_add_overflow},
@code{__builtin_sub_overflow}, or @code{__builtin_mul_overflow}, except that @code{__builtin_sub_overflow}, or @code{__builtin_mul_overflow}, except that
they don't store the result of the arithmetic operation anywhere and the they don't store the result of the arithmetic operation anywhere and the
last argument is not a pointer, but some integral expression. last argument is not a pointer, but some expression with integral type other
than enumerated or Boolean type.
The built-in functions promote the first two operands into infinite precision signed type The built-in functions promote the first two operands into infinite precision signed type
and perform addition on those promoted operands. The result is then and perform addition on those promoted operands. The result is then
......
...@@ -405,9 +405,23 @@ get_min_precision (tree arg, signop sign) ...@@ -405,9 +405,23 @@ get_min_precision (tree arg, signop sign)
return prec + (orig_sign != sign); return prec + (orig_sign != sign);
} }
/* Helper for expand_*_overflow. Set the __imag__ part to true
(1 except for signed:1 type, in which case store -1). */
static void
expand_arith_set_overflow (tree lhs, rtx target)
{
if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs))) == 1
&& !TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))))
write_complex_part (target, constm1_rtx, true);
else
write_complex_part (target, const1_rtx, true);
}
/* Helper for expand_*_overflow. Store RES into the __real__ part /* Helper for expand_*_overflow. Store RES into the __real__ part
of TARGET. If RES has larger MODE than __real__ part of TARGET, 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. */ set the __imag__ part to 1 if RES doesn't fit into it. Similarly
if LHS has smaller precision than its mode. */
static void static void
expand_arith_overflow_result_store (tree lhs, rtx target, expand_arith_overflow_result_store (tree lhs, rtx target,
...@@ -424,7 +438,35 @@ expand_arith_overflow_result_store (tree lhs, rtx target, ...@@ -424,7 +438,35 @@ expand_arith_overflow_result_store (tree lhs, rtx target,
do_compare_rtx_and_jump (res, convert_modes (mode, tgtmode, lres, uns), do_compare_rtx_and_jump (res, convert_modes (mode, tgtmode, lres, uns),
EQ, true, mode, NULL_RTX, NULL, done_label, EQ, true, mode, NULL_RTX, NULL, done_label,
PROB_VERY_LIKELY); PROB_VERY_LIKELY);
write_complex_part (target, const1_rtx, true); expand_arith_set_overflow (lhs, target);
emit_label (done_label);
}
int prec = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs)));
int tgtprec = GET_MODE_PRECISION (tgtmode);
if (prec < tgtprec)
{
rtx_code_label *done_label = gen_label_rtx ();
int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
res = lres;
if (uns)
{
rtx mask
= immed_wide_int_const (wi::shifted_mask (0, prec, false, tgtprec),
tgtmode);
lres = expand_simple_binop (tgtmode, AND, res, mask, NULL_RTX,
true, OPTAB_DIRECT);
}
else
{
lres = expand_shift (LSHIFT_EXPR, tgtmode, res, tgtprec - prec,
NULL_RTX, 1);
lres = expand_shift (RSHIFT_EXPR, tgtmode, lres, tgtprec - prec,
NULL_RTX, 0);
}
do_compare_rtx_and_jump (res, lres,
EQ, true, tgtmode, NULL_RTX, NULL, done_label,
PROB_VERY_LIKELY);
expand_arith_set_overflow (lhs, target);
emit_label (done_label); emit_label (done_label);
} }
write_complex_part (target, lres, false); write_complex_part (target, lres, false);
...@@ -861,7 +903,7 @@ expand_addsub_overflow (location_t loc, tree_code code, tree lhs, ...@@ -861,7 +903,7 @@ expand_addsub_overflow (location_t loc, tree_code code, tree lhs,
do_pending_stack_adjust (); do_pending_stack_adjust ();
} }
else if (lhs) else if (lhs)
write_complex_part (target, const1_rtx, true); expand_arith_set_overflow (lhs, target);
/* We're done. */ /* We're done. */
emit_label (done_label); emit_label (done_label);
...@@ -956,7 +998,7 @@ expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan) ...@@ -956,7 +998,7 @@ expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan)
do_pending_stack_adjust (); do_pending_stack_adjust ();
} }
else if (lhs) else if (lhs)
write_complex_part (target, const1_rtx, true); expand_arith_set_overflow (lhs, target);
/* We're done. */ /* We're done. */
emit_label (done_label); emit_label (done_label);
...@@ -1082,7 +1124,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, ...@@ -1082,7 +1124,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
NULL, do_main_label, PROB_VERY_LIKELY); NULL, do_main_label, PROB_VERY_LIKELY);
do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX, do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
NULL, do_main_label, PROB_VERY_LIKELY); NULL, do_main_label, PROB_VERY_LIKELY);
write_complex_part (target, const1_rtx, true); expand_arith_set_overflow (lhs, target);
emit_label (do_main_label); emit_label (do_main_label);
goto do_main; goto do_main;
default: default:
...@@ -1213,7 +1255,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, ...@@ -1213,7 +1255,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
is, thus we can keep do_main code oring in overflow as is. */ is, thus we can keep do_main code oring in overflow as is. */
do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode, NULL_RTX, do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode, NULL_RTX,
NULL, do_main_label, PROB_VERY_LIKELY); NULL, do_main_label, PROB_VERY_LIKELY);
write_complex_part (target, const1_rtx, true); expand_arith_set_overflow (lhs, target);
emit_label (do_main_label); emit_label (do_main_label);
goto do_main; goto do_main;
default: default:
...@@ -1617,7 +1659,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, ...@@ -1617,7 +1659,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
do_pending_stack_adjust (); do_pending_stack_adjust ();
} }
else if (lhs) else if (lhs)
write_complex_part (target, const1_rtx, true); expand_arith_set_overflow (lhs, target);
/* We're done. */ /* We're done. */
emit_label (done_label); emit_label (done_label);
...@@ -1628,7 +1670,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, ...@@ -1628,7 +1670,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
rtx_code_label *all_done_label = gen_label_rtx (); rtx_code_label *all_done_label = gen_label_rtx ();
do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX, do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
NULL, all_done_label, PROB_VERY_LIKELY); NULL, all_done_label, PROB_VERY_LIKELY);
write_complex_part (target, const1_rtx, true); expand_arith_set_overflow (lhs, target);
emit_label (all_done_label); emit_label (all_done_label);
} }
...@@ -1639,7 +1681,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, ...@@ -1639,7 +1681,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
rtx_code_label *set_noovf = gen_label_rtx (); rtx_code_label *set_noovf = gen_label_rtx ();
do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX, do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX,
NULL, all_done_label, PROB_VERY_LIKELY); NULL, all_done_label, PROB_VERY_LIKELY);
write_complex_part (target, const1_rtx, true); expand_arith_set_overflow (lhs, target);
do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX, do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
NULL, set_noovf, PROB_VERY_LIKELY); NULL, set_noovf, PROB_VERY_LIKELY);
do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX, do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
......
2016-06-24 Jakub Jelinek <jakub@redhat.com>
* c-c++-common/builtin-arith-overflow-1.c (generic_wrong_type, f3,
f4): Adjust expected diagnostics.
* c-c++-common/torture/builtin-arith-overflow.h (TP): New macro.
(T): If OVFP is defined, redefine to TP.
* c-c++-common/torture/builtin-arith-overflow-12.c: Adjust comment.
* c-c++-common/torture/builtin-arith-overflow-p-1.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-2.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-3.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-4.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-5.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-6.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-7.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-8.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-9.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-10.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-11.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-12.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-13.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-14.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-15.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-16.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-17.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-18.c: New test.
* c-c++-common/torture/builtin-arith-overflow-p-19.c: New test.
* g++.dg/ext/builtin-arith-overflow-1.C: Pass 0 instead of C
as last argument to __builtin_add_overflow_p.
2016-06-23 Uros Bizjak <ubizjak@gmail.com> 2016-06-23 Uros Bizjak <ubizjak@gmail.com>
* g++.dg/vect/pr33834_2.cc: Use dg-additional-options instead of * g++.dg/vect/pr33834_2.cc: Use dg-additional-options instead of
......
...@@ -118,14 +118,14 @@ generic_wrong_type (int a, int b) ...@@ -118,14 +118,14 @@ generic_wrong_type (int a, int b)
{ {
void *p = 0; void *p = 0;
double d = 0; double d = 0;
int x = __builtin_add_overflow (a, b, p); /* { dg-error "does not have pointer to integer type" } */ int x = __builtin_add_overflow (a, b, p); /* { dg-error "does not have pointer to integral type" } */
x += __builtin_sub_overflow (a, b, &p); /* { dg-error "does not have pointer to integer type" } */ x += __builtin_sub_overflow (a, b, &p); /* { dg-error "does not have pointer to integral type" } */
x += __builtin_mul_overflow (a, b, &d); /* { dg-error "does not have pointer to integer type" } */ x += __builtin_mul_overflow (a, b, &d); /* { dg-error "does not have pointer to integral type" } */
/* Also verify literal arguments. */ /* Also verify literal arguments. */
x += __builtin_add_overflow (1, 1, p); /* { dg-error "does not have pointer to integer type" } */ x += __builtin_add_overflow (1, 1, p); /* { dg-error "does not have pointer to integral type" } */
x += __builtin_sub_overflow (1, 1, &p); /* { dg-error "does not have pointer to integer type" } */ x += __builtin_sub_overflow (1, 1, &p); /* { dg-error "does not have pointer to integral type" } */
x += __builtin_mul_overflow (1, 1, &d); /* { dg-error "does not have pointer to integer type" } */ x += __builtin_mul_overflow (1, 1, &d); /* { dg-error "does not have pointer to integral type" } */
return x; return x;
} }
...@@ -236,8 +236,8 @@ f3 (float fa, int a, _Complex long int ca, double fb, void *pb, int b, enum E eb ...@@ -236,8 +236,8 @@ f3 (float fa, int a, _Complex long int ca, double fb, void *pb, int b, enum E eb
x += __builtin_sub_overflow_p (ca, b, eb); /* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */ x += __builtin_sub_overflow_p (ca, b, eb); /* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */
x += __builtin_mul_overflow_p (a, fb, bb); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */ x += __builtin_mul_overflow_p (a, fb, bb); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */
x += __builtin_add_overflow_p (a, pb, a); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */ x += __builtin_add_overflow_p (a, pb, a); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */
x += __builtin_sub_overflow_p (a, eb, eb); x += __builtin_sub_overflow_p (a, eb, eb); /* { dg-error "argument 3 in call to function\[^\n\r]*has enumerated type" } */
x += __builtin_mul_overflow_p (a, bb, bb); x += __builtin_mul_overflow_p (a, bb, bb); /* { dg-error "argument 3 in call to function\[^\n\r]*has boolean type" } */
x += __builtin_add_overflow_p (a, b, fa); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */ x += __builtin_add_overflow_p (a, b, fa); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */
x += __builtin_sub_overflow_p (a, b, ca); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */ x += __builtin_sub_overflow_p (a, b, ca); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */
x += __builtin_mul_overflow_p (a, b, c); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */ x += __builtin_mul_overflow_p (a, b, c); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */
...@@ -247,11 +247,11 @@ f3 (float fa, int a, _Complex long int ca, double fb, void *pb, int b, enum E eb ...@@ -247,11 +247,11 @@ f3 (float fa, int a, _Complex long int ca, double fb, void *pb, int b, enum E eb
int int
f4 (float *fp, double *dp, _Complex int *cp, enum E *ep, bool *bp, long long int *llp) 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" } */ int x = __builtin_add_overflow (1, 2, fp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integral 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_sub_overflow (1, 2, dp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integral 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_mul_overflow (1, 2, cp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integral 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_add_overflow (1, 2, ep); /* { dg-error "argument 3 in call to function\[^\n\r]*has pointer to enumerated 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_sub_overflow (1, 2, bp); /* { dg-error "argument 3 in call to function\[^\n\r]*has pointer to boolean type" } */
x += __builtin_mul_overflow (1, 2, llp); x += __builtin_mul_overflow (1, 2, llp);
return x; return x;
} }
/* Test __builtin_{add,sub,mul_overflow. */ /* Test __builtin_{add,sub,mul}_overflow. */
/* { dg-do run } */ /* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ /* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
......
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#include "builtin-arith-overflow-1.h"
#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)
return 0;
}
/* Test __builtin_{add,sub}_overflow_p 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-p-7.c"
/* Test __builtin_{add,sub}_overflow_p 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-p-7.c"
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run { target int128 } } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run { target c } } */
/* { 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
struct S
{
signed int s1 : 1;
unsigned int u1 : 1;
signed int s2 : 2;
unsigned int u2 : 2;
signed int s3 : 3;
unsigned int u3 : 3;
signed int s4 : 4;
unsigned int u4 : 4;
signed int s5 : 5;
unsigned int u5 : 5;
signed int s6 : 6;
unsigned int u6 : 6;
signed int s7 : 7;
unsigned int u7 : 7;
} vs;
#define TESTS \
TP (100, signed char, signed char, vs.u2, -1, 0, add, 1) \
TP (101, unsigned char, unsigned char, vs.u4, 5, 5, add, 0) \
TP (102, unsigned char, unsigned char, vs.u3, 5, 3, add, 1) \
TP (103, signed char, unsigned short, vs.u1, 5, 5, sub, 0) \
TP (104, signed char, unsigned short, vs.u1, 6, 5, sub, 0) \
TP (105, signed char, unsigned short, vs.u1, 7, 5, sub, 1) \
TP (106, signed char, unsigned short, vs.u4, 5, 6, sub, 1) \
TP (107, signed char, signed char, vs.u1, -1, -1, mul, 0) \
TP (108, signed char, signed char, vs.s1, -1, -1, mul, 1) \
TP (109, unsigned char, signed char, vs.u6, 17, -2, mul, 1) \
TP (110, unsigned char, signed char, vs.s6, 17, -2, mul, 1) \
TP (111, unsigned char, signed char, vs.s7, 17, -2, mul, 0) \
TP (112, unsigned WTYPE, signed WTYPE, vs.s5, 5, -2, mul, 0) \
TP (113, unsigned WTYPE, signed WTYPE, vs.s4, 5, -2, mul, 1) \
TP (114, long long int, long long int, vs.u2, -3, 5, add, 0) \
TP (115, long long int, long long int, vs.u1, -3, 5, add, 1) \
TP (116, long long int, int, vs.u3, -5, 3, add, 1) \
TP (117, long long int, int, vs.s1, -5, 3, add, 1) \
TP (118, long long int, int, vs.s2, -5, 3, add, 0) \
TP (119, int, WTYPE, vs.u2, -3, 5, add, 0) \
TP (120, int, WTYPE, vs.u1, -3, 5, add, 1) \
TP (121, unsigned char, unsigned char, vs.u6, SCHAR_MAX - 1, (unsigned char) SCHAR_MAX + 4, sub, 1) \
TP (122, unsigned char, unsigned char, vs.s3, SCHAR_MAX - 1, (unsigned char) SCHAR_MAX + 4, sub, 1) \
TP (123, unsigned char, unsigned char, vs.s4, SCHAR_MAX - 1, (unsigned char) SCHAR_MAX + 4, sub, 0) \
TP (124, unsigned int, unsigned int, vs.u7, INT_MAX, 1, add, 1) \
TP (125, unsigned int, unsigned int, vs.u7, 127, 1, add, 1) \
TP (126, unsigned int, unsigned int, vs.u7, 1, 63, add, 0) \
TP (127, int, int, vs.s7, INT_MIN, 1, sub, 1) \
TP (128, int, int, vs.s7, -64, 1, sub, 1) \
TP (129, int, int, vs.s7, -63, 1, sub, 0)
TESTS
#undef TP
#define TP(n, t1, t2, er, v1, v2, b, o) t##n##b ();
int
main ()
{
TESTS
return 0;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#include "builtin-arith-overflow-1.h"
#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)
return 0;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#include "builtin-arith-overflow-1.h"
#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)
return 0;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub,mul}_overflow_p. */
/* { dg-do run { target int128 } } */
/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */
#define OVFP
#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;
}
/* Test __builtin_{add,sub}_overflow_p 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)) void \
n (t1 x, t2 y, int *ovf) \
{ \
*ovf = __builtin_##b##_overflow_p (x, y, \
(tr) 0); \
}
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); \
n (t1##1, t2##2, &ovf); \
if (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;
}
/* Test __builtin_{add,sub}_overflow_p 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-p-7.c"
/* Test __builtin_{add,sub}_overflow_p 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-p-7.c"
...@@ -90,5 +90,70 @@ t##n##b (void) \ ...@@ -90,5 +90,70 @@ t##n##b (void) \
if (r2 != (tr) (vr) || v != 7 * o) \ if (r2 != (tr) (vr) || v != 7 * o) \
__builtin_abort (); \ __builtin_abort (); \
} }
#define TP(n, t1, t2, er, v1, v2, b, o) \
__attribute__((noinline, noclone)) void \
t##n##_1##b (t1 x, t2 y) \
{ \
if (__builtin_##b##_overflow_p (x, y, er)) \
bar (); \
} \
\
__attribute__((noinline, noclone)) void \
t##n##_2##b (t2 y) \
{ \
t1 x = (v1); \
if (__builtin_##b##_overflow_p (x, y, er)) \
bar (); \
} \
\
__attribute__((noinline, noclone)) void \
t##n##_3##b (t2 y) \
{ \
if (__builtin_##b##_overflow_p ((t1) (v1), y, \
er)) \
bar (); \
} \
\
__attribute__((noinline, noclone)) void \
t##n##_4##b (t1 x) \
{ \
t2 y = (v2); \
if (__builtin_##b##_overflow_p (x, y, er)) \
bar (); \
} \
\
__attribute__((noinline, noclone)) void \
t##n##_5##b (t1 x) \
{ \
if (__builtin_##b##_overflow_p (x, (t2) (v2), \
er)) \
bar (); \
} \
\
__attribute__((noinline, noclone)) void \
t##n##b (void) \
{ \
t1 x = (v1); \
t2 y = (v2); \
v = 0; \
t##n##_1##b (x, y); \
t##n##_2##b (y); \
t##n##_3##b (y); \
t##n##_4##b (x); \
t##n##_5##b (x); \
if (__builtin_##b##_overflow_p (x, y, er)) \
bar (); \
if (__builtin_##b##_overflow_p ((t1) (v1), \
(t2) (v2), \
er)) \
bar (); \
if (v != 7 * o) \
__builtin_abort (); \
}
#ifdef OVFP
#undef T
#define T(n, t1, t2, tr, v1, v2, vr, b, o) \
TP(n, t1, t2, (tr) 0, v1, v2, b, o)
#endif
#define ST(n, t, v1, v2, vr, b, o) \ #define ST(n, t, v1, v2, vr, b, o) \
T (n, t, t, t, v1, v2, vr, b, o) T (n, t, t, t, v1, v2, vr, b, o)
// { dg-do compile } // { dg-do compile }
enum A { B = 1, C = 2, D = __builtin_add_overflow_p (B, C, C) }; enum A { B = 1, C = 2, D = __builtin_add_overflow_p (B, C, 0) };
int e[__builtin_add_overflow_p (B, C, C) + 1]; int e[__builtin_add_overflow_p (B, C, 0) + 1];
template <int N> int foo (int); template <int N> int foo (int);
void void
bar () bar ()
{ {
foo <__builtin_add_overflow_p (B, C, C) + 1> (0); foo <__builtin_add_overflow_p (B, C, 0) + 1> (0);
} }
...@@ -4016,6 +4016,9 @@ extract_range_basic (value_range *vr, gimple *stmt) ...@@ -4016,6 +4016,9 @@ extract_range_basic (value_range *vr, gimple *stmt)
set_value_range_to_value (vr, set_value_range_to_value (vr,
build_int_cst (type, ovf), build_int_cst (type, ovf),
NULL); NULL);
else if (TYPE_PRECISION (type) == 1
&& !TYPE_UNSIGNED (type))
set_value_range_to_varying (vr);
else else
set_value_range (vr, VR_RANGE, build_int_cst (type, 0), set_value_range (vr, VR_RANGE, build_int_cst (type, 0),
build_int_cst (type, 1), NULL); build_int_cst (type, 1), NULL);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment