re PR rtl-optimization/26026 (power of 2 mod missing optimisation)
authorAlan Modra <amodra@bigpond.net.au>
Tue, 18 Apr 2006 23:45:47 +0000 (23:45 +0000)
committerAlan Modra <amodra@gcc.gnu.org>
Tue, 18 Apr 2006 23:45:47 +0000 (09:15 +0930)
PR rtl-optimization/26026
* fold-const.c (fold_binary): Optimize div and mod where the divisor
is a known power of two shifted left a variable amount.

From-SVN: r113060

gcc/ChangeLog
gcc/fold-const.c

index e044e2b1b6a85b3434abbbb46b9053bff8150c61..f8968eaa2a10a9a0e4865b82a1715d8cdd213cf8 100644 (file)
@@ -1,3 +1,9 @@
+2006-04-19  Alan Modra  <amodra@bigpond.net.au>
+
+       PR rtl-optimization/26026
+       * fold-const.c (fold_binary): Optimize div and mod where the divisor
+       is a known power of two shifted left a variable amount.
+
 2006-04-18  Geoffrey Keating  <geoffk@apple.com>
 
        * dwarf2out.c (prune_unused_types_update_strings): Don't add strings
index deb568cd3af792b0274da5fc066d2003164402e6..39bd36689d5bab60a9d45d2e4bd0dc5cd445c18a 100644 (file)
@@ -9600,8 +9600,27 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       return NULL_TREE;
 
     case TRUNC_DIV_EXPR:
-    case ROUND_DIV_EXPR:
     case FLOOR_DIV_EXPR:
+      /* Simplify A / (B << N) where A and B are positive and B is
+        a power of 2, to A >> (N + log2(B)).  */
+      if (TREE_CODE (arg1) == LSHIFT_EXPR
+         && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0)))
+       {
+         tree sval = TREE_OPERAND (arg1, 0);
+         if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0)
+           {
+             tree sh_cnt = TREE_OPERAND (arg1, 1);
+             unsigned long pow2 = exact_log2 (TREE_INT_CST_LOW (sval));
+
+             sh_cnt = fold_build2 (PLUS_EXPR, TREE_TYPE (sh_cnt),
+                                   sh_cnt, build_int_cst (NULL_TREE, pow2));
+             return fold_build2 (RSHIFT_EXPR, type,
+                                 fold_convert (type, arg0), sh_cnt);
+           }
+       }
+      /* Fall thru */
+
+    case ROUND_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case EXACT_DIV_EXPR:
       if (integer_onep (arg1))
@@ -9671,31 +9690,24 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        return omit_one_operand (type, integer_zero_node, arg0);
 
       /* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR,
-         i.e. "X % C" into "X & C2", if X and C are positive.  */
+         i.e. "X % C" into "X & (C - 1)", if X and C are positive.  */
       if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR)
-         && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0))
-         && integer_pow2p (arg1) && tree_int_cst_sgn (arg1) >= 0)
+         && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0)))
        {
-         unsigned HOST_WIDE_INT high, low;
-         tree mask;
-         int l;
+         tree c = arg1;
+         /* Also optimize A % (C << N)  where C is a power of 2,
+            to A & ((C << N) - 1).  */
+         if (TREE_CODE (arg1) == LSHIFT_EXPR)
+           c = TREE_OPERAND (arg1, 0);
 
-         l = tree_log2 (arg1);
-         if (l >= HOST_BITS_PER_WIDE_INT)
-           {
-             high = ((unsigned HOST_WIDE_INT) 1
-                     << (l - HOST_BITS_PER_WIDE_INT)) - 1;
-             low = -1;
-           }
-         else
+         if (integer_pow2p (c) && tree_int_cst_sgn (c) > 0)
            {
-             high = 0;
-             low = ((unsigned HOST_WIDE_INT) 1 << l) - 1;
+             tree mask = fold_build2 (MINUS_EXPR, TREE_TYPE (arg1),
+                                      arg1, integer_one_node);
+             return fold_build2 (BIT_AND_EXPR, type,
+                                 fold_convert (type, arg0),
+                                 fold_convert (type, mask));
            }
-
-         mask = build_int_cst_wide (type, low, high);
-         return fold_build2 (BIT_AND_EXPR, type,
-                             fold_convert (type, arg0), mask);
        }
 
       /* X % -C is the same as X % C.  */