I am testing the following patch to fix the regression in min/max
detection introduced by comparison canonicalization like a < 267
to a <= 266.  The patch allows us to identify all four min/max
cases in the testcase below.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

Richard.

2016-03-14  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/56365
        * tree-ssa-phiopt.c (minmax_replacement): Handle alternate
        constants to compare against.

        * gcc.dg/tree-ssa/phi-opt-14.c: New testcase.

Index: gcc/tree-ssa-phiopt.c
===================================================================
*** gcc/tree-ssa-phiopt.c       (revision 234180)
--- gcc/tree-ssa-phiopt.c       (working copy)
*************** minmax_replacement (basic_block cond_bb,
*** 1045,1051 ****
    gassign *new_stmt;
    edge true_edge, false_edge;
    enum tree_code cmp, minmax, ass_code;
!   tree smaller, larger, arg_true, arg_false;
    gimple_stmt_iterator gsi, gsi_from;
  
    type = TREE_TYPE (PHI_RESULT (phi));
--- 1045,1051 ----
    gassign *new_stmt;
    edge true_edge, false_edge;
    enum tree_code cmp, minmax, ass_code;
!   tree smaller, alt_smaller, larger, alt_larger, arg_true, arg_false;
    gimple_stmt_iterator gsi, gsi_from;
  
    type = TREE_TYPE (PHI_RESULT (phi));
*************** minmax_replacement (basic_block cond_bb,
*** 1059,1073 ****
--- 1059,1117 ----
  
    /* This transformation is only valid for order comparisons.  Record which
       operand is smaller/larger if the result of the comparison is true.  */
+   alt_smaller = NULL_TREE;
+   alt_larger = NULL_TREE;
    if (cmp == LT_EXPR || cmp == LE_EXPR)
      {
        smaller = gimple_cond_lhs (cond);
        larger = gimple_cond_rhs (cond);
+       /* If we have smaller < CST it is equivalent to smaller <= CST-1.
+        Likewise smaller <= CST is equivalent to smaller < CST+1.  */
+       if (TREE_CODE (larger) == INTEGER_CST)
+       {
+         if (cmp == LT_EXPR)
+           {
+             bool overflow;
+             wide_int alt = wi::sub (larger, 1, TYPE_SIGN (TREE_TYPE (larger)),
+                                     &overflow);
+             if (! overflow)
+               alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt);
+           }
+         else
+           {
+             bool overflow;
+             wide_int alt = wi::add (larger, 1, TYPE_SIGN (TREE_TYPE (larger)),
+                                     &overflow);
+             if (! overflow)
+               alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt);
+           }
+       }
      }
    else if (cmp == GT_EXPR || cmp == GE_EXPR)
      {
        smaller = gimple_cond_rhs (cond);
        larger = gimple_cond_lhs (cond);
+       /* If we have larger > CST it is equivalent to larger >= CST+1.
+        Likewise larger >= CST is equivalent to larger > CST-1.  */
+       if (TREE_CODE (smaller) == INTEGER_CST)
+       {
+         if (cmp == GT_EXPR)
+           {
+             bool overflow;
+             wide_int alt = wi::add (smaller, 1, TYPE_SIGN (TREE_TYPE 
(smaller)),
+                                     &overflow);
+             if (! overflow)
+               alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt);
+           }
+         else
+           {
+             bool overflow;
+             wide_int alt = wi::sub (smaller, 1, TYPE_SIGN (TREE_TYPE 
(smaller)),
+                                     &overflow);
+             if (! overflow)
+               alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt);
+           }
+       }
      }
    else
      return false;
