On 19/11/25 20:47, Jakub Jelinek wrote:
External email: Use caution opening links or attachments
On Wed, Nov 19, 2025 at 08:39:48PM +0530, Dhruv Chawla wrote:
Ah, I didn't even think of that, good catch. I've attached an updated patch,
does it look okay?
Signed-off-by: Dhruv Chawla <[email protected]>
PR tree-optimization/122733
gcc/ChangeLog:
* match.pd: Remove patterns. Also call constant_boolean_node instead of
Usually one specifies the match.pd entities with (parts of) the
transformation comments, so I'd say:
* match.pd ((y << x) {<,<=,>,>=} x): Remove.
((y << x) == x, (y << x) != x): Merge into a single pattern
with iterator.
+/* (y << x) == x -> false and (y << x) != x -> true when y != 0. */
+(for cmp (eq ne)
(simplify
(cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
- && tree_expr_nonzero_p (@0)
- && tree_expr_nonnegative_p (@0))
- { build_one_cst (type); })))
+ && tree_expr_nonzero_p (@0))
+ { constant_boolean_node (cmp != EQ_EXPR, type); })))
I think the normal match.pd indentation is by 1 column instead of 2,
so
(for cmp (eq ne)
(simplify
(cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
&& tree_expr_nonzero_p (@0))
{ constant_boolean_node (cmp != EQ_EXPR, type); })))
Otherwise LGTM.
Thanks, I have attached the updated patch.
Jakub
--
Regards,
Dhruv
-- >8 --
From 6a0f575f33410a2edd2b86387a764c1f750a10a1 Mon Sep 17 00:00:00 2001
From: Dhruv Chawla <[email protected]>
Date: Wed, 19 Nov 2025 04:55:08 -0800
Subject: [PATCH v4] PR tree-optimization/122733: Remove patterns for (y << x)
{<,<=,>,>=} x
These patterns should not be in match.pd as they require range
information checks that ideally belong in VRP. They were also causing
breakages as the checks weren't tight enough.
Bootstrapped and regtested on aarch64-linux-gnu.
Signed-off-by: Dhruv Chawla <[email protected]>
PR tree-optimization/122733
gcc/ChangeLog:
* match.pd ((y << x) {<,<=,>,>=} x): Remove.
((y << x) {==,!=} x): Call constant_boolean_node instead of
build_one_cst/build_zero_cst and combine into one pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/match-shift-cmp-1.c: Update test to only check
equality.
* gcc.dg/match-shift-cmp-2.c: Likewise.
* gcc.dg/match-shift-cmp-3.c: Likewise.
* gcc.dg/match-shift-cmp-4.c: Removed.
---
gcc/match.pd | 34 +++-------------
gcc/testsuite/gcc.dg/match-shift-cmp-1.c | 11 +----
gcc/testsuite/gcc.dg/match-shift-cmp-2.c | 23 ++---------
gcc/testsuite/gcc.dg/match-shift-cmp-3.c | 27 ++++++-------
gcc/testsuite/gcc.dg/match-shift-cmp-4.c | 51 ------------------------
5 files changed, 23 insertions(+), 123 deletions(-)
delete mode 100644 gcc/testsuite/gcc.dg/match-shift-cmp-4.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 63d56b08192..4e064e18570 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1339,37 +1339,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (INTEGRAL_TYPE_P (type))
(rshift (op @0 @2) @1))))
-/* (y << x) == x -> 0 when y != 0. */
-(simplify
- (eq:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
- && tree_expr_nonzero_p (@0))
- { build_zero_cst (type); }))
-
-/* (y << x) {<,<=} x -> 0 when y > 0. */
-(for cmp (lt le)
- (simplify
- (cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
- && tree_expr_nonzero_p (@0)
- && tree_expr_nonnegative_p (@0))
- { build_zero_cst (type); })))
-
-/* (y << x) != x -> 1 when y != 0. */
-(simplify
- (ne:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
+/* (y << x) == x -> false and (y << x) != x -> true when y != 0. */
+(for cmp (eq ne)
+ (simplify
+ (cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
&& tree_expr_nonzero_p (@0))
- { build_one_cst (type); }))
-
-/* (y << x) {>,>=} x -> 1 when y > 0. */
-(for cmp (gt ge)
- (simplify
- (cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
- && tree_expr_nonzero_p (@0)
- && tree_expr_nonnegative_p (@0))
- { build_one_cst (type); })))
+ { constant_boolean_node (cmp != EQ_EXPR, type); })))
/* Fold (1 << (C - x)) where C = precision(type) - 1
into ((1 << C) >> x). */
diff --git a/gcc/testsuite/gcc.dg/match-shift-cmp-1.c
b/gcc/testsuite/gcc.dg/match-shift-cmp-1.c
index b22d57d370f..7a69cd19437 100644
--- a/gcc/testsuite/gcc.dg/match-shift-cmp-1.c
+++ b/gcc/testsuite/gcc.dg/match-shift-cmp-1.c
@@ -34,17 +34,8 @@ typedef enum
TEST_OP_CST (eq, ==, 1)
TEST_OP_CST (ne, !=, 2)
-TEST_OP_CST (lt, <, 3)
-TEST_OP_CST (gt, >, 4)
-TEST_OP_CST (le, <=, 5)
-TEST_OP_CST (ge, >=, 6)
TEST_OP (eq, ==)
TEST_OP (ne, !=)
-TEST_OP (lt, <)
-TEST_OP (gt, >)
-TEST_OP (le, <=)
-TEST_OP (ge, >=)
-/* FIXME: The lt, le, gt and ge cases for int and enum don't get optimized. */
-/* { dg-final { scan-tree-dump-times "<<" 8 optimized } } */
+/* { dg-final { scan-tree-dump-not "<<" optimized } } */
diff --git a/gcc/testsuite/gcc.dg/match-shift-cmp-2.c
b/gcc/testsuite/gcc.dg/match-shift-cmp-2.c
index 96a2fd954f6..3d514ba1ee1 100644
--- a/gcc/testsuite/gcc.dg/match-shift-cmp-2.c
+++ b/gcc/testsuite/gcc.dg/match-shift-cmp-2.c
@@ -36,27 +36,12 @@ typedef enum
TEST_OP_CST (eq, ==, 0)
TEST_OP_CST (ne, !=, 0)
-TEST_OP_CST (lt, <, 0)
-TEST_OP_CST (gt, >, 0)
-TEST_OP_CST (le, <=, 0)
-TEST_OP_CST (ge, >=, 0)
TEST_OP (eq, ==)
TEST_OP (ne, !=)
-TEST_OP (lt, <)
-TEST_OP (gt, >)
-TEST_OP (le, <=)
-TEST_OP (ge, >=)
/* These end up getting folded by other patterns. */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) == 0" 8 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) != 0" 8 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) > 0" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) < 0" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) >= 0" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) <= 0" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "~x_\\d\\(D\\)" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "return x_\\d\\(D\\);" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "return 0;" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "return 1;" 4 optimized } } */
-/* Total: 48. */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) == 0" 6 optimized } } */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) != 0" 6 optimized } } */
+/* { dg-final { scan-tree-dump-times "~x_\\d\\(D\\)" 2 optimized } } */
+/* { dg-final { scan-tree-dump-times "return x_\\d\\(D\\);" 2 optimized } } */
diff --git a/gcc/testsuite/gcc.dg/match-shift-cmp-3.c
b/gcc/testsuite/gcc.dg/match-shift-cmp-3.c
index 34380cfeb96..e46ac30b905 100644
--- a/gcc/testsuite/gcc.dg/match-shift-cmp-3.c
+++ b/gcc/testsuite/gcc.dg/match-shift-cmp-3.c
@@ -1,25 +1,27 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
-/* The fold (y << x) <op> x -> 0|1 shouldn't trigger when y is negative or
- zero unsigned (except for == and !=). */
+/* The fold (y << x) <op> x -> 0|1 should trigger when y is negative
+ unsigned. */
#define TEST_ONE_CST(n, op, type, cst) \
- bool lshift_cst_##type##_##n (type x) { return ((cst << x) op x); }
+ bool lshift_cst_##type##_##n (type x) { return ((unsigned) (cst) << x) op x;
}
#define TEST_OP_CST(n, op, cst) \
+ TEST_ONE_CST (n, op, unsigned, cst)
\
TEST_ONE_CST (n, op, int, cst)
\
TEST_ONE_CST (n, op, test_enum, cst)
#define TEST_ONE(n, op, type) \
bool lshift_##type##_##n (type x, type y)
\
{
\
- if (y > 0)
\
+ if ((int) y <= 0)
\
__builtin_unreachable ();
\
- return ((y << x) op x);
\
+ return ((unsigned) (y) << x) op x;
\
}
#define TEST_OP(n, op) \
+ TEST_ONE (n, op, unsigned)
\
TEST_ONE (n, op, int)
\
TEST_ONE (n, op, test_enum)
@@ -31,14 +33,11 @@ typedef enum
TWO = 2
} test_enum;
-TEST_OP_CST (lt, <, -1)
-TEST_OP_CST (gt, >, -2)
-TEST_OP_CST (le, <=, -3)
-TEST_OP_CST (ge, >=, -4)
+TEST_OP_CST (eq, ==, -1)
+TEST_OP_CST (ne, !=, -2)
-TEST_OP (lt, <)
-TEST_OP (gt, >)
-TEST_OP (le, <=)
-TEST_OP (ge, >=)
+TEST_OP (eq, ==)
+TEST_OP (ne, !=)
-/* { dg-final { scan-tree-dump-times "<<" 16 optimized } } */
+/* { dg-final { scan-tree-dump-times "return 0;" 6 optimized } } */
+/* { dg-final { scan-tree-dump-times "return 1;" 6 optimized } } */
diff --git a/gcc/testsuite/gcc.dg/match-shift-cmp-4.c
b/gcc/testsuite/gcc.dg/match-shift-cmp-4.c
deleted file mode 100644
index 629e2a376d1..00000000000
--- a/gcc/testsuite/gcc.dg/match-shift-cmp-4.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-optimized" } */
-
-/* The fold (y << x) <op> x -> 0|1 should trigger when y is negative
- unsigned. */
-
-#define TEST_ONE_CST(n, op, type, cst)
\
- bool lshift_cst_##type##_##n (type x) { return ((unsigned) (cst) << x) op x;
}
-
-#define TEST_OP_CST(n, op, cst)
\
- TEST_ONE_CST (n, op, unsigned, cst)
\
- TEST_ONE_CST (n, op, int, cst)
\
- TEST_ONE_CST (n, op, test_enum, cst)
-
-#define TEST_ONE(n, op, type)
\
- bool lshift_##type##_##n (type x, type y)
\
- {
\
- if ((int) y <= 0)
\
- __builtin_unreachable ();
\
- return ((unsigned) (y) << x) op x;
\
- }
-
-#define TEST_OP(n, op)
\
- TEST_ONE (n, op, unsigned)
\
- TEST_ONE (n, op, int)
\
- TEST_ONE (n, op, test_enum)
-
-typedef enum
-{
- MONE = -1,
- ZERO = 0,
- ONE = 1,
- TWO = 2
-} test_enum;
-
-TEST_OP_CST (eq, ==, -1)
-TEST_OP_CST (ne, !=, -2)
-TEST_OP_CST (lt, <, -3)
-TEST_OP_CST (gt, >, -4)
-TEST_OP_CST (le, <=, -5)
-TEST_OP_CST (ge, >=, -6)
-
-TEST_OP (eq, ==)
-TEST_OP (ne, !=)
-TEST_OP (lt, <)
-TEST_OP (gt, >)
-TEST_OP (le, <=)
-TEST_OP (ge, >=)
-
-/* { dg-final { scan-tree-dump-times "return 0;" 18 optimized } } */
-/* { dg-final { scan-tree-dump-times "return 1;" 18 optimized } } */
--
2.44.0From 6a0f575f33410a2edd2b86387a764c1f750a10a1 Mon Sep 17 00:00:00 2001
From: Dhruv Chawla <[email protected]>
Date: Wed, 19 Nov 2025 04:55:08 -0800
Subject: [PATCH v4] PR tree-optimization/122733: Remove patterns for (y << x)
{<,<=,>,>=} x
These patterns should not be in match.pd as they require range
information checks that ideally belong in VRP. They were also causing
breakages as the checks weren't tight enough.
Bootstrapped and regtested on aarch64-linux-gnu.
Signed-off-by: Dhruv Chawla <[email protected]>
PR tree-optimization/122733
gcc/ChangeLog:
* match.pd ((y << x) {<,<=,>,>=} x): Remove.
((y << x) {==,!=} x): Call constant_boolean_node instead of
build_one_cst/build_zero_cst and combine into one pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/match-shift-cmp-1.c: Update test to only check
equality.
* gcc.dg/match-shift-cmp-2.c: Likewise.
* gcc.dg/match-shift-cmp-3.c: Likewise.
* gcc.dg/match-shift-cmp-4.c: Removed.
---
gcc/match.pd | 34 +++-------------
gcc/testsuite/gcc.dg/match-shift-cmp-1.c | 11 +----
gcc/testsuite/gcc.dg/match-shift-cmp-2.c | 23 ++---------
gcc/testsuite/gcc.dg/match-shift-cmp-3.c | 27 ++++++-------
gcc/testsuite/gcc.dg/match-shift-cmp-4.c | 51 ------------------------
5 files changed, 23 insertions(+), 123 deletions(-)
delete mode 100644 gcc/testsuite/gcc.dg/match-shift-cmp-4.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 63d56b08192..4e064e18570 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1339,37 +1339,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (INTEGRAL_TYPE_P (type))
(rshift (op @0 @2) @1))))
-/* (y << x) == x -> 0 when y != 0. */
-(simplify
- (eq:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
- && tree_expr_nonzero_p (@0))
- { build_zero_cst (type); }))
-
-/* (y << x) {<,<=} x -> 0 when y > 0. */
-(for cmp (lt le)
- (simplify
- (cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
- && tree_expr_nonzero_p (@0)
- && tree_expr_nonnegative_p (@0))
- { build_zero_cst (type); })))
-
-/* (y << x) != x -> 1 when y != 0. */
-(simplify
- (ne:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
+/* (y << x) == x -> false and (y << x) != x -> true when y != 0. */
+(for cmp (eq ne)
+ (simplify
+ (cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
(if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
&& tree_expr_nonzero_p (@0))
- { build_one_cst (type); }))
-
-/* (y << x) {>,>=} x -> 1 when y > 0. */
-(for cmp (gt ge)
- (simplify
- (cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
- && tree_expr_nonzero_p (@0)
- && tree_expr_nonnegative_p (@0))
- { build_one_cst (type); })))
+ { constant_boolean_node (cmp != EQ_EXPR, type); })))
/* Fold (1 << (C - x)) where C = precision(type) - 1
into ((1 << C) >> x). */
diff --git a/gcc/testsuite/gcc.dg/match-shift-cmp-1.c
b/gcc/testsuite/gcc.dg/match-shift-cmp-1.c
index b22d57d370f..7a69cd19437 100644
--- a/gcc/testsuite/gcc.dg/match-shift-cmp-1.c
+++ b/gcc/testsuite/gcc.dg/match-shift-cmp-1.c
@@ -34,17 +34,8 @@ typedef enum
TEST_OP_CST (eq, ==, 1)
TEST_OP_CST (ne, !=, 2)
-TEST_OP_CST (lt, <, 3)
-TEST_OP_CST (gt, >, 4)
-TEST_OP_CST (le, <=, 5)
-TEST_OP_CST (ge, >=, 6)
TEST_OP (eq, ==)
TEST_OP (ne, !=)
-TEST_OP (lt, <)
-TEST_OP (gt, >)
-TEST_OP (le, <=)
-TEST_OP (ge, >=)
-/* FIXME: The lt, le, gt and ge cases for int and enum don't get optimized. */
-/* { dg-final { scan-tree-dump-times "<<" 8 optimized } } */
+/* { dg-final { scan-tree-dump-not "<<" optimized } } */
diff --git a/gcc/testsuite/gcc.dg/match-shift-cmp-2.c
b/gcc/testsuite/gcc.dg/match-shift-cmp-2.c
index 96a2fd954f6..3d514ba1ee1 100644
--- a/gcc/testsuite/gcc.dg/match-shift-cmp-2.c
+++ b/gcc/testsuite/gcc.dg/match-shift-cmp-2.c
@@ -36,27 +36,12 @@ typedef enum
TEST_OP_CST (eq, ==, 0)
TEST_OP_CST (ne, !=, 0)
-TEST_OP_CST (lt, <, 0)
-TEST_OP_CST (gt, >, 0)
-TEST_OP_CST (le, <=, 0)
-TEST_OP_CST (ge, >=, 0)
TEST_OP (eq, ==)
TEST_OP (ne, !=)
-TEST_OP (lt, <)
-TEST_OP (gt, >)
-TEST_OP (le, <=)
-TEST_OP (ge, >=)
/* These end up getting folded by other patterns. */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) == 0" 8 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) != 0" 8 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) > 0" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) < 0" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) >= 0" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) <= 0" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "~x_\\d\\(D\\)" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "return x_\\d\\(D\\);" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "return 0;" 4 optimized } } */
-/* { dg-final { scan-tree-dump-times "return 1;" 4 optimized } } */
-/* Total: 48. */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) == 0" 6 optimized } } */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) != 0" 6 optimized } } */
+/* { dg-final { scan-tree-dump-times "~x_\\d\\(D\\)" 2 optimized } } */
+/* { dg-final { scan-tree-dump-times "return x_\\d\\(D\\);" 2 optimized } } */
diff --git a/gcc/testsuite/gcc.dg/match-shift-cmp-3.c
b/gcc/testsuite/gcc.dg/match-shift-cmp-3.c
index 34380cfeb96..e46ac30b905 100644
--- a/gcc/testsuite/gcc.dg/match-shift-cmp-3.c
+++ b/gcc/testsuite/gcc.dg/match-shift-cmp-3.c
@@ -1,25 +1,27 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
-/* The fold (y << x) <op> x -> 0|1 shouldn't trigger when y is negative or
- zero unsigned (except for == and !=). */
+/* The fold (y << x) <op> x -> 0|1 should trigger when y is negative
+ unsigned. */
#define TEST_ONE_CST(n, op, type, cst)
\
- bool lshift_cst_##type##_##n (type x) { return ((cst << x) op x); }
+ bool lshift_cst_##type##_##n (type x) { return ((unsigned) (cst) << x) op x;
}
#define TEST_OP_CST(n, op, cst)
\
+ TEST_ONE_CST (n, op, unsigned, cst)
\
TEST_ONE_CST (n, op, int, cst)
\
TEST_ONE_CST (n, op, test_enum, cst)
#define TEST_ONE(n, op, type)
\
bool lshift_##type##_##n (type x, type y)
\
{
\
- if (y > 0)
\
+ if ((int) y <= 0)
\
__builtin_unreachable ();
\
- return ((y << x) op x);
\
+ return ((unsigned) (y) << x) op x;
\
}
#define TEST_OP(n, op)
\
+ TEST_ONE (n, op, unsigned)
\
TEST_ONE (n, op, int)
\
TEST_ONE (n, op, test_enum)
@@ -31,14 +33,11 @@ typedef enum
TWO = 2
} test_enum;
-TEST_OP_CST (lt, <, -1)
-TEST_OP_CST (gt, >, -2)
-TEST_OP_CST (le, <=, -3)
-TEST_OP_CST (ge, >=, -4)
+TEST_OP_CST (eq, ==, -1)
+TEST_OP_CST (ne, !=, -2)
-TEST_OP (lt, <)
-TEST_OP (gt, >)
-TEST_OP (le, <=)
-TEST_OP (ge, >=)
+TEST_OP (eq, ==)
+TEST_OP (ne, !=)
-/* { dg-final { scan-tree-dump-times "<<" 16 optimized } } */
+/* { dg-final { scan-tree-dump-times "return 0;" 6 optimized } } */
+/* { dg-final { scan-tree-dump-times "return 1;" 6 optimized } } */
diff --git a/gcc/testsuite/gcc.dg/match-shift-cmp-4.c
b/gcc/testsuite/gcc.dg/match-shift-cmp-4.c
deleted file mode 100644
index 629e2a376d1..00000000000
--- a/gcc/testsuite/gcc.dg/match-shift-cmp-4.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-optimized" } */
-
-/* The fold (y << x) <op> x -> 0|1 should trigger when y is negative
- unsigned. */
-
-#define TEST_ONE_CST(n, op, type, cst)
\
- bool lshift_cst_##type##_##n (type x) { return ((unsigned) (cst) << x) op x;
}
-
-#define TEST_OP_CST(n, op, cst)
\
- TEST_ONE_CST (n, op, unsigned, cst)
\
- TEST_ONE_CST (n, op, int, cst)
\
- TEST_ONE_CST (n, op, test_enum, cst)
-
-#define TEST_ONE(n, op, type)
\
- bool lshift_##type##_##n (type x, type y)
\
- {
\
- if ((int) y <= 0)
\
- __builtin_unreachable ();
\
- return ((unsigned) (y) << x) op x;
\
- }
-
-#define TEST_OP(n, op)
\
- TEST_ONE (n, op, unsigned)
\
- TEST_ONE (n, op, int)
\
- TEST_ONE (n, op, test_enum)
-
-typedef enum
-{
- MONE = -1,
- ZERO = 0,
- ONE = 1,
- TWO = 2
-} test_enum;
-
-TEST_OP_CST (eq, ==, -1)
-TEST_OP_CST (ne, !=, -2)
-TEST_OP_CST (lt, <, -3)
-TEST_OP_CST (gt, >, -4)
-TEST_OP_CST (le, <=, -5)
-TEST_OP_CST (ge, >=, -6)
-
-TEST_OP (eq, ==)
-TEST_OP (ne, !=)
-TEST_OP (lt, <)
-TEST_OP (gt, >)
-TEST_OP (le, <=)
-TEST_OP (ge, >=)
-
-/* { dg-final { scan-tree-dump-times "return 0;" 18 optimized } } */
-/* { dg-final { scan-tree-dump-times "return 1;" 18 optimized } } */
--
2.44.0