expmed.c (expand_mult): Use synthetic multiplication sequences for more classes of...
authorRoger Sayle <roger@eyesopen.com>
Sun, 13 Mar 2005 17:06:42 +0000 (17:06 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Sun, 13 Mar 2005 17:06:42 +0000 (17:06 +0000)
* expmed.c (expand_mult): Use synthetic multiplication sequences for
more classes of DImode multiplication by constant.  Allow both
multiplication by small negative constants (by performing a
multiplication by a positive constant and negating the result) and
multiplications by large powers of two, by using a left shift.

From-SVN: r96377

gcc/ChangeLog
gcc/expmed.c

index 1a9614f6334b897706c62463a54910f47952774e..f3a66255d94f82abbc086ffbeb04547bbd743367 100644 (file)
@@ -1,3 +1,11 @@
+2005-03-13  Roger Sayle  <roger@eyesopen.com>
+
+       * expmed.c (expand_mult): Use synthetic multiplication sequences for
+       more classes of DImode multiplication by constant.  Allow both
+       multiplication by small negative constants (by performing a 
+       multiplication by a positive constant and negating the result) and
+       multiplications by large powers of two, by using a left shift.
+
 2005-03-13  Kazu Hirata  <kazu@cs.umass.edu>
 
        * tree-into-ssa.c (find_idf): Speed up by putting the indexes
index afbbaf53869b38d42618e673fe1cb6064c0bd21e..093791e148a20214d602821596950b5729e7da9b 100644 (file)
@@ -3011,57 +3011,96 @@ rtx
 expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
             int unsignedp)
 {
-  rtx const_op1 = op1;
   enum mult_variant variant;
   struct algorithm algorithm;
+  int max_cost;
 
-  /* synth_mult does an `unsigned int' multiply.  As long as the mode is
-     less than or equal in size to `unsigned int' this doesn't matter.
-     If the mode is larger than `unsigned int', then synth_mult works only
-     if the constant value exactly fits in an `unsigned int' without any
-     truncation.  This means that multiplying by negative values does
-     not work; results are off by 2^32 on a 32 bit machine.  */
-
-  /* If we are multiplying in DImode, it may still be a win
-     to try to work with shifts and adds.  */
-  if (GET_CODE (op1) == CONST_DOUBLE
-      && GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT
-      && HOST_BITS_PER_INT >= BITS_PER_WORD
-      && CONST_DOUBLE_HIGH (op1) == 0)
-    const_op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
-  else if (HOST_BITS_PER_INT < GET_MODE_BITSIZE (mode)
-          && GET_CODE (op1) == CONST_INT
-          && INTVAL (op1) < 0)
-    const_op1 = 0;
-
-  /* We used to test optimize here, on the grounds that it's better to
-     produce a smaller program when -O is not used.
-     But this causes such a terrible slowdown sometimes
-     that it seems better to use synth_mult always.  */
-
-  if (const_op1 && GET_CODE (const_op1) == CONST_INT
+  /* Handling const0_rtx here allows us to use zero as a rogue value for
+     coeff below.  */
+  if (op1 == const0_rtx)
+    return const0_rtx;
+  if (op1 == const1_rtx)
+    return op0;
+  if (op1 == constm1_rtx)
+    return expand_unop (mode,
+                       GET_MODE_CLASS (mode) == MODE_INT
+                       && !unsignedp && flag_trapv
+                       ? negv_optab : neg_optab,
+                       op0, target, 0);
+
+  /* These are the operations that are potentially turned into a sequence
+     of shifts and additions.  */
+  if (GET_MODE_CLASS (mode) == MODE_INT
       && (unsignedp || !flag_trapv))
     {
-      HOST_WIDE_INT coeff = INTVAL (const_op1);
-      int mult_cost;
+      HOST_WIDE_INT coeff = 0;
 
-      /* Special case powers of two.  */
-      if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+      /* synth_mult does an `unsigned int' multiply.  As long as the mode is
+        less than or equal in size to `unsigned int' this doesn't matter.
+        If the mode is larger than `unsigned int', then synth_mult works
+        only if the constant value exactly fits in an `unsigned int' without
+        any truncation.  This means that multiplying by negative values does
+        not work; results are off by 2^32 on a 32 bit machine.  */
+
+      if (GET_CODE (op1) == CONST_INT)
        {
-         if (coeff == 0)
-           return const0_rtx;
-         if (coeff == 1)
-           return op0;
-         return expand_shift (LSHIFT_EXPR, mode, op0,
-                              build_int_cst (NULL_TREE, floor_log2 (coeff)),
-                              target, unsignedp);
+         /* Attempt to handle multiplication of DImode values by negative
+            coefficients, by performing the multiplication by a positive
+            multiplier and then inverting the result.  */
+         if (INTVAL (op1) < 0
+             && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
+           {
+             /* Its safe to use -INTVAL (op1) even for INT_MIN, as the
+                result is interpreted as an unsigned coefficient.  */
+             max_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET)
+                        - neg_cost[mode];
+             if (max_cost > 0
+                 && choose_mult_variant (mode, -INTVAL (op1), &algorithm,
+                                         &variant, max_cost))
+               {
+                 rtx temp = expand_mult_const (mode, op0, -INTVAL (op1),
+                                               NULL_RTX, &algorithm,
+                                               variant);
+                 return expand_unop (mode, neg_optab, temp, target, 0);
+               }
+           }
+         else coeff = INTVAL (op1);
+       }
+      else if (GET_CODE (op1) == CONST_DOUBLE)
+       {
+         /* If we are multiplying in DImode, it may still be a win
+            to try to work with shifts and adds.  */
+         if (CONST_DOUBLE_HIGH (op1) == 0)
+           coeff = CONST_DOUBLE_LOW (op1);
+         else if (CONST_DOUBLE_LOW (op1) == 0
+                  && EXACT_POWER_OF_2_OR_ZERO_P (CONST_DOUBLE_HIGH (op1)))
+           {
+             int shift = floor_log2 (CONST_DOUBLE_HIGH (op1))
+                         + HOST_BITS_PER_WIDE_INT;
+             return expand_shift (LSHIFT_EXPR, mode, op0,
+                                  build_int_cst (NULL_TREE, shift),
+                                  target, unsignedp);
+           }
+       }
+        
+      /* We used to test optimize here, on the grounds that it's better to
+        produce a smaller program when -O is not used.  But this causes
+        such a terrible slowdown sometimes that it seems better to always
+        use synth_mult.  */
+      if (coeff != 0)
+       {
+         /* Special case powers of two.  */
+         if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+           return expand_shift (LSHIFT_EXPR, mode, op0,
+                                build_int_cst (NULL_TREE, floor_log2 (coeff)),
+                                target, unsignedp);
+
+         max_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+         if (choose_mult_variant (mode, coeff, &algorithm, &variant,
+                                  max_cost))
+           return expand_mult_const (mode, op0, coeff, target,
+                                     &algorithm, variant);
        }
-
-      mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
-      if (choose_mult_variant (mode, coeff, &algorithm, &variant,
-                              mult_cost))
-       return expand_mult_const (mode, op0, coeff, target,
-                                 &algorithm, variant);
     }
 
   if (GET_CODE (op0) == CONST_DOUBLE)