*************** minmax_replacement (basic_block cond_bb,
*** 1098,1105 ****
  
    if (empty_block_p (middle_bb))
      {
!       if (operand_equal_for_phi_arg_p (arg_true, smaller)
!         && operand_equal_for_phi_arg_p (arg_false, larger))
        {
          /* Case
  
--- 1142,1153 ----
  
    if (empty_block_p (middle_bb))
      {
!       if ((operand_equal_for_phi_arg_p (arg_true, smaller)
!          || (alt_smaller
!              && operand_equal_for_phi_arg_p (arg_true, alt_smaller)))
!         && (operand_equal_for_phi_arg_p (arg_false, larger)
!             || (alt_larger
!                 && operand_equal_for_phi_arg_p (arg_true, alt_larger))))
        {
          /* Case
  
*************** minmax_replacement (basic_block cond_bb,
*** 1109,1116 ****
             rslt = larger;  */
          minmax = MIN_EXPR;
        }
!       else if (operand_equal_for_phi_arg_p (arg_false, smaller)
!              && operand_equal_for_phi_arg_p (arg_true, larger))
        minmax = MAX_EXPR;
        else
        return false;
--- 1157,1168 ----
             rslt = larger;  */
          minmax = MIN_EXPR;
        }
!       else if ((operand_equal_for_phi_arg_p (arg_false, smaller)
!               || (alt_smaller
!                   && operand_equal_for_phi_arg_p (arg_false, alt_smaller)))
!              && (operand_equal_for_phi_arg_p (arg_true, larger)
!                  || (alt_larger
!                      && operand_equal_for_phi_arg_p (arg_true, alt_larger))))
        minmax = MAX_EXPR;
        else
        return false;
*************** minmax_replacement (basic_block cond_bb,
*** 1148,1154 ****
          if (!operand_equal_for_phi_arg_p (lhs, arg_true))
            return false;
  
!         if (operand_equal_for_phi_arg_p (arg_false, larger))
            {
              /* Case
  
--- 1200,1208 ----
          if (!operand_equal_for_phi_arg_p (lhs, arg_true))
            return false;
  
!         if (operand_equal_for_phi_arg_p (arg_false, larger)
!             || (alt_larger
!                 && operand_equal_for_phi_arg_p (arg_false, alt_larger)))
            {
              /* Case
  
*************** minmax_replacement (basic_block cond_bb,
*** 1161,1169 ****
                return false;
  
              minmax = MIN_EXPR;
!             if (operand_equal_for_phi_arg_p (op0, smaller))
                bound = op1;
!             else if (operand_equal_for_phi_arg_p (op1, smaller))
                bound = op0;
              else
                return false;
--- 1215,1227 ----
                return false;
  
              minmax = MIN_EXPR;
!             if (operand_equal_for_phi_arg_p (op0, smaller)
!                 || (alt_smaller
!                     && operand_equal_for_phi_arg_p (op0, alt_smaller)))
                bound = op1;
!             else if (operand_equal_for_phi_arg_p (op1, smaller)
!                      || (alt_smaller
!                          && operand_equal_for_phi_arg_p (op1, alt_smaller)))
                bound = op0;
              else
                return false;
*************** minmax_replacement (basic_block cond_bb,
*** 1173,1179 ****
                                                  bound, larger)))
                return false;
            }
!         else if (operand_equal_for_phi_arg_p (arg_false, smaller))
            {
              /* Case
  
--- 1231,1239 ----
                                                  bound, larger)))
                return false;
            }
!         else if (operand_equal_for_phi_arg_p (arg_false, smaller)
!                  || (alt_smaller
!                      && operand_equal_for_phi_arg_p (arg_false, alt_smaller)))
            {
              /* Case
  
*************** minmax_replacement (basic_block cond_bb,
*** 1186,1194 ****
                return false;
  
              minmax = MAX_EXPR;
!             if (operand_equal_for_phi_arg_p (op0, larger))
                bound = op1;
!             else if (operand_equal_for_phi_arg_p (op1, larger))
                bound = op0;
              else
                return false;
--- 1246,1258 ----
                return false;
  
              minmax = MAX_EXPR;
!             if (operand_equal_for_phi_arg_p (op0, larger)
!                 || (alt_larger
!                     && operand_equal_for_phi_arg_p (op0, alt_larger)))
                bound = op1;
!             else if (operand_equal_for_phi_arg_p (op1, larger)
!                      || (alt_larger
!                          && operand_equal_for_phi_arg_p (op1, alt_larger)))
                bound = op0;
              else
                return false;
*************** minmax_replacement (basic_block cond_bb,
*** 1207,1213 ****
          if (!operand_equal_for_phi_arg_p (lhs, arg_false))
            return false;
  
!         if (operand_equal_for_phi_arg_p (arg_true, larger))
            {
              /* Case
  
--- 1271,1279 ----
          if (!operand_equal_for_phi_arg_p (lhs, arg_false))
            return false;
  
!         if (operand_equal_for_phi_arg_p (arg_true, larger)
!             || (alt_larger
!                 && operand_equal_for_phi_arg_p (arg_true, alt_larger)))
            {
              /* Case
  
*************** minmax_replacement (basic_block cond_bb,
*** 1220,1228 ****
                return false;
  
              minmax = MAX_EXPR;
!             if (operand_equal_for_phi_arg_p (op0, smaller))
                bound = op1;
!             else if (operand_equal_for_phi_arg_p (op1, smaller))
                bound = op0;
              else
                return false;
--- 1286,1298 ----
                return false;
  
              minmax = MAX_EXPR;
!             if (operand_equal_for_phi_arg_p (op0, smaller)
!                 || (alt_smaller
!                     && operand_equal_for_phi_arg_p (op0, alt_smaller)))
                bound = op1;
!             else if (operand_equal_for_phi_arg_p (op1, smaller)
!                      || (alt_smaller
!                          && operand_equal_for_phi_arg_p (op1, alt_smaller)))
                bound = op0;
              else
                return false;
*************** minmax_replacement (basic_block cond_bb,
*** 1232,1238 ****
                                                  bound, larger)))
                return false;
            }
!         else if (operand_equal_for_phi_arg_p (arg_true, smaller))
            {
              /* Case
  
--- 1302,1310 ----
                                                  bound, larger)))
                return false;
            }
!         else if (operand_equal_for_phi_arg_p (arg_true, smaller)
!                  || (alt_smaller
!                      && operand_equal_for_phi_arg_p (arg_true, alt_smaller)))
            {
              /* Case
  
Index: gcc/testsuite/gcc.dg/tree-ssa/phi-opt-14.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/phi-opt-14.c  (revision 0)
--- gcc/testsuite/gcc.dg/tree-ssa/phi-opt-14.c  (working copy)
***************
*** 0 ****
--- 1,37 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O -fdump-tree-phiopt1" } */
+ 
+ int test_01 (int a)
+ {
+   if (127 <= a)
+     a = 127;
+   else if (a <= -128)
+     a = -128;
+   return a;
+ }
+ int test_02 (int a)
+ {
+   if (127 < a)
+     a = 127;
+   else if (a <= -128)
+     a = -128;
+   return a;
+ }
+ int test_03 (int a)
+ {
+   if (127 <= a)
+     a = 127;
+   else if (a < -128)
+     a = -128;
+   return a;
+ }
+ int test_04 (int a)
+ {
+   if (127 < a)
+     a = 127;
+   else if (a < -128)
+     a = -128;
+   return a;
+ }
+ 
+ /* { dg-final { scan-tree-dump-not "if" "phiopt1" } } */

Reply via email to