aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-01-05 10:57:52 +0100
committerJakub Jelinek <jakub@redhat.com>2021-01-05 10:59:00 +0100
commit4615cde5d7ef281d4b554df411f82ad707f0a54d (patch)
tree69005f7b86e4e76b7fed0153ad53bb708f0966a6
parent6b69738c1e30ec31cb11dce1d9209e7a5b92301b (diff)
downloadgcc-4615cde5d7ef281d4b554df411f82ad707f0a54d.zip
gcc-4615cde5d7ef281d4b554df411f82ad707f0a54d.tar.gz
gcc-4615cde5d7ef281d4b554df411f82ad707f0a54d.tar.bz2
simplify-rtx: Optimize (x - 1) * y + y [PR98334]
We don't try to optimize for signed x, y (int) (x - 1U) * y + y into x * y, we can't do that with signed x * y, because the former is well defined for INT_MIN and -1, while the latter is not. We could perhaps optimize it during isel or some very late optimization where we'd turn magically flag_wrapv, but we don't do that yet. This patch optimizes it in simplify-rtx.c, such that we can optimize it during combine. 2021-01-05 Jakub Jelinek <jakub@redhat.com> PR rtl-optimization/98334 * simplify-rtx.c (simplify_context::simplify_binary_operation_1): Optimize (X - 1) * Y + Y to X * Y or (X + 1) * Y - Y to X * Y. * gcc.target/i386/pr98334.c: New test.
-rw-r--r--gcc/simplify-rtx.c56
-rw-r--r--gcc/testsuite/gcc.target/i386/pr98334.c36
2 files changed, 92 insertions, 0 deletions
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index e041b8e..571e233 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -2602,6 +2602,42 @@ simplify_context::simplify_binary_operation_1 (rtx_code code,
return (set_src_cost (tem, int_mode, speed)
<= set_src_cost (orig, int_mode, speed) ? tem : 0);
}
+
+ /* Optimize (X - 1) * Y + Y to X * Y. */
+ lhs = op0;
+ rhs = op1;
+ if (GET_CODE (op0) == MULT)
+ {
+ if (((GET_CODE (XEXP (op0, 0)) == PLUS
+ && XEXP (XEXP (op0, 0), 1) == constm1_rtx)
+ || (GET_CODE (XEXP (op0, 0)) == MINUS
+ && XEXP (XEXP (op0, 0), 1) == const1_rtx))
+ && rtx_equal_p (XEXP (op0, 1), op1))
+ lhs = XEXP (XEXP (op0, 0), 0);
+ else if (((GET_CODE (XEXP (op0, 1)) == PLUS
+ && XEXP (XEXP (op0, 1), 1) == constm1_rtx)
+ || (GET_CODE (XEXP (op0, 1)) == MINUS
+ && XEXP (XEXP (op0, 1), 1) == const1_rtx))
+ && rtx_equal_p (XEXP (op0, 0), op1))
+ lhs = XEXP (XEXP (op0, 1), 0);
+ }
+ else if (GET_CODE (op1) == MULT)
+ {
+ if (((GET_CODE (XEXP (op1, 0)) == PLUS
+ && XEXP (XEXP (op1, 0), 1) == constm1_rtx)
+ || (GET_CODE (XEXP (op1, 0)) == MINUS
+ && XEXP (XEXP (op1, 0), 1) == const1_rtx))
+ && rtx_equal_p (XEXP (op1, 1), op0))
+ rhs = XEXP (XEXP (op1, 0), 0);
+ else if (((GET_CODE (XEXP (op1, 1)) == PLUS
+ && XEXP (XEXP (op1, 1), 1) == constm1_rtx)
+ || (GET_CODE (XEXP (op1, 1)) == MINUS
+ && XEXP (XEXP (op1, 1), 1) == const1_rtx))
+ && rtx_equal_p (XEXP (op1, 0), op0))
+ rhs = XEXP (XEXP (op1, 1), 0);
+ }
+ if (lhs != op0 || rhs != op1)
+ return simplify_gen_binary (MULT, int_mode, lhs, rhs);
}
/* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit. */
@@ -2789,6 +2825,26 @@ simplify_context::simplify_binary_operation_1 (rtx_code code,
return (set_src_cost (tem, int_mode, speed)
<= set_src_cost (orig, int_mode, speed) ? tem : 0);
}
+
+ /* Optimize (X + 1) * Y - Y to X * Y. */
+ lhs = op0;
+ if (GET_CODE (op0) == MULT)
+ {
+ if (((GET_CODE (XEXP (op0, 0)) == PLUS
+ && XEXP (XEXP (op0, 0), 1) == const1_rtx)
+ || (GET_CODE (XEXP (op0, 0)) == MINUS
+ && XEXP (XEXP (op0, 0), 1) == constm1_rtx))
+ && rtx_equal_p (XEXP (op0, 1), op1))
+ lhs = XEXP (XEXP (op0, 0), 0);
+ else if (((GET_CODE (XEXP (op0, 1)) == PLUS
+ && XEXP (XEXP (op0, 1), 1) == const1_rtx)
+ || (GET_CODE (XEXP (op0, 1)) == MINUS
+ && XEXP (XEXP (op0, 1), 1) == constm1_rtx))
+ && rtx_equal_p (XEXP (op0, 0), op1))
+ lhs = XEXP (XEXP (op0, 1), 0);
+ }
+ if (lhs != op0)
+ return simplify_gen_binary (MULT, int_mode, lhs, op1);
}
/* (a - (-b)) -> (a + b). True even for IEEE. */
diff --git a/gcc/testsuite/gcc.target/i386/pr98334.c b/gcc/testsuite/gcc.target/i386/pr98334.c
new file mode 100644
index 0000000..283abc5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr98334.c
@@ -0,0 +1,36 @@
+/* PR rtl-optimization/98334 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fomit-frame-pointer -fno-stack-protector" } */
+/* { dg-final { scan-assembler-not "\taddl\t" } } */
+/* { dg-final { scan-assembler-not "\tsubl\t" } } */
+/* { dg-final { scan-assembler-not "\tleal\t" } } */
+
+int
+foo (int i, unsigned int n)
+{
+ int result = 0;
+ while (n > 0)
+ {
+ result += i;
+ n -= 1;
+ }
+ return result;
+}
+
+int
+bar (int x, int y)
+{
+ return (int) (y - 1U) * x + x;
+}
+
+int
+baz (int x, int y)
+{
+ return (y - 1) * x + x;
+}
+
+int
+qux (int x, int y)
+{
+ return x * (int) (y + 1U) - x;
+}