Hi!

The following patch canonicalizes M = X >> (prec - 1); (X + M) ^ M
for signed integral types into ABS_EXPR (X).  For X == min it is already
UB because M is -1 and min + -1 is UB, so we can use ABS_EXPR rather than
say ABSU_EXPR + cast.

The backend might then emit the abs code back using the shift and addition
and xor if it is the best sequence for the target, but could do something
different that is better.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2020-05-06  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/94783
        * match.pd ((X + (X >> (prec - 1))) ^ (X >> (prec - 1)) to abs (X)):
        New simplification.

        * gcc.dg/tree-ssa/pr94783.c: New test.

--- gcc/match.pd.jj     2020-05-06 15:48:23.658858289 +0200
+++ gcc/match.pd        2020-05-06 17:47:02.035347946 +0200
@@ -120,6 +120,18 @@ (define_operator_list COND_TERNARY
   (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
    (convert (absu:utype @0)))))
 
+#if GIMPLE
+/* Optimize (X + (X >> (prec - 1))) ^ (X >> (prec - 1)) into abs (X).  */
+(simplify
+ (bit_xor:c (plus:cs @0 (rshift@2 @0 INTEGER_CST@1)) @2)
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      && !TYPE_UNSIGNED (TREE_TYPE (@0))
+      && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+      && wi::to_widest (@1) == element_precision (TREE_TYPE (@0)) - 1
+      && TREE_CODE (@2) == SSA_NAME
+      && num_imm_uses (@2) == 2)
+  (abs @0)))
+#endif
 
 /* Simplifications of operations with one constant operand and
    simplifications to constants or single values.  */
--- gcc/testsuite/gcc.dg/tree-ssa/pr94783.c.jj  2020-05-06 17:52:35.515323297 
+0200
+++ gcc/testsuite/gcc.dg/tree-ssa/pr94783.c     2020-05-06 17:52:10.915693948 
+0200
@@ -0,0 +1,12 @@
+/* PR tree-optimization/94783 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump "ABS_EXPR" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " >> 31" "optimized" } } */
+
+int
+foo (int v)
+{
+  int mask = v >> (__SIZEOF_INT__ * __CHAR_BIT__ - 1);
+  return (v + mask) ^ mask;
+}

        Jakub

Reply via email to