Add a transformation for a nested lshift/rshift inside a plus that
compares for equality with the same operand of the plus. In other words:
((a OP b) + c EQ|NE c)
becomes, for OP = (lshift, rshift) and in a scenario without overflows:
a EQ|NE 0
This optimizes the following code, seen in perlbench:
long
frob(long x, long y, long z)
{
long ret = (y << 2) + z;
long cond = ret != z;
if (cond == 0)
ret = 0;
return ret;
}
gcc/ChangeLog:
* match.pd (`(cmp ((a OP b) + c) c`): New pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/torture/ifcond-plus-shift-czero.c: New test.
Signed-off-by: Daniel Barboza <[email protected]>
---
Changes from v1:
- Use an existing 'cmp' only pattern as base instead of adding a new
pattern that includes the conditional
- v1 link: https://gcc.gnu.org/pipermail/gcc-patches/2026-January/704992.html
gcc/match.pd | 13 ++++++++++
.../gcc.dg/torture/ifcond-plus-shift-czero.c | 25 +++++++++++++++++++
2 files changed, 38 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/torture/ifcond-plus-shift-czero.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 08d0810e986..27ee5c2ea6b 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2946,6 +2946,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
&& (CONSTANT_CLASS_P (@1) || (single_use (@2) && single_use (@3))))
(op @1 { build_zero_cst (TREE_TYPE (@1)); }))))
+/* Do the same but with lshift|rshift as @0. */
+(for cmp (eq ne)
+ (for op (lshift rshift)
+ (simplify
+ (cmp:c (nop_convert?@3 (plus:c@2 (op @0 @4) (convert1? @1))) (convert2? @1))
+ (with { tree type0 = TREE_TYPE (@0); }
+ (if (ANY_INTEGRAL_TYPE_P (type0)
+ && (TYPE_OVERFLOW_UNDEFINED (type0)
+ || TYPE_OVERFLOW_WRAPS (type0))
+ && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@2))
+ && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1)))
+ (cmp @0 { build_zero_cst (type0); }))))))
+
/* (&a + b) !=/== (&a[1] + c) -> (&a[0] - &a[1]) + b !=/== c */
(for neeq (ne eq)
(simplify
diff --git a/gcc/testsuite/gcc.dg/torture/ifcond-plus-shift-czero.c
b/gcc/testsuite/gcc.dg/torture/ifcond-plus-shift-czero.c
new file mode 100644
index 00000000000..769412202c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/ifcond-plus-shift-czero.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-phiopt2" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-fno-fat-lto-objects" } { "" } } */
+
+long
+f1 (long x, long y, long z)
+{
+ long ret = (y << 2) + z;
+ long cond = ret != z;
+ if (cond == 0)
+ ret = 0;
+ return ret;
+}
+
+long
+f2 (long x, long y, long z)
+{
+ long ret = (y >> 2) + z;
+ long cond = ret != z;
+ if (cond == 0)
+ ret = 0;
+ return ret;
+}
+
+/* { dg-final { scan-tree-dump-times "== 0" 2 "phiopt2" } } */
--
2.43.0