This patch fixes both 119471 and the remainder of 110992.
At issue is we do not recognize that if
"a * b != 0" , then neither "a" nor "b" can be zero.
This is fairly trivial with range-ops. op1_range and op2_range for
operator_mult are taught that if the LHS does not contain zero, than
neither does either operand.
Included are patches for trunk (gcc15), gcc14, and gcc13. All are
basically the same few lines.
I presume we want to wait for stage 1 to check this into trunk .
Bootstraps with no regressions on x86_64-pc-linux-gnu on all 3
branches. OK for gcc13 and gcc14 branches?
Andrew
From 74edd2831affac005d2d5bf0170668188aa1a091 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Thu, 27 Mar 2025 13:44:00 -0400
Subject: [PATCH] If the LHS does not contain zero, neither do multiply
operands.
Given ~[0,0] = op1 * op2, range-ops should determine that neither op1 nor
op2 is zero. Add this to the operator_mult for op1_range. op2_range
simply invokes op1_range, so both will be covered.
PR tree-optimzation/110992.c
PR tree-optimzation/119471.c
gcc/
* range-op.cc (operator_mult::op1_range): If the LHS does not
contain zero, return non-zero.
gcc/testsuite/
* gcc.dg/pr110992.c: New.
* gcc.dg/pr119471.c: New.
---
gcc/range-op.cc | 7 +++++++
gcc/testsuite/gcc.dg/pr110992.c | 18 ++++++++++++++++++
gcc/testsuite/gcc.dg/pr119471.c | 19 +++++++++++++++++++
3 files changed, 44 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/pr110992.c
create mode 100644 gcc/testsuite/gcc.dg/pr119471.c
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index d1a1cd73687..6ea0d9935eb 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2140,6 +2140,13 @@ operator_mult::op1_range (irange &r, tree type,
wide_int offset;
if (op2.singleton_p (offset) && offset != 0)
return range_op_handler (TRUNC_DIV_EXPR).fold_range (r, type, lhs, op2);
+
+ // ~[0, 0] = op1 * op2 defines op1 and op2 as non-zero.
+ if (!lhs.contains_p (wi::zero (TYPE_PRECISION (lhs.type ()))))
+ {
+ r.set_nonzero (type);
+ return true;
+ }
return false;
}
diff --git a/gcc/testsuite/gcc.dg/pr110992.c b/gcc/testsuite/gcc.dg/pr110992.c
new file mode 100644
index 00000000000..05e9b9267e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr110992.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void foo (int);
+
+int f(unsigned b, short c)
+{
+ int bt = b;
+ int bt1 = bt;
+ int t = bt1 & -(c!=0);
+ // int t = bt1 * (c!=0);
+
+ if (!t) return 0;
+ foo(bt == 0);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "foo \\(0\\)" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/pr119471.c b/gcc/testsuite/gcc.dg/pr119471.c
new file mode 100644
index 00000000000..4c55d85f77c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr119471.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int fa(int a, int b)
+{
+ int c = a * b;
+ if (c != 0)
+ return (a != 0);
+ return 0;
+}
+int fb(int a, int b)
+{
+ int c = a * b;
+ if (c != 0)
+ return (b != 0);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "PHI <1" 2 "evrp" } } */
--
2.45.0
From 68f8db2c13df7acee838ba1503d97f9e7f18ecea Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Thu, 27 Mar 2025 13:50:16 -0400
Subject: [PATCH 2/2] If the LHS does not contain zero, neither do multiply
operands.
Given ~[0,0] = op1 * op2, range-ops should determine that neither op1 nor
op2 is zero. Add this to the operator_mult for op1_range. op2_range
simply invokes op1_range, so both will be covered.
PR tree-optimzation/110992.c
PR tree-optimzation/119471.c
gcc/
* range-op.cc (operator_mult::op1_range): If the LHS does not
contain zero, return non-zero.
gcc/testsuite/
* gcc.dg/pr110992.c: New.
* gcc.dg/pr119471.c: New.
---
gcc/range-op.cc | 8 ++++++++
gcc/testsuite/gcc.dg/pr110992.c | 18 ++++++++++++++++++
gcc/testsuite/gcc.dg/pr119471.c | 19 +++++++++++++++++++
3 files changed, 45 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/pr110992.c
create mode 100644 gcc/testsuite/gcc.dg/pr119471.c
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 97a88dc7efa..275b3ae6891 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -1976,6 +1976,14 @@ operator_mult::op1_range (irange &r, tree type,
if (op2.singleton_p (&offset) && !integer_zerop (offset))
return range_op_handler (TRUNC_DIV_EXPR, type).fold_range (r, type,
lhs, op2);
+
+ // ~[0, 0] = op1 * op2 defines op1 and op2 as non-zero.
+ if (!contains_zero_p ((lhs)))
+ {
+ r.set_nonzero (type);
+ return true;
+ }
+
return false;
}
diff --git a/gcc/testsuite/gcc.dg/pr110992.c b/gcc/testsuite/gcc.dg/pr110992.c
new file mode 100644
index 00000000000..05e9b9267e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr110992.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void foo (int);
+
+int f(unsigned b, short c)
+{
+ int bt = b;
+ int bt1 = bt;
+ int t = bt1 & -(c!=0);
+ // int t = bt1 * (c!=0);
+
+ if (!t) return 0;
+ foo(bt == 0);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "foo \\(0\\)" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/pr119471.c b/gcc/testsuite/gcc.dg/pr119471.c
new file mode 100644
index 00000000000..4c55d85f77c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr119471.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int fa(int a, int b)
+{
+ int c = a * b;
+ if (c != 0)
+ return (a != 0);
+ return 0;
+}
+int fb(int a, int b)
+{
+ int c = a * b;
+ if (c != 0)
+ return (b != 0);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "PHI <1" 2 "evrp" } } */
--
2.45.0
From e4be843cafa680e2be336a7d4b4424828b98dd20 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Wed, 26 Mar 2025 10:34:42 -0400
Subject: [PATCH 2/2] If the LHS does not contain zero, neither do multiply
operands.
Given ~[0,0] = op1 * op2, range-ops should determine that neither op1 nor
op2 is zero. Add this to the operator_mult for op1_range. op2_range
simply invokes op1_range, so both will be covered.
PR tree-optimzation/110992.c
PR tree-optimzation/119471.c
gcc/
* range-op.cc (operator_mult::op1_range): If the LHS does not
contain zero, return non-zero.
gcc/testsuite/
* gcc.dg/pr110992.c: New.
* gcc.dg/pr119471.c: New.
---
gcc/range-op.cc | 7 +++++++
gcc/testsuite/gcc.dg/pr110992.c | 18 ++++++++++++++++++
gcc/testsuite/gcc.dg/pr119471.c | 19 +++++++++++++++++++
3 files changed, 44 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/pr110992.c
create mode 100644 gcc/testsuite/gcc.dg/pr119471.c
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index e6aeefd436f..5c0bcdc3b37 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2220,6 +2220,13 @@ operator_mult::op1_range (irange &r, tree type,
wide_int offset;
if (op2.singleton_p (offset) && offset != 0)
return range_op_handler (TRUNC_DIV_EXPR).fold_range (r, type, lhs, op2);
+
+ // ~[0, 0] = op1 * op2 defines op1 and op2 as non-zero.
+ if (!lhs.contains_p (wi::zero (TYPE_PRECISION (lhs.type ()))))
+ {
+ r.set_nonzero (type);
+ return true;
+ }
return false;
}
diff --git a/gcc/testsuite/gcc.dg/pr110992.c b/gcc/testsuite/gcc.dg/pr110992.c
new file mode 100644
index 00000000000..05e9b9267e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr110992.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void foo (int);
+
+int f(unsigned b, short c)
+{
+ int bt = b;
+ int bt1 = bt;
+ int t = bt1 & -(c!=0);
+ // int t = bt1 * (c!=0);
+
+ if (!t) return 0;
+ foo(bt == 0);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "foo \\(0\\)" 1 "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/pr119471.c b/gcc/testsuite/gcc.dg/pr119471.c
new file mode 100644
index 00000000000..4c55d85f77c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr119471.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+int fa(int a, int b)
+{
+ int c = a * b;
+ if (c != 0)
+ return (a != 0);
+ return 0;
+}
+int fb(int a, int b)
+{
+ int c = a * b;
+ if (c != 0)
+ return (b != 0);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "PHI <1" 2 "evrp" } } */
--
2.45.0