aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-11-21 17:18:17 +0000
committerJakub Jelinek <jakub@redhat.com>2019-11-21 17:18:17 +0000
commitba81dff0c57348a93854acd663d8ca42a29fe9f4 (patch)
tree1dd152dec0883580e53144a6e66298b05cd84cca
parentd7a161d3e726c955559ce5291fbd44dd39dac206 (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/ChangeLog10
-rw-r--r--gcc/internal-fn.c27
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr91450-1.c88
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr91450-2.c76
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;
+}