[43/77] Use scalar_int_mode in simplify_comparison
authorRichard Sandiford <richard.sandiford@linaro.org>
Wed, 30 Aug 2017 11:15:46 +0000 (11:15 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 30 Aug 2017 11:15:46 +0000 (11:15 +0000)
The main loop of simplify_comparison starts with:

      if (GET_MODE_CLASS (mode) != MODE_INT
          && ! (mode == VOIDmode
                && (GET_CODE (op0) == COMPARE || COMPARISON_P (op0))))
        break;

So VOIDmode is only acceptable when comparing a COMPARE,
EQ, NE, etc. operand against a constant.  After this, the loop
calls simplify_compare_const to:

  (a) bring the constant op1 closer to 0 where possible and
  (b) use nonzero_bits and num_sign_bit_copies to get a simpler
      constant.

(a) works for both integer and VOID modes, (b) is specific
to integer modes.

The loop then has a big switch statement that handles further
simplifications.  This switch statement checks for COMPARISON_P
codes but not for COMPARE.

This patch uses scalar_int_mode to make the split between
(a) and (b) more explicit.  It also takes the COMPARISON_P
handling out of the switch statement and does it first,
so that the rest of the loop can treat the mode as a
scalar_int_mode.

2017-08-30  Richard Sandiford  <richard.sandiford@linaro.org>
    Alan Hayward  <alan.hayward@arm.com>
    David Sherwood  <david.sherwood@arm.com>

gcc/
* combine.c (simplify_compare_const): Check that the mode is a
scalar_int_mode (rather than VOIDmode) before testing its
precision.
(simplify_comparison): Move COMPARISON_P handling out of the
loop and restrict the latter part of the loop to scalar_int_modes.
Check is_a <scalar_int_mode> before calling HWI_COMPUTABLE_MODE_P
and when considering SUBREG_REGs.  Use is_int_mode instead of
checking GET_MODE_CLASS against MODE_INT.

Co-Authored-By: Alan Hayward <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>
From-SVN: r251495

gcc/ChangeLog
gcc/combine.c

index fb28c99..5449fa1 100644 (file)
@@ -2,6 +2,19 @@
            Alan Hayward  <alan.hayward@arm.com>
            David Sherwood  <david.sherwood@arm.com>
 
+       * combine.c (simplify_compare_const): Check that the mode is a
+       scalar_int_mode (rather than VOIDmode) before testing its
+       precision.
+       (simplify_comparison): Move COMPARISON_P handling out of the
+       loop and restrict the latter part of the loop to scalar_int_modes.
+       Check is_a <scalar_int_mode> before calling HWI_COMPUTABLE_MODE_P
+       and when considering SUBREG_REGs.  Use is_int_mode instead of
+       checking GET_MODE_CLASS against MODE_INT.
+
+2017-08-30  Richard Sandiford  <richard.sandiford@linaro.org>
+           Alan Hayward  <alan.hayward@arm.com>
+           David Sherwood  <david.sherwood@arm.com>
+
        * combine.c (try_widen_shift_mode): Move check for equal modes to...
        (simplify_shift_const_1): ...here.  Use scalar_int_mode for
        shift_unit_mode and for modes involved in scalar shifts.
index 2e0e67b..2fbfed4 100644 (file)
@@ -11640,7 +11640,7 @@ static enum rtx_code
 simplify_compare_const (enum rtx_code code, machine_mode mode,
                        rtx op0, rtx *pop1)
 {
-  unsigned int mode_width = GET_MODE_PRECISION (mode);
+  scalar_int_mode int_mode;
   HOST_WIDE_INT const_op = INTVAL (*pop1);
 
   /* Get the constant we are comparing against and turn off all bits
@@ -11655,10 +11655,11 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
   if (const_op
       && (code == EQ || code == NE || code == GE || code == GEU
          || code == LT || code == LTU)
-      && mode_width - 1 < HOST_BITS_PER_WIDE_INT
-      && pow2p_hwi (const_op & GET_MODE_MASK (mode))
-      && (nonzero_bits (op0, mode)
-         == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (mode))))
+      && is_a <scalar_int_mode> (mode, &int_mode)
+      && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+      && pow2p_hwi (const_op & GET_MODE_MASK (int_mode))
+      && (nonzero_bits (op0, int_mode)
+         == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (int_mode))))
     {
       code = (code == EQ || code == GE || code == GEU ? NE : EQ);
       const_op = 0;
@@ -11669,7 +11670,8 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
   if (const_op == -1
       && (code == EQ || code == NE || code == GT || code == LE
          || code == GEU || code == LTU)
-      && num_sign_bit_copies (op0, mode) == mode_width)
+      && is_a <scalar_int_mode> (mode, &int_mode)
+      && num_sign_bit_copies (op0, int_mode) == GET_MODE_PRECISION (int_mode))
     {
       code = (code == EQ || code == LE || code == GEU ? NE : EQ);
       const_op = 0;
@@ -11703,9 +11705,10 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
       /* If we are doing a <= 0 comparison on a value known to have
         a zero sign bit, we can replace this with == 0.  */
       else if (const_op == 0
-              && mode_width - 1 < HOST_BITS_PER_WIDE_INT
-              && (nonzero_bits (op0, mode)
-                  & (HOST_WIDE_INT_1U << (mode_width - 1)))
+              && is_a <scalar_int_mode> (mode, &int_mode)
+              && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+              && (nonzero_bits (op0, int_mode)
+                  & (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
               == 0)
        code = EQ;
       break;
@@ -11733,9 +11736,10 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
       /* If we are doing a > 0 comparison on a value known to have
         a zero sign bit, we can replace this with != 0.  */
       else if (const_op == 0
-              && mode_width - 1 < HOST_BITS_PER_WIDE_INT
-              && (nonzero_bits (op0, mode)
-                  & (HOST_WIDE_INT_1U << (mode_width - 1)))
+              && is_a <scalar_int_mode> (mode, &int_mode)
+              && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+              && (nonzero_bits (op0, int_mode)
+                  & (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
               == 0)
        code = NE;
       break;
@@ -11749,9 +11753,10 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
          /* ... fall through ...  */
        }
       /* (unsigned) < 0x80000000 is equivalent to >= 0.  */
-      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
-              && (unsigned HOST_WIDE_INT) const_op
-              == HOST_WIDE_INT_1U << (mode_width - 1))
+      else if (is_a <scalar_int_mode> (mode, &int_mode)
+              && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+              && ((unsigned HOST_WIDE_INT) const_op
+                  == HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
        {
          const_op = 0;
          code = GE;
@@ -11765,9 +11770,11 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
       if (const_op == 0)
        code = EQ;
       /* (unsigned) <= 0x7fffffff is equivalent to >= 0.  */
-      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
-              && (unsigned HOST_WIDE_INT) const_op
-              == (HOST_WIDE_INT_1U << (mode_width - 1)) - 1)
+      else if (is_a <scalar_int_mode> (mode, &int_mode)
+              && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+              && ((unsigned HOST_WIDE_INT) const_op
+                  == ((HOST_WIDE_INT_1U
+                       << (GET_MODE_PRECISION (int_mode) - 1)) - 1)))
        {
          const_op = 0;
          code = GE;
@@ -11784,9 +11791,10 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
        }
 
       /* (unsigned) >= 0x80000000 is equivalent to < 0.  */
-      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
-              && (unsigned HOST_WIDE_INT) const_op
-              == HOST_WIDE_INT_1U << (mode_width - 1))
+      else if (is_a <scalar_int_mode> (mode, &int_mode)
+              && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+              && ((unsigned HOST_WIDE_INT) const_op
+                  == HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
        {
          const_op = 0;
          code = LT;
@@ -11800,9 +11808,11 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
       if (const_op == 0)
        code = NE;
       /* (unsigned) > 0x7fffffff is equivalent to < 0.  */
-      else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
-              && (unsigned HOST_WIDE_INT) const_op
-              == (HOST_WIDE_INT_1U << (mode_width - 1)) - 1)
+      else if (is_a <scalar_int_mode> (mode, &int_mode)
+              && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+              && ((unsigned HOST_WIDE_INT) const_op
+                  == (HOST_WIDE_INT_1U
+                      << (GET_MODE_PRECISION (int_mode) - 1)) - 1))
        {
          const_op = 0;
          code = LT;
@@ -11987,9 +11997,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
 
   while (CONST_INT_P (op1))
     {
-      machine_mode mode = GET_MODE (op0);
-      unsigned int mode_width = GET_MODE_PRECISION (mode);
-      unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
+      machine_mode raw_mode = GET_MODE (op0);
+      scalar_int_mode int_mode;
       int equality_comparison_p;
       int sign_bit_comparison_p;
       int unsigned_comparison_p;
@@ -12000,14 +12009,14 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
         can handle VOIDmode if OP0 is a COMPARE or a comparison
         operation.  */
 
-      if (GET_MODE_CLASS (mode) != MODE_INT
-         && ! (mode == VOIDmode
+      if (GET_MODE_CLASS (raw_mode) != MODE_INT
+         && ! (raw_mode == VOIDmode
                && (GET_CODE (op0) == COMPARE || COMPARISON_P (op0))))
        break;
 
       /* Try to simplify the compare to constant, possibly changing the
         comparison op, and/or changing op1 to zero.  */
-      code = simplify_compare_const (code, mode, op0, &op1);
+      code = simplify_compare_const (code, raw_mode, op0, &op1);
       const_op = INTVAL (op1);
 
       /* Compute some predicates to simplify code below.  */
@@ -12019,16 +12028,62 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
 
       /* If this is a sign bit comparison and we can do arithmetic in
         MODE, say that we will only be needing the sign bit of OP0.  */
-      if (sign_bit_comparison_p && HWI_COMPUTABLE_MODE_P (mode))
-       op0 = force_to_mode (op0, mode,
+      if (sign_bit_comparison_p
+         && is_a <scalar_int_mode> (raw_mode, &int_mode)
+         && HWI_COMPUTABLE_MODE_P (int_mode))
+       op0 = force_to_mode (op0, int_mode,
                             HOST_WIDE_INT_1U
-                            << (GET_MODE_PRECISION (mode) - 1),
+                            << (GET_MODE_PRECISION (int_mode) - 1),
                             0);
 
+      if (COMPARISON_P (op0))
+       {
+         /* We can't do anything if OP0 is a condition code value, rather
+            than an actual data value.  */
+         if (const_op != 0
+             || CC0_P (XEXP (op0, 0))
+             || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
+           break;
+
+         /* Get the two operands being compared.  */
+         if (GET_CODE (XEXP (op0, 0)) == COMPARE)
+           tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1);
+         else
+           tem = XEXP (op0, 0), tem1 = XEXP (op0, 1);
+
+         /* Check for the cases where we simply want the result of the
+            earlier test or the opposite of that result.  */
+         if (code == NE || code == EQ
+             || (val_signbit_known_set_p (raw_mode, STORE_FLAG_VALUE)
+                 && (code == LT || code == GE)))
+           {
+             enum rtx_code new_code;
+             if (code == LT || code == NE)
+               new_code = GET_CODE (op0);
+             else
+               new_code = reversed_comparison_code (op0, NULL);
+
+             if (new_code != UNKNOWN)
+               {
+                 code = new_code;
+                 op0 = tem;
+                 op1 = tem1;
+                 continue;
+               }
+           }
+         break;
+       }
+
+      if (raw_mode == VOIDmode)
+       break;
+      scalar_int_mode mode = as_a <scalar_int_mode> (raw_mode);
+
       /* Now try cases based on the opcode of OP0.  If none of the cases
         does a "continue", we exit this loop immediately after the
         switch.  */
 
+      unsigned int mode_width = GET_MODE_PRECISION (mode);
+      unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
       switch (GET_CODE (op0))
        {
        case ZERO_EXTRACT:
@@ -12173,8 +12228,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
             insn of the given mode, since we'd have to revert it
             later on, and then we wouldn't know whether to sign- or
             zero-extend.  */
-         mode = GET_MODE (XEXP (op0, 0));
-         if (GET_MODE_CLASS (mode) == MODE_INT
+         if (is_int_mode (GET_MODE (XEXP (op0, 0)), &mode)
              && ! unsigned_comparison_p
              && HWI_COMPUTABLE_MODE_P (mode)
              && trunc_int_for_mode (const_op, mode) == const_op
@@ -12208,11 +12262,12 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
 
          if (mode_width <= HOST_BITS_PER_WIDE_INT
              && subreg_lowpart_p (op0)
-             && GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op0))) > mode_width
+             && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (op0)),
+                                        &inner_mode)
+             && GET_MODE_PRECISION (inner_mode) > mode_width
              && GET_CODE (SUBREG_REG (op0)) == PLUS
              && CONST_INT_P (XEXP (SUBREG_REG (op0), 1)))
            {
-             machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
              rtx a = XEXP (SUBREG_REG (op0), 0);
              HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
 
@@ -12248,19 +12303,19 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          if (paradoxical_subreg_p (op0))
            ;
          else if (subreg_lowpart_p (op0)
-                  && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+                  && GET_MODE_CLASS (mode) == MODE_INT
                   && is_int_mode (GET_MODE (SUBREG_REG (op0)), &inner_mode)
                   && (code == NE || code == EQ)
                   && GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT
                   && !paradoxical_subreg_p (op0)
                   && (nonzero_bits (SUBREG_REG (op0), inner_mode)
-                      & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
+                      & ~GET_MODE_MASK (mode)) == 0)
            {
              /* Remove outer subregs that don't do anything.  */
              tem = gen_lowpart (inner_mode, op1);
 
              if ((nonzero_bits (tem, inner_mode)
-                  & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
+                  & ~GET_MODE_MASK (mode)) == 0)
                {
                  op0 = SUBREG_REG (op0);
                  op1 = tem;
@@ -12274,8 +12329,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          /* FALLTHROUGH */
 
        case ZERO_EXTEND:
-         mode = GET_MODE (XEXP (op0, 0));
-         if (GET_MODE_CLASS (mode) == MODE_INT
+         if (is_int_mode (GET_MODE (XEXP (op0, 0)), &mode)
              && (unsigned_comparison_p || equality_comparison_p)
              && HWI_COMPUTABLE_MODE_P (mode)
              && (unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (mode)
@@ -12364,45 +12418,6 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            }
          break;
 
-       case EQ:  case NE:
-       case UNEQ:  case LTGT:
-       case LT:  case LTU:  case UNLT:  case LE:  case LEU:  case UNLE:
-       case GT:  case GTU:  case UNGT:  case GE:  case GEU:  case UNGE:
-       case UNORDERED: case ORDERED:
-         /* We can't do anything if OP0 is a condition code value, rather
-            than an actual data value.  */
-         if (const_op != 0
-             || CC0_P (XEXP (op0, 0))
-             || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
-           break;
-
-         /* Get the two operands being compared.  */
-         if (GET_CODE (XEXP (op0, 0)) == COMPARE)
-           tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1);
-         else
-           tem = XEXP (op0, 0), tem1 = XEXP (op0, 1);
-
-         /* Check for the cases where we simply want the result of the
-            earlier test or the opposite of that result.  */
-         if (code == NE || code == EQ
-             || (val_signbit_known_set_p (GET_MODE (op0), STORE_FLAG_VALUE)
-                 && (code == LT || code == GE)))
-           {
-             enum rtx_code new_code;
-             if (code == LT || code == NE)
-               new_code = GET_CODE (op0);
-             else
-               new_code = reversed_comparison_code (op0, NULL);
-
-             if (new_code != UNKNOWN)
-               {
-                 code = new_code;
-                 op0 = tem;
-                 op1 = tem1;
-                 continue;
-               }
-           }
-         break;
 
        case IOR:
          /* The sign bit of (ior (plus X (const_int -1)) X) is nonzero
@@ -12674,7 +12689,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            {
              rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
              rtx add_const = XEXP (XEXP (op0, 0), 1);
-             rtx new_const = simplify_gen_binary (ASHIFTRT, GET_MODE (op0),
+             rtx new_const = simplify_gen_binary (ASHIFTRT, mode,
                                                   add_const, XEXP (op0, 1));
 
              op0 = simplify_gen_binary (PLUS, tmode,