Commit beeac4c2 by Jakub Jelinek Committed by Jakub Jelinek

re PR middle-end/91450 (__builtin_mul_overflow(A,B,R) wrong code if product < 0,…

re PR middle-end/91450 (__builtin_mul_overflow(A,B,R) wrong code if product < 0, *R is unsigned, and !(A&B))

	PR middle-end/91450
	* internal-fn.c (expand_mul_overflow): For s1 * s2 -> ur, if one
	operand is negative and one non-negative, compare the non-negative
	one against 0 rather than comparing s1 & s2 against 0.  Otherwise,
	don't compare (s1 & s2) == 0, but compare separately both s1 == 0
	and s2 == 0, unless one of them is known to be negative.  Remove
	tem2 variable, use tem where tem2 has been used before.

	* gcc.c-torture/execute/pr91450-1.c: New test.
	* gcc.c-torture/execute/pr91450-2.c: New test.

From-SVN: r278437
parent 655b60f9
2019-11-19 Jakub Jelinek <jakub@redhat.com>
PR middle-end/91450
* internal-fn.c (expand_mul_overflow): For s1 * s2 -> ur, if one
operand is negative and one non-negative, compare the non-negative
one against 0 rather than comparing s1 & s2 against 0. Otherwise,
don't compare (s1 & s2) == 0, but compare separately both s1 == 0
and s2 == 0, unless one of them is known to be negative. Remove
tem2 variable, use tem where tem2 has been used before.
2019-11-19 Eric Botcazou <ebotcazou@adacore.com> 2019-11-19 Eric Botcazou <ebotcazou@adacore.com>
* doc/invoke.texi (-gno-internal-reset-location-views): Fix typo. * doc/invoke.texi (-gno-internal-reset-location-views): Fix typo.
...@@ -1409,7 +1409,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, ...@@ -1409,7 +1409,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
/* s1 * s2 -> ur */ /* s1 * s2 -> ur */
if (!uns0_p && !uns1_p && unsr_p) if (!uns0_p && !uns1_p && unsr_p)
{ {
rtx tem, tem2; rtx tem;
switch (pos_neg0 | pos_neg1) switch (pos_neg0 | pos_neg1)
{ {
case 1: /* Both operands known to be non-negative. */ case 1: /* Both operands known to be non-negative. */
...@@ -1439,10 +1439,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, ...@@ -1439,10 +1439,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
ops.op2 = NULL_TREE; ops.op2 = NULL_TREE;
ops.location = loc; ops.location = loc;
res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL); res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false, do_compare_rtx_and_jump (pos_neg0 == 1 ? op0 : op1, const0_rtx, EQ,
OPTAB_LIB_WIDEN); true, mode, NULL_RTX, NULL, done_label,
do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode,
NULL_RTX, NULL, done_label,
profile_probability::very_likely ()); profile_probability::very_likely ());
goto do_error_label; goto do_error_label;
} }
...@@ -1473,16 +1471,23 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, ...@@ -1473,16 +1471,23 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
arg1 = error_mark_node; arg1 = error_mark_node;
emit_jump (do_main_label); emit_jump (do_main_label);
emit_label (after_negate_label); emit_label (after_negate_label);
tem2 = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false, tem = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
OPTAB_LIB_WIDEN); OPTAB_LIB_WIDEN);
do_compare_rtx_and_jump (tem2, const0_rtx, GE, false, mode, NULL_RTX, do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
NULL, do_main_label, profile_probability::very_likely ()); NULL, do_main_label,
profile_probability::very_likely ());
/* One argument is negative here, the other positive. This /* One argument is negative here, the other positive. This
overflows always, unless one of the arguments is 0. But overflows always, unless one of the arguments is 0. But
if e.g. s2 is 0, (U) s1 * 0 doesn't overflow, whatever s1 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. */ 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, if (pos_neg0 != 2)
NULL, do_main_label, profile_probability::very_likely ()); do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
NULL, do_main_label,
profile_probability::very_unlikely ());
if (pos_neg1 != 2)
do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
NULL, do_main_label,
profile_probability::very_unlikely ());
expand_arith_set_overflow (lhs, target); expand_arith_set_overflow (lhs, target);
emit_label (do_main_label); emit_label (do_main_label);
goto do_main; goto do_main;
......
2019-11-19 Jakub Jelinek <jakub@redhat.com> 2019-11-19 Jakub Jelinek <jakub@redhat.com>
PR middle-end/91450
* gcc.c-torture/execute/pr91450-1.c: New test.
* gcc.c-torture/execute/pr91450-2.c: New test.
PR c++/92504 PR c++/92504
* g++.dg/gomp/pr92504.C: New test. * g++.dg/gomp/pr92504.C: New test.
......
/* PR middle-end/91450 */
__attribute__((noipa)) unsigned long long
foo (int a, int b)
{
unsigned long long r;
if (!__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
return r;
}
__attribute__((noipa)) unsigned long long
bar (int a, int b)
{
unsigned long long r;
if (a >= 0)
return 0;
if (!__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
return r;
}
__attribute__((noipa)) unsigned long long
baz (int a, int b)
{
unsigned long long r;
if (b >= 0)
return 0;
if (!__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
return r;
}
__attribute__((noipa)) unsigned long long
qux (int a, int b)
{
unsigned long long r;
if (a >= 0)
return 0;
if (b < 0)
return 0;
if (!__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
return r;
}
__attribute__((noipa)) unsigned long long
quux (int a, int b)
{
unsigned long long r;
if (a < 0)
return 0;
if (b >= 0)
return 0;
if (!__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
return r;
}
int
main ()
{
if (foo (-4, 2) != -8ULL)
__builtin_abort ();
if (foo (2, -4) != -8ULL)
__builtin_abort ();
if (bar (-4, 2) != -8ULL)
__builtin_abort ();
if (baz (2, -4) != -8ULL)
__builtin_abort ();
if (qux (-4, 2) != -8ULL)
__builtin_abort ();
if (quux (2, -4) != -8ULL)
__builtin_abort ();
if (foo (-2, 1) != -2ULL)
__builtin_abort ();
if (foo (1, -2) != -2ULL)
__builtin_abort ();
if (bar (-2, 1) != -2ULL)
__builtin_abort ();
if (baz (1, -2) != -2ULL)
__builtin_abort ();
if (qux (-2, 1) != -2ULL)
__builtin_abort ();
if (quux (1, -2) != -2ULL)
__builtin_abort ();
return 0;
}
/* PR middle-end/91450 */
__attribute__((noipa)) void
foo (int a, int b)
{
unsigned long long r;
if (__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
if (r != 0)
__builtin_abort ();
}
__attribute__((noipa)) void
bar (int a, int b)
{
unsigned long long r;
if (a >= 0)
return;
if (__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
if (r != 0)
__builtin_abort ();
}
__attribute__((noipa)) void
baz (int a, int b)
{
unsigned long long r;
if (b >= 0)
return;
if (__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
if (r != 0)
__builtin_abort ();
}
__attribute__((noipa)) void
qux (int a, int b)
{
unsigned long long r;
if (a >= 0)
return;
if (b < 0)
return;
if (__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
if (r != 0)
__builtin_abort ();
}
__attribute__((noipa)) void
quux (int a, int b)
{
unsigned long long r;
if (a < 0)
return;
if (b >= 0)
return;
if (__builtin_mul_overflow (a, b, &r))
__builtin_abort ();
if (r != 0)
__builtin_abort ();
}
int
main ()
{
foo (-4, 0);
foo (0, -4);
foo (0, 0);
bar (-4, 0);
baz (0, -4);
qux (-4, 0);
quux (0, -4);
return 0;
}
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