diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-11-21 17:18:17 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2019-11-21 17:18:17 +0000 |
commit | ba81dff0c57348a93854acd663d8ca42a29fe9f4 (patch) | |
tree | 1dd152dec0883580e53144a6e66298b05cd84cca | |
parent | d7a161d3e726c955559ce5291fbd44dd39dac206 (diff) |
Backported from mainline
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.
* gcc.c-torture/execute/pr91450-1.c: New test.
* gcc.c-torture/execute/pr91450-2.c: New test.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gcc-8-branch@278583 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/internal-fn.c | 27 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr91450-1.c | 88 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr91450-2.c | 76 |
5 files changed, 196 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f485ba64177..4c46e2bbd44 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,16 @@ 2019-11-21 Jakub Jelinek <jakub@redhat.com> Backported from mainline + 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-08 Jakub Jelinek <jakub@redhat.com> PR c++/92384 diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index da205c9d68a..3b95cb6d258 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -1385,7 +1385,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, /* s1 * s2 -> ur */ if (!uns0_p && !uns1_p && unsr_p) { - rtx tem, tem2; + rtx tem; switch (pos_neg0 | pos_neg1) { case 1: /* Both operands known to be non-negative. */ @@ -1415,10 +1415,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, 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); - do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode, - NULL_RTX, NULL, done_label, + do_compare_rtx_and_jump (pos_neg0 == 1 ? op0 : op1, const0_rtx, EQ, + true, mode, NULL_RTX, NULL, done_label, profile_probability::very_likely ()); goto do_error_label; } @@ -1449,16 +1447,23 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, 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); - do_compare_rtx_and_jump (tem2, const0_rtx, GE, false, mode, NULL_RTX, - NULL, do_main_label, profile_probability::very_likely ()); + tem = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false, + OPTAB_LIB_WIDEN); + do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX, + NULL, do_main_label, + profile_probability::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. */ - do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode, NULL_RTX, - NULL, do_main_label, profile_probability::very_likely ()); + if (pos_neg0 != 2) + 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); emit_label (do_main_label); goto do_main; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0f8be8f3b23..f1b1fd3da4d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,12 @@ 2019-11-21 Jakub Jelinek <jakub@redhat.com> Backported from mainline + 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. + 2019-11-08 Jakub Jelinek <jakub@redhat.com> PR c++/92384 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr91450-1.c b/gcc/testsuite/gcc.c-torture/execute/pr91450-1.c new file mode 100644 index 00000000000..9aafc5f791a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr91450-1.c @@ -0,0 +1,88 @@ +/* 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; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr91450-2.c b/gcc/testsuite/gcc.c-torture/execute/pr91450-2.c new file mode 100644 index 00000000000..bfaabbb5ac6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr91450-2.c @@ -0,0 +1,76 @@ +/* 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; +} |