aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAndrew Pinski <apinski@marvell.com>2023-07-23 21:44:39 +0000
committerAndrew Pinski <apinski@marvell.com>2023-08-01 00:06:14 +0000
commitcc2003cd87532f319c94028f17d20a327df5ccfa (patch)
tree6d20131ed1cef0c45a9a4f839ee8517a05a54ab6 /gcc
parenta349ba16f18b66b70c7a1bdb1ab5c5b6247676da (diff)
downloadgcc-cc2003cd87532f319c94028f17d20a327df5ccfa.zip
gcc-cc2003cd87532f319c94028f17d20a327df5ccfa.tar.gz
gcc-cc2003cd87532f319c94028f17d20a327df5ccfa.tar.bz2
Fix PR 93044: extra cast is not removed
In this case we are not removing convert to a bigger size back to the same size (or smaller) if signedness does not match. For an example: ``` signed char _1; ... _1 = *a_4(D); b_5 = (short unsigned int) _1; _2 = (unsigned char) b_5; ``` The inner cast is not needed and can be removed but was not. The match pattern for removing the extra cast is overly complex so decided to add a new case for rather than trying to modify the current if statement here. Committed as approved. Bootstrapped and tested on x86_64-linux-gnu with no regressions. gcc/ChangeLog: PR tree-optimization/93044 * match.pd (nested int casts): A truncation (to the same size or smaller) can always remove the inner cast. gcc/testsuite/ChangeLog: PR tree-optimization/93044 * gcc.dg/tree-ssa/cast-1.c: New test. * gcc.dg/tree-ssa/cast-2.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/match.pd10
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/cast-1.c12
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/cast-2.c12
3 files changed, 34 insertions, 0 deletions
diff --git a/gcc/match.pd b/gcc/match.pd
index 74f0a84..cfd6ea0 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4340,6 +4340,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
&& ! (final_ptr && inside_prec != inter_prec))
(ocvt @0))
+ /* `(outer:M)(inter:N) a:O`
+ can be converted to `(outer:M) a`
+ if M <= O && N >= O. No matter what signedness of the casts,
+ as the final is either a truncation from the original or just
+ a sign change of the type. */
+ (if (inside_int && inter_int && final_int
+ && final_prec <= inside_prec
+ && inter_prec >= inside_prec)
+ (convert @0))
+
/* A truncation to an unsigned type (a zero-extension) should be
canonicalized as bitwise and of a mask. */
(if (GIMPLE /* PR70366: doing this in GENERIC breaks -Wconversion. */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cast-1.c b/gcc/testsuite/gcc.dg/tree-ssa/cast-1.c
new file mode 100644
index 0000000..0f33ab5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cast-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+
+void f(signed char *a, unsigned char *c)
+{
+ unsigned short b = *a;
+ *c = ((unsigned char)b);
+}
+
+
+/* { dg-final { scan-tree-dump-not "\\(short unsigned int\\)" "optimized"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cast-2.c b/gcc/testsuite/gcc.dg/tree-ssa/cast-2.c
new file mode 100644
index 0000000..d665e92
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cast-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+
+void f(signed short *a, unsigned char *c)
+{
+ unsigned long b = *a;
+ *c = ((unsigned char)b);
+}
+
+
+/* { dg-final { scan-tree-dump-not "\\(long unsigned int\\)" "optimized"} } */