aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2024-10-24 14:22:32 +0100
committerRichard Sandiford <richard.sandiford@arm.com>2024-10-24 14:22:32 +0100
commitec8e8d359690e7347e6e718cc9254d59f694e138 (patch)
tree2ec81774f84e64b934740c50ef74f46e6ecf34a6 /gcc/testsuite
parent8d01bc7dc453a44cd5b1913fb8a4104ee56fa410 (diff)
downloadgcc-ec8e8d359690e7347e6e718cc9254d59f694e138.zip
gcc-ec8e8d359690e7347e6e718cc9254d59f694e138.tar.gz
gcc-ec8e8d359690e7347e6e718cc9254d59f694e138.tar.bz2
Try to simplify (X >> C1) << (C1 + C2) -> X << C2
This patch adds a rule to simplify (X >> C1) << (C1 + C2) -> X << C2 when the low C1 bits of X are known to be zero. Any single conversion can take place between the shifts. E.g. for a truncating conversion, any extra bits of X that are preserved by truncating after the shift are immediately lost by the shift left. And the sign bits used for an extending conversion are the same as the sign bits used for the rshift. (A double conversion of say int->unsigned->uint64_t would be wrong though.) gcc/ * match.pd: Simplify (X >> C1) << (C1 + C2) -> X << C2 if the low C1 bits of X are zero. gcc/testsuite/ * gcc.dg/tree-ssa/shifts-1.c: New test. * gcc.dg/tree-ssa/shifts-2.c: Likewise.
Diffstat (limited to 'gcc/testsuite')
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/shifts-1.c61
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/shifts-2.c21
2 files changed, 82 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/shifts-1.c b/gcc/testsuite/gcc.dg/tree-ssa/shifts-1.c
new file mode 100644
index 0000000..d88500c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/shifts-1.c
@@ -0,0 +1,61 @@
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+unsigned int
+f1 (unsigned int x)
+{
+ if (x & 3)
+ __builtin_unreachable ();
+ x >>= 2;
+ return x << 3;
+}
+
+unsigned int
+f2 (unsigned int x)
+{
+ if (x & 3)
+ __builtin_unreachable ();
+ unsigned char y = x;
+ y >>= 2;
+ return y << 3;
+}
+
+unsigned long
+f3 (unsigned int x)
+{
+ if (x & 3)
+ __builtin_unreachable ();
+ x >>= 2;
+ return (unsigned long) x << 3;
+}
+
+int
+f4 (int x)
+{
+ if (x & 15)
+ __builtin_unreachable ();
+ x >>= 4;
+ return x << 5;
+}
+
+unsigned int
+f5 (int x)
+{
+ if (x & 31)
+ __builtin_unreachable ();
+ x >>= 5;
+ return x << 6;
+}
+
+unsigned int
+f6 (unsigned int x)
+{
+ if (x & 1)
+ __builtin_unreachable ();
+ x >>= 1;
+ return x << (sizeof (int) * __CHAR_BIT__ - 1);
+}
+
+/* { dg-final { scan-tree-dump-not {<[a-z]*_div_expr,} "optimized" } } */
+/* { dg-final { scan-tree-dump-not {<rshift_expr,} "optimized" } } */
+/* { dg-final { scan-tree-dump-times {<lshift_expr, [^,]*, [^,]*, 1,} 5 "optimized" } } */
+/* { dg-final { scan-tree-dump {<lshift_expr, [^,]*, [^,]*, 30,} "optimized" { target int32 } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/shifts-2.c b/gcc/testsuite/gcc.dg/tree-ssa/shifts-2.c
new file mode 100644
index 0000000..67ba4a7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/shifts-2.c
@@ -0,0 +1,21 @@
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+unsigned int
+f1 (unsigned int x)
+{
+ if (x & 3)
+ __builtin_unreachable ();
+ x >>= 3;
+ return x << 4;
+}
+
+unsigned int
+f2 (unsigned int x)
+{
+ if (x & 3)
+ __builtin_unreachable ();
+ x >>= 2;
+ return x << 1;
+}
+
+/* { dg-final { scan-tree-dump-times {<rshift_expr,} 2 "optimized" } } */