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) ? x : y
becomes, for OP = (lshift, rshift) and in a scenario without overflows:
a !=/== 0 ? x : y
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 (`((a OP b) + c eq|ne c) ? x : y`): New pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/torture/ifcond-plus-shift-czero.c: New test.
Signed-off-by: Daniel Barboza <[email protected]>
---
gcc/match.pd | 17 +++++++++++++
.../gcc.dg/torture/ifcond-plus-shift-czero.c | 25 +++++++++++++++++++
2 files changed, 42 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 ccdc1129e23..fdc18b1ef41 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2824,6 +2824,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(le (minus (convert:etype @0) { lo; }) { hi; })
(gt (minus (convert:etype @0) { lo; }) { hi; })))))))))
+/* Reduces ((A OP B) + C EQ|NE C) ? X : Y to
+ A EQ|NE 0 ? x : y, for OP = (lshift, rshift). */
+(for cmp (eq ne)
+ (for op (lshift rshift)
+ (simplify
+ (cond (cmp:c (plus:c (op @1 @2) @0) @0) @3 @4)
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1)))
+ (with
+ {
+ fold_overflow_warning ("assuming signed overflow does not occur "
+ "when changing (X << imm) + C1 cmp C1 to "
+ "X << imm cmp 0 and X << imm cmp 0 "
+ "to X cmp 0",
+ WARN_STRICT_OVERFLOW_COMPARISON); }
+ (cond (cmp @1 { build_zero_cst (type); }) @3 @4))))))
+
/* X + Z < Y + Z is the same as X < Y when there is no overflow. */
(for op (lt le ge gt)
(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