aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/match.pd22
-rw-r--r--gcc/testsuite/gcc.dg/fold-condneg-1.c59
-rw-r--r--gcc/testsuite/gcc.dg/fold-condneg-2.c11
-rw-r--r--gcc/testsuite/gcc.dg/fold-condnot-1.c84
-rw-r--r--gcc/testsuite/gcc.dg/pr101145-1.c12
-rw-r--r--gcc/testsuite/gcc.dg/pr101145-2.c15
-rw-r--r--gcc/tree-ssa-loop-niter.c19
7 files changed, 221 insertions, 1 deletions
diff --git a/gcc/match.pd b/gcc/match.pd
index 0a00b08..0d7b8dd 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4403,6 +4403,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(op (min @X { wide_int_to_tree (from_type, real_c1); })
{ wide_int_to_tree (from_type, c2); })))))))))
+/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2. */
+(simplify
+ (cond (ne @0 INTEGER_CST@1) (negate@3 @0) INTEGER_CST@2)
+ (if (!TYPE_SATURATING (type)
+ && (TYPE_OVERFLOW_WRAPS (type)
+ || !wi::only_sign_bit_p (wi::to_wide (@1)))
+ && wi::eq_p (wi::neg (wi::to_wide (@1)), wi::to_wide (@2)))
+ @3))
+
+/* X != C1 ? ~X : C2 simplifies to ~X when ~C1 == C2. */
+(simplify
+ (cond (ne @0 INTEGER_CST@1) (bit_not@3 @0) INTEGER_CST@2)
+ (if (wi::eq_p (wi::bit_not (wi::to_wide (@1)), wi::to_wide (@2)))
+ @3))
+
+/* (X + 1) > Y ? -X : 1 simplifies to X >= Y ? -X : 1 when
+ X is unsigned, as when X + 1 overflows, X is -1, so -X == 1. */
+(simplify
+ (cond (gt (plus @0 integer_onep) @1) (negate @0) integer_onep@2)
+ (if (TYPE_UNSIGNED (type))
+ (cond (ge @0 @1) (negate @0) @2)))
+
(for cnd (cond vec_cond)
/* A ? B : (A ? X : C) -> A ? B : C. */
(simplify
diff --git a/gcc/testsuite/gcc.dg/fold-condneg-1.c b/gcc/testsuite/gcc.dg/fold-condneg-1.c
new file mode 100644
index 0000000..c4edd74
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-condneg-1.c
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int test_i0(int x)
+{
+ return x != 0 ? -x : 0;
+}
+
+int test_i1(int x)
+{
+ return x != 1 ? -x : -1;
+}
+
+int test_im1(int x)
+{
+ return x != -1 ? -x : 1;
+}
+
+unsigned int test_u0(unsigned int x)
+{
+ return x != 0 ? -x : 0;
+}
+
+unsigned int test_u1(unsigned int x)
+{
+ return x != 1 ? -x : ~0u;
+}
+
+unsigned int test_um1(unsigned int x)
+{
+ return x != ~0u ? -x : 1;
+}
+
+unsigned char test_uc0(unsigned char x)
+{
+ return x != 0 ? -x : 0;
+}
+
+unsigned char test_uc1(unsigned char x)
+{
+ return x != 1 ? -x : 255;
+}
+
+unsigned char test_uc127(unsigned char x)
+{
+ return x != 127 ? -x : 129;
+}
+
+unsigned char test_uc128(unsigned char x)
+{
+ return x != 128 ? -x : 128;
+}
+
+unsigned char test_uc255(unsigned char x)
+{
+ return x != 255 ? -x : 1;
+}
+
+/* { dg-final { scan-tree-dump-not "goto" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/fold-condneg-2.c b/gcc/testsuite/gcc.dg/fold-condneg-2.c
new file mode 100644
index 0000000..1af2463
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-condneg-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftrapv -fdump-tree-optimized" } */
+
+#define INT_MIN (-__INT_MAX__ - 1)
+
+int test(int x)
+{
+ return x != INT_MIN ? -x : INT_MIN;
+}
+
+/* { dg-final { scan-tree-dump "goto" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/fold-condnot-1.c b/gcc/testsuite/gcc.dg/fold-condnot-1.c
new file mode 100644
index 0000000..75d558c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-condnot-1.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int test_i0(int x)
+{
+ return x != 0 ? ~x : ~0;
+}
+
+int test_i1(int x)
+{
+ return x != 1 ? ~x : -2;
+}
+
+int test_im1(int x)
+{
+ return x != ~0 ? ~x : 0;
+}
+
+unsigned int test_u0(unsigned int x)
+{
+ return x != 0 ? ~x : ~0;
+}
+
+unsigned int test_u1(unsigned int x)
+{
+ return x != 1 ? ~x : ~1u;
+}
+
+unsigned int test_um1(unsigned int x)
+{
+ return x != ~0u ? ~x : 0;
+}
+
+signed char test_c0(signed char x)
+{
+ return x != 0 ? ~x : -1;
+}
+
+signed char test_c1(signed char x)
+{
+ return x != 1 ? ~x : -2;
+}
+
+signed char test_cm1(signed char x)
+{
+ return x != -1 ? ~x : 0;
+}
+
+signed char test_cm128(signed char x)
+{
+ return x != -128 ? ~x : 127;
+}
+
+signed char test_c127(signed char x)
+{
+ return x != 127 ? ~x : -128;
+}
+
+unsigned char test_uc0(unsigned char x)
+{
+ return x != 0 ? ~x : 255;
+}
+
+unsigned char test_uc1(unsigned char x)
+{
+ return x != 1 ? ~x : 254;
+}
+
+unsigned char test_uc127(unsigned char x)
+{
+ return x != 127 ? ~x : 128;
+}
+
+unsigned char test_uc128(unsigned char x)
+{
+ return x != 128 ? ~x : 127;
+}
+
+unsigned char test_ucm1(unsigned char x)
+{
+ return x != 255 ? ~x : 0;
+}
+
+/* { dg-final { scan-tree-dump-not "goto" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr101145-1.c b/gcc/testsuite/gcc.dg/pr101145-1.c
new file mode 100644
index 0000000..e6f7923
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101145-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+unsigned foo(unsigned val, unsigned start)
+{
+ unsigned cnt = 0;
+ for (unsigned i = start; i > val; ++i)
+ cnt++;
+ return cnt;
+}
+
+/* { dg-final { scan-tree-dump "cnt_\[0-9\] = -start_\[0-9\]\\(D\\);" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr101145-2.c b/gcc/testsuite/gcc.dg/pr101145-2.c
new file mode 100644
index 0000000..6ecfeb2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101145-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+unsigned foo(unsigned val, unsigned start)
+{
+ unsigned cnt = 0;
+ unsigned i = start;
+ do {
+ cnt++;
+ i++;
+ } while (i > val);
+ return cnt;
+}
+
+/* { dg-final { scan-tree-dump "cnt_\[0-9\] = start_\[0-9\]\\(D\\) >= val_\[0-9\]\\(D\\) \\? _\[0-9\] : 1;" "optimized" } } */
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 7510940..06954e4 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -1478,7 +1478,7 @@ assert_loop_rolls_lt (tree type, affine_iv *iv0, affine_iv *iv1,
The number of iterations is stored to NITER. */
static bool
-number_of_iterations_until_wrap (class loop *, tree type, affine_iv *iv0,
+number_of_iterations_until_wrap (class loop *loop, tree type, affine_iv *iv0,
affine_iv *iv1, class tree_niter_desc *niter)
{
tree niter_type = unsigned_type_for (type);
@@ -1506,6 +1506,23 @@ number_of_iterations_until_wrap (class loop *, tree type, affine_iv *iv0,
num = fold_build2 (MINUS_EXPR, niter_type, wide_int_to_tree (type, max),
iv1->base);
+
+ /* When base has the form iv + 1, if we know iv >= n, then iv + 1 < n
+ only when iv + 1 overflows, i.e. when iv == TYPE_VALUE_MAX. */
+ if (sgn == UNSIGNED
+ && integer_onep (step)
+ && TREE_CODE (iv1->base) == PLUS_EXPR
+ && integer_onep (TREE_OPERAND (iv1->base, 1)))
+ {
+ tree cond = fold_build2 (GE_EXPR, boolean_type_node,
+ TREE_OPERAND (iv1->base, 0), iv0->base);
+ cond = simplify_using_initial_conditions (loop, cond);
+ if (integer_onep (cond))
+ may_be_zero = fold_build2 (EQ_EXPR, boolean_type_node,
+ TREE_OPERAND (iv1->base, 0),
+ TYPE_MAX_VALUE (type));
+ }
+
high = max;
if (TREE_CODE (iv1->base) == INTEGER_CST)
low = wi::to_wide (iv1->base) - 1;