re PR rtl-optimization/20532 (Bad code for DImode left shifts by 31 and then 1)
authorAlexandre Oliva <aoliva@redhat.com>
Thu, 24 Mar 2005 05:57:52 +0000 (05:57 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Thu, 24 Mar 2005 05:57:52 +0000 (05:57 +0000)
gcc/ChangeLog:
PR rtl-optimization/20532
* simplify-rtx.c (simplify_binary_operation_1): Protect from
overflow when adding coefficients for PLUS or MINUS.
(simplify_binary_operation_1): Handle CONST_DOUBLE exact power of
two as multiplier.
gcc/testsuite/ChangeLog:
PR rtl-optimization/20532
* gcc.target/i386/badshift.c: New.

From-SVN: r96982

gcc/ChangeLog
gcc/simplify-rtx.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/badshift.c [new file with mode: 0644]

index 081b91a62d7988aad42158b88e78b4cbdc55d972..933e4e446eb8400fb3e1400df2429639c5f42bff 100644 (file)
@@ -1,3 +1,11 @@
+2005-03-24  Alexandre Oliva  <aoliva@redhat.com>
+
+       PR rtl-optimization/20532
+       * simplify-rtx.c (simplify_binary_operation_1): Protect from
+       overflow when adding coefficients for PLUS or MINUS.
+       (simplify_binary_operation_1): Handle CONST_DOUBLE exact power of
+       two as multiplier.
+
 2005-03-23  Joseph S. Myers  <joseph@codesourcery.com>
 
        * langhooks.h (truthvalue_conversion): Remove.
index a7033315e98fedca52970558c7b3f8d54c2519e0..865d6f933bb398c8c24a6f45fc4350671e026eac 100644 (file)
@@ -1257,44 +1257,67 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (! FLOAT_MODE_P (mode))
        {
-         HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
+         HOST_WIDE_INT coeff0h = 0, coeff1h = 0;
+         unsigned HOST_WIDE_INT coeff0l = 1, coeff1l = 1;
          rtx lhs = op0, rhs = op1;
 
          if (GET_CODE (lhs) == NEG)
-           coeff0 = -1, lhs = XEXP (lhs, 0);
+           {
+             coeff0l = -1;
+             coeff0h = -1;
+             lhs = XEXP (lhs, 0);
+           }
          else if (GET_CODE (lhs) == MULT
                   && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
-           coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
+           {
+             coeff0l = INTVAL (XEXP (lhs, 1));
+             coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
+             lhs = XEXP (lhs, 0);
+           }
          else if (GET_CODE (lhs) == ASHIFT
                   && GET_CODE (XEXP (lhs, 1)) == CONST_INT
                   && INTVAL (XEXP (lhs, 1)) >= 0
                   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+             coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+             coeff0h = 0;
              lhs = XEXP (lhs, 0);
            }
 
          if (GET_CODE (rhs) == NEG)
-           coeff1 = -1, rhs = XEXP (rhs, 0);
+           {
+             coeff1l = -1;
+             coeff1h = -1;
+             rhs = XEXP (rhs, 0);
+           }
          else if (GET_CODE (rhs) == MULT
                   && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
            {
-             coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
+             coeff1l = INTVAL (XEXP (rhs, 1));
+             coeff1h = INTVAL (XEXP (rhs, 1)) < 0 ? -1 : 0;
+             rhs = XEXP (rhs, 0);
            }
          else if (GET_CODE (rhs) == ASHIFT
                   && GET_CODE (XEXP (rhs, 1)) == CONST_INT
                   && INTVAL (XEXP (rhs, 1)) >= 0
                   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+             coeff1l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+             coeff1h = 0;
              rhs = XEXP (rhs, 0);
            }
 
          if (rtx_equal_p (lhs, rhs))
            {
              rtx orig = gen_rtx_PLUS (mode, op0, op1);
-             tem = simplify_gen_binary (MULT, mode, lhs,
-                                        GEN_INT (coeff0 + coeff1));
+             rtx coeff;
+             unsigned HOST_WIDE_INT l;
+             HOST_WIDE_INT h;
+
+             add_double (coeff0l, coeff0h, coeff1l, coeff1h, &l, &h);
+             coeff = immed_double_const (l, h, mode);
+
+             tem = simplify_gen_binary (MULT, mode, lhs, coeff);
              return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
                ? tem : 0;
            }
@@ -1405,46 +1428,67 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (! FLOAT_MODE_P (mode))
        {
-         HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
+         HOST_WIDE_INT coeff0h = 0, negcoeff1h = -1;
+         unsigned HOST_WIDE_INT coeff0l = 1, negcoeff1l = -1;
          rtx lhs = op0, rhs = op1;
 
          if (GET_CODE (lhs) == NEG)
-           coeff0 = -1, lhs = XEXP (lhs, 0);
+           {
+             coeff0l = -1;
+             coeff0h = -1;
+             lhs = XEXP (lhs, 0);
+           }
          else if (GET_CODE (lhs) == MULT
                   && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
            {
-             coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
+             coeff0l = INTVAL (XEXP (lhs, 1));
+             coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
+             lhs = XEXP (lhs, 0);
            }
          else if (GET_CODE (lhs) == ASHIFT
                   && GET_CODE (XEXP (lhs, 1)) == CONST_INT
                   && INTVAL (XEXP (lhs, 1)) >= 0
                   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+             coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+             coeff0h = 0;
              lhs = XEXP (lhs, 0);
            }
 
          if (GET_CODE (rhs) == NEG)
-           coeff1 = - 1, rhs = XEXP (rhs, 0);
+           {
+             negcoeff1l = 1;
+             negcoeff1h = 0;
+             rhs = XEXP (rhs, 0);
+           }
          else if (GET_CODE (rhs) == MULT
                   && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
            {
-             coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
+             negcoeff1l = -INTVAL (XEXP (rhs, 1));
+             negcoeff1h = INTVAL (XEXP (rhs, 1)) <= 0 ? 0 : -1;
+             rhs = XEXP (rhs, 0);
            }
          else if (GET_CODE (rhs) == ASHIFT
                   && GET_CODE (XEXP (rhs, 1)) == CONST_INT
                   && INTVAL (XEXP (rhs, 1)) >= 0
                   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
            {
-             coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+             negcoeff1l = -(((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1)));
+             negcoeff1h = -1;
              rhs = XEXP (rhs, 0);
            }
 
          if (rtx_equal_p (lhs, rhs))
            {
              rtx orig = gen_rtx_MINUS (mode, op0, op1);
-             tem = simplify_gen_binary (MULT, mode, lhs,
-                                        GEN_INT (coeff0 - coeff1));
+             rtx coeff;
+             unsigned HOST_WIDE_INT l;
+             HOST_WIDE_INT h;
+
+             add_double (coeff0l, coeff0h, negcoeff1l, negcoeff1h, &l, &h);
+             coeff = immed_double_const (l, h, mode);
+
+             tem = simplify_gen_binary (MULT, mode, lhs, coeff);
              return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
                ? tem : 0;
            }
@@ -1531,6 +1575,16 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
              || val != HOST_BITS_PER_WIDE_INT - 1))
        return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
 
+      /* Likewise for multipliers wider than a word.  */
+      else if (GET_CODE (trueop1) == CONST_DOUBLE
+              && (GET_MODE (trueop1) == VOIDmode
+                  || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
+              && GET_MODE (op0) == mode
+              && CONST_DOUBLE_LOW (trueop1) == 0
+              && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
+       return simplify_gen_binary (ASHIFT, mode, op0,
+                                   GEN_INT (val + HOST_BITS_PER_WIDE_INT));
+
       /* x*2 is x+x and x*(-1) is -x */
       if (GET_CODE (trueop1) == CONST_DOUBLE
          && GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT
index 465d516f451361ff05181ecc929eba865a73483b..41fd479b52d209e5703a5f1bee1c4a5137eb3c5c 100644 (file)
@@ -1,3 +1,8 @@
+2005-03-24  Alexandre Oliva  <aoliva@redhat.com>
+
+       PR rtl-optimization/20532
+       * gcc.target/i386/badshift.c: New.
+
 2005-03-23  Francois-Xavier Coudert  <coudert@clipper.ens.fr>
 
        * pr18025.f90: New test.
diff --git a/gcc/testsuite/gcc.target/i386/badshift.c b/gcc/testsuite/gcc.target/i386/badshift.c
new file mode 100644 (file)
index 0000000..ddbf613
--- /dev/null
@@ -0,0 +1,28 @@
+/* PR rtl-optimization/20532 */
+
+/* { dg-do run } */
+/* { dg-options "-m32 -march=i386 -O1" } */
+
+/* We used to optimize the DImode shift-by-32 to zero because in combine
+   we turned:
+
+     (v << 31) * (v << 31)
+
+   into:
+
+     (v * (((HOST_WIDE_INT)1 << 31) + ((HOST_WIDE_INT)1 << 31)))
+
+   With a 32-bit HOST_WIDE_INT, the coefficient overflowed to zero.  */
+
+unsigned long long int badshift(unsigned long long int v)
+{
+        return v << 31 << 1;
+}
+
+extern void abort ();
+
+int main() {
+  if (badshift (1) == 0)
+    abort ();
+  return 0;
+}