OSDN Git Service

* Makefile.in (reload1.o-warn): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index c51ca9e..cb79aa9 100644 (file)
@@ -1,6 +1,7 @@
 /* RTL simplification functions for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -158,6 +159,9 @@ avoid_constant_pool_reference (rtx x)
       return x;
     }
 
+  if (GET_MODE (x) == BLKmode)
+    return x;
+
   addr = XEXP (x, 0);
 
   /* Call target hook to avoid the effects of -fpic etc....  */
@@ -198,14 +202,6 @@ avoid_constant_pool_reference (rtx x)
 
   return x;
 }
-
-/* Return true if X is a MEM referencing the constant pool.  */
-
-bool
-constant_pool_reference_p (rtx x)
-{
-  return avoid_constant_pool_reference (x) != x;
-}
 \f
 /* Make a unary operation by first seeing if it folds and otherwise making
    the specified operation.  */
@@ -786,11 +782,54 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       break;
 
     case POPCOUNT:
+      switch (GET_CODE (op))
+       {
+       case BSWAP:
+       case ZERO_EXTEND:
+         /* (popcount (zero_extend <X>)) = (popcount <X>) */
+         return simplify_gen_unary (POPCOUNT, mode, XEXP (op, 0),
+                                    GET_MODE (XEXP (op, 0)));
+
+       case ROTATE:
+       case ROTATERT:
+         /* Rotations don't affect popcount.  */
+         if (!side_effects_p (XEXP (op, 1)))
+           return simplify_gen_unary (POPCOUNT, mode, XEXP (op, 0),
+                                      GET_MODE (XEXP (op, 0)));
+         break;
+
+       default:
+         break;
+       }
+      break;
+
     case PARITY:
-      /* (pop* (zero_extend <X>)) = (pop* <X>) */
-      if (GET_CODE (op) == ZERO_EXTEND)
-       return simplify_gen_unary (code, mode, XEXP (op, 0),
-                                  GET_MODE (XEXP (op, 0)));
+      switch (GET_CODE (op))
+       {
+       case NOT:
+       case BSWAP:
+       case ZERO_EXTEND:
+       case SIGN_EXTEND:
+         return simplify_gen_unary (PARITY, mode, XEXP (op, 0),
+                                    GET_MODE (XEXP (op, 0)));
+
+       case ROTATE:
+       case ROTATERT:
+         /* Rotations don't affect parity.  */
+         if (!side_effects_p (XEXP (op, 1)))
+           return simplify_gen_unary (PARITY, mode, XEXP (op, 0),
+                                      GET_MODE (XEXP (op, 0)));
+         break;
+
+       default:
+         break;
+       }
+      break;
+
+    case BSWAP:
+      /* (bswap (bswap x)) -> x.  */
+      if (GET_CODE (op) == BSWAP)
+       return XEXP (op, 0);
       break;
 
     case FLOAT:
@@ -1042,6 +1081,21 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          val &= 1;
          break;
 
+       case BSWAP:
+         {
+           unsigned int s;
+
+           val = 0;
+           for (s = 0; s < width; s += 8)
+             {
+               unsigned int d = width - s - 8;
+               unsigned HOST_WIDE_INT byte;
+               byte = (arg0 >> s) & 0xff;
+               val |= byte << d;
+             }
+         }
+         break;
+
        case TRUNCATE:
          val = arg0;
          break;
@@ -1188,6 +1242,30 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          lv &= 1;
          break;
 
+       case BSWAP:
+         {
+           unsigned int s;
+
+           hv = 0;
+           lv = 0;
+           for (s = 0; s < width; s += 8)
+             {
+               unsigned int d = width - s - 8;
+               unsigned HOST_WIDE_INT byte;
+
+               if (s < HOST_BITS_PER_WIDE_INT)
+                 byte = (l1 >> s) & 0xff;
+               else
+                 byte = (h1 >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
+
+               if (d < HOST_BITS_PER_WIDE_INT)
+                 lv |= byte << d;
+               else
+                 hv |= byte << (d - HOST_BITS_PER_WIDE_INT);
+             }
+         }
+         break;
+
        case TRUNCATE:
          /* This is just a change-of-mode, so do nothing.  */
          lv = l1, hv = h1;
@@ -1610,7 +1688,8 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                                                         XEXP (op0, 1)));
 
       /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).  */
-      if (GET_CODE (op0) == MULT
+      if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode)
+         && GET_CODE (op0) == MULT
          && GET_CODE (XEXP (op0, 0)) == NEG)
        {
          rtx in1, in2;
@@ -1838,7 +1917,8 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
        return reversed;
 
       /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).  */
-      if (GET_CODE (op1) == MULT
+      if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode)
+         && GET_CODE (op1) == MULT
          && GET_CODE (XEXP (op1, 0)) == NEG)
        {
          rtx in1, in2;
@@ -1853,7 +1933,8 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       /* Canonicalize (minus (neg A) (mult B C)) to
         (minus (mult (neg B) C) A).  */
-      if (GET_CODE (op1) == MULT
+      if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode)
+         && GET_CODE (op1) == MULT
          && GET_CODE (op0) == NEG)
        {
          rtx in1, in2;
@@ -1986,6 +2067,33 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
        return op1;
  
+      /* Canonicalize (X & C1) | C2.  */
+      if (GET_CODE (op0) == AND
+         && GET_CODE (trueop1) == CONST_INT
+         && GET_CODE (XEXP (op0, 1)) == CONST_INT)
+       {
+         HOST_WIDE_INT mask = GET_MODE_MASK (mode);
+         HOST_WIDE_INT c1 = INTVAL (XEXP (op0, 1));
+         HOST_WIDE_INT c2 = INTVAL (trueop1);
+
+         /* If (C1&C2) == C1, then (X&C1)|C2 becomes X.  */
+         if ((c1 & c2) == c1
+             && !side_effects_p (XEXP (op0, 0)))
+           return trueop1;
+
+         /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2.  */
+         if (((c1|c2) & mask) == mask)
+           return simplify_gen_binary (IOR, mode, XEXP (op0, 0), op1);
+
+         /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2.  */
+         if (((c1 & ~c2) & mask) != (c1 & mask))
+           {
+             tem = simplify_gen_binary (AND, mode, XEXP (op0, 0),
+                                        gen_int_mode (c1 & ~c2, mode));
+             return simplify_gen_binary (IOR, mode, tem, op1);
+           }
+       }
+
       /* Convert (A & B) | A to A.  */
       if (GET_CODE (op0) == AND
          && (rtx_equal_p (XEXP (op0, 0), op1)
@@ -2226,6 +2334,18 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          return simplify_gen_unary (ZERO_EXTEND, mode, tem, imode);
        }
 
+      /* Canonicalize (A | C1) & C2 as (A & C2) | (C1 & C2).  */
+      if (GET_CODE (op0) == IOR
+         && GET_CODE (trueop1) == CONST_INT
+         && GET_CODE (XEXP (op0, 1)) == CONST_INT)
+       {
+         HOST_WIDE_INT tmp = INTVAL (trueop1) & INTVAL (XEXP (op0, 1));
+         return simplify_gen_binary (IOR, mode,
+                                     simplify_gen_binary (AND, mode,
+                                                          XEXP (op0, 0), op1),
+                                     gen_int_mode (tmp, mode));
+       }
+
       /* Convert (A ^ B) & A to A & (~B) since the latter is often a single
         insn (and may simplify more).  */
       if (GET_CODE (op0) == XOR
@@ -2436,21 +2556,45 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
     case ROTATERT:
     case ROTATE:
     case ASHIFTRT:
+      if (trueop1 == CONST0_RTX (mode))
+       return op0;
+      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
+       return op0;
       /* Rotating ~0 always results in ~0.  */
       if (GET_CODE (trueop0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
          && (unsigned HOST_WIDE_INT) INTVAL (trueop0) == GET_MODE_MASK (mode)
          && ! side_effects_p (op1))
        return op0;
-
-      /* Fall through....  */
+      break;
 
     case ASHIFT:
     case SS_ASHIFT:
+      if (trueop1 == CONST0_RTX (mode))
+       return op0;
+      if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
+       return op0;
+      break;
+
     case LSHIFTRT:
       if (trueop1 == CONST0_RTX (mode))
        return op0;
       if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
        return op0;
+      /* Optimize (lshiftrt (clz X) C) as (eq X 0).  */
+      if (GET_CODE (op0) == CLZ
+         && GET_CODE (trueop1) == CONST_INT
+         && STORE_FLAG_VALUE == 1
+         && INTVAL (trueop1) < (HOST_WIDE_INT)width)
+       {
+         enum machine_mode imode = GET_MODE (XEXP (op0, 0));
+         unsigned HOST_WIDE_INT zero_val = 0;
+
+         if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
+             && zero_val == GET_MODE_BITSIZE (imode)
+             && INTVAL (trueop1) == exact_log2 (zero_val))
+           return simplify_gen_relational (EQ, mode, imode,
+                                           XEXP (op0, 0), const0_rtx);
+       }
       break;
 
     case SMIN:
@@ -3161,7 +3305,6 @@ struct simplify_plus_minus_op_data
 {
   rtx op;
   short neg;
-  short ix;
 };
 
 static int
@@ -3175,7 +3318,12 @@ simplify_plus_minus_op_data_cmp (const void *p1, const void *p2)
            - commutative_operand_precedence (d1->op));
   if (result)
     return result;
-  return d1->ix - d2->ix;
+
+  /* Group together equal REGs to do more simplification.  */
+  if (REG_P (d1->op) && REG_P (d2->op))
+    return REGNO (d1->op) - REGNO (d2->op);
+  else
+    return 0;
 }
 
 static rtx
@@ -3185,7 +3333,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
   struct simplify_plus_minus_op_data ops[8];
   rtx result, tem;
   int n_ops = 2, input_ops = 2;
-  int first, changed, canonicalized = 0;
+  int changed, n_constants = 0, canonicalized = 0;
   int i, j;
 
   memset (ops, 0, sizeof ops);
@@ -3262,6 +3410,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
              break;
 
            case CONST_INT:
+             n_constants++;
              if (this_neg)
                {
                  ops[i].op = neg_const_int (mode, this_op);
@@ -3278,18 +3427,10 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
     }
   while (changed);
 
-  gcc_assert (n_ops >= 2);
-  if (!canonicalized)
-    {
-      int n_constants = 0;
-
-      for (i = 0; i < n_ops; i++)
-       if (GET_CODE (ops[i].op) == CONST_INT)
-         n_constants++;
+  if (n_constants > 1)
+    canonicalized = 1;
 
-      if (n_constants <= 1)
-       return NULL_RTX;
-    }
+  gcc_assert (n_ops >= 2);
 
   /* If we only have two operands, we can avoid the loops.  */
   if (n_ops == 2)
@@ -3318,22 +3459,37 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
       return simplify_const_binary_operation (code, mode, lhs, rhs);
     }
 
-  /* Now simplify each pair of operands until nothing changes.  The first
-     time through just simplify constants against each other.  */
-
-  first = 1;
+  /* Now simplify each pair of operands until nothing changes.  */
   do
     {
-      changed = first;
+      /* Insertion sort is good enough for an eight-element array.  */
+      for (i = 1; i < n_ops; i++)
+        {
+          struct simplify_plus_minus_op_data save;
+          j = i - 1;
+          if (simplify_plus_minus_op_data_cmp (&ops[j], &ops[i]) < 0)
+           continue;
+
+          canonicalized = 1;
+          save = ops[i];
+          do
+           ops[j + 1] = ops[j];
+          while (j-- && simplify_plus_minus_op_data_cmp (&ops[j], &save) > 0);
+          ops[j + 1] = save;
+        }
 
-      for (i = 0; i < n_ops - 1; i++)
-       for (j = i + 1; j < n_ops; j++)
+      /* This is only useful the first time through.  */
+      if (!canonicalized)
+        return NULL_RTX;
+
+      changed = 0;
+      for (i = n_ops - 1; i > 0; i--)
+       for (j = i - 1; j >= 0; j--)
          {
-           rtx lhs = ops[i].op, rhs = ops[j].op;
-           int lneg = ops[i].neg, rneg = ops[j].neg;
+           rtx lhs = ops[j].op, rhs = ops[i].op;
+           int lneg = ops[j].neg, rneg = ops[i].neg;
 
-           if (lhs != 0 && rhs != 0
-               && (! first || (CONSTANT_P (lhs) && CONSTANT_P (rhs))))
+           if (lhs != 0 && rhs != 0)
              {
                enum rtx_code ncode = PLUS;
 
@@ -3369,13 +3525,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
                    && ! (GET_CODE (tem) == CONST
                          && GET_CODE (XEXP (tem, 0)) == ncode
                          && XEXP (XEXP (tem, 0), 0) == lhs
-                         && XEXP (XEXP (tem, 0), 1) == rhs)
-                   /* Don't allow -x + -1 -> ~x simplifications in the
-                      first pass.  This allows us the chance to combine
-                      the -1 with other constants.  */
-                   && ! (first
-                         && GET_CODE (tem) == NOT
-                         && XEXP (tem, 0) == rhs))
+                         && XEXP (XEXP (tem, 0), 1) == rhs))
                  {
                    lneg &= rneg;
                    if (GET_CODE (tem) == NEG)
@@ -3391,24 +3541,17 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
              }
          }
 
-      first = 0;
+      /* Pack all the operands to the lower-numbered entries.  */
+      for (i = 0, j = 0; j < n_ops; j++)
+        if (ops[j].op)
+          {
+           ops[i] = ops[j];
+           i++;
+          }
+      n_ops = i;
     }
   while (changed);
 
-  /* Pack all the operands to the lower-numbered entries.  */
-  for (i = 0, j = 0; j < n_ops; j++)
-    if (ops[j].op)
-      {
-       ops[i] = ops[j];
-       /* Stabilize sort.  */
-       ops[i].ix = i;
-       i++;
-      }
-  n_ops = i;
-
-  /* Sort the operations based on swap_commutative_operands_p.  */
-  qsort (ops, n_ops, sizeof (*ops), simplify_plus_minus_op_data_cmp);
-
   /* Create (minus -C X) instead of (neg (const (plus X C))).  */
   if (n_ops == 2
       && GET_CODE (ops[1].op) == CONST_INT
@@ -3565,29 +3708,69 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
 {
   enum rtx_code op0code = GET_CODE (op0);
 
-  if (GET_CODE (op1) == CONST_INT)
+  if (op1 == const0_rtx && COMPARISON_P (op0))
     {
-      if (INTVAL (op1) == 0 && COMPARISON_P (op0))
+      /* If op0 is a comparison, extract the comparison arguments
+         from it.  */
+      if (code == NE)
        {
-         /* If op0 is a comparison, extract the comparison arguments
-            from it.  */
-         if (code == NE)
-           {
-             if (GET_MODE (op0) == mode)
-               return simplify_rtx (op0);
-             else
-               return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
-                                               XEXP (op0, 0), XEXP (op0, 1));
-           }
-         else if (code == EQ)
-           {
-             enum rtx_code new_code = reversed_comparison_code (op0, NULL_RTX);
-             if (new_code != UNKNOWN)
-               return simplify_gen_relational (new_code, mode, VOIDmode,
-                                               XEXP (op0, 0), XEXP (op0, 1));
-           }
+         if (GET_MODE (op0) == mode)
+           return simplify_rtx (op0);
+         else
+           return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
+                                           XEXP (op0, 0), XEXP (op0, 1));
+       }
+      else if (code == EQ)
+       {
+         enum rtx_code new_code = reversed_comparison_code (op0, NULL_RTX);
+         if (new_code != UNKNOWN)
+           return simplify_gen_relational (new_code, mode, VOIDmode,
+                                           XEXP (op0, 0), XEXP (op0, 1));
+       }
+    }
+
+  if (op1 == const0_rtx)
+    {
+      /* Canonicalize (GTU x 0) as (NE x 0).  */
+      if (code == GTU)
+        return simplify_gen_relational (NE, mode, cmp_mode, op0, op1);
+      /* Canonicalize (LEU x 0) as (EQ x 0).  */
+      if (code == LEU)
+        return simplify_gen_relational (EQ, mode, cmp_mode, op0, op1);
+    }
+  else if (op1 == const1_rtx)
+    {
+      switch (code)
+        {
+        case GE:
+         /* Canonicalize (GE x 1) as (GT x 0).  */
+         return simplify_gen_relational (GT, mode, cmp_mode,
+                                         op0, const0_rtx);
+       case GEU:
+         /* Canonicalize (GEU x 1) as (NE x 0).  */
+         return simplify_gen_relational (NE, mode, cmp_mode,
+                                         op0, const0_rtx);
+       case LT:
+         /* Canonicalize (LT x 1) as (LE x 0).  */
+         return simplify_gen_relational (LE, mode, cmp_mode,
+                                         op0, const0_rtx);
+       case LTU:
+         /* Canonicalize (LTU x 1) as (EQ x 0).  */
+         return simplify_gen_relational (EQ, mode, cmp_mode,
+                                         op0, const0_rtx);
+       default:
+         break;
        }
     }
+  else if (op1 == constm1_rtx)
+    {
+      /* Canonicalize (LE x -1) as (LT x 0).  */
+      if (code == LE)
+        return simplify_gen_relational (LT, mode, cmp_mode, op0, const0_rtx);
+      /* Canonicalize (GT x -1) as (GE x 0).  */
+      if (code == GT)
+        return simplify_gen_relational (GE, mode, cmp_mode, op0, const0_rtx);
+    }
 
   /* (eq/ne (plus x cst1) cst2) simplifies to (eq/ne x (cst2 - cst1))  */
   if ((code == EQ || code == NE)
@@ -3653,6 +3836,27 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
                                    simplify_gen_binary (XOR, cmp_mode,
                                                         XEXP (op0, 1), op1));
 
+  if (op0code == POPCOUNT && op1 == const0_rtx)
+    switch (code)
+      {
+      case EQ:
+      case LE:
+      case LEU:
+       /* (eq (popcount x) (const_int 0)) -> (eq x (const_int 0)).  */
+       return simplify_gen_relational (EQ, mode, GET_MODE (XEXP (op0, 0)),
+                                       XEXP (op0, 0), const0_rtx);
+
+      case NE:
+      case GT:
+      case GTU:
+       /* (ne (popcount x) (const_int 0)) -> (ne x (const_int 0)).  */
+       return simplify_gen_relational (NE, mode, GET_MODE (XEXP (op0, 0)),
+                                       XEXP (op0, 0), const0_rtx);
+
+      default:
+       break;
+      }
+
   return NULL_RTX;
 }
 
@@ -3709,26 +3913,25 @@ simplify_const_relational_operation (enum rtx_code code,
      a register or a CONST_INT, this can't help; testing for these cases will
      prevent infinite recursion here and speed things up.
 
-     If CODE is an unsigned comparison, then we can never do this optimization,
-     because it gives an incorrect result if the subtraction wraps around zero.
-     ANSI C defines unsigned operations such that they never overflow, and
-     thus such cases can not be ignored; but we cannot do it even for
-     signed comparisons for languages such as Java, so test flag_wrapv.  */
+     We can only do this for EQ and NE comparisons as otherwise we may
+     lose or introduce overflow which we cannot disregard as undefined as
+     we do not know the signedness of the operation on either the left or
+     the right hand side of the comparison.  */
 
-  if (!flag_wrapv && INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
+  if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
+      && (code == EQ || code == NE)
       && ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
            && (REG_P (op1) || GET_CODE (trueop1) == CONST_INT))
       && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
-      /* We cannot do this for == or != if tem is a nonzero address.  */
-      && ((code != EQ && code != NE) || ! nonzero_address_p (tem))
-      && code != GTU && code != GEU && code != LTU && code != LEU)
+      /* We cannot do this if tem is a nonzero address.  */
+      && ! nonzero_address_p (tem))
     return simplify_const_relational_operation (signed_condition (code),
                                                mode, tem, const0_rtx);
 
-  if (flag_unsafe_math_optimizations && code == ORDERED)
+  if (! HONOR_NANS (mode) && code == ORDERED)
     return const_true_rtx;
 
-  if (flag_unsafe_math_optimizations && code == UNORDERED)
+  if (! HONOR_NANS (mode) && code == UNORDERED)
     return const0_rtx;
 
   /* For modes without NaNs, if the two operands are equal, we know the
@@ -3911,26 +4114,52 @@ simplify_const_relational_operation (enum rtx_code code,
          /* Optimize abs(x) < 0.0.  */
          if (trueop1 == CONST0_RTX (mode)
              && !HONOR_SNANS (mode)
-             && !(flag_wrapv && INTEGRAL_MODE_P (mode)))
+             && (!INTEGRAL_MODE_P (mode)
+                 || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
            {
              tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
                                                       : trueop0;
              if (GET_CODE (tem) == ABS)
-               return const0_rtx;
+               {
+                 if (INTEGRAL_MODE_P (mode)
+                     && (issue_strict_overflow_warning
+                         (WARN_STRICT_OVERFLOW_CONDITIONAL)))
+                   warning (OPT_Wstrict_overflow,
+                            ("assuming signed overflow does not occur when "
+                             "assuming abs (x) < 0 is false"));
+                 return const0_rtx;
+               }
            }
+
+         /* Optimize popcount (x) < 0.  */
+         if (GET_CODE (trueop0) == POPCOUNT && trueop1 == const0_rtx)
+           return const_true_rtx;
          break;
 
        case GE:
          /* Optimize abs(x) >= 0.0.  */
          if (trueop1 == CONST0_RTX (mode)
              && !HONOR_NANS (mode)
-             && !(flag_wrapv && INTEGRAL_MODE_P (mode)))
+             && (!INTEGRAL_MODE_P (mode)
+                 || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
            {
              tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
                                                       : trueop0;
              if (GET_CODE (tem) == ABS)
-               return const_true_rtx;
+               {
+                 if (INTEGRAL_MODE_P (mode)
+                     && (issue_strict_overflow_warning
+                         (WARN_STRICT_OVERFLOW_CONDITIONAL)))
+                   warning (OPT_Wstrict_overflow,
+                            ("assuming signed overflow does not occur when "
+                             "assuming abs (x) >= 0 is true"));
+                 return const_true_rtx;
+               }
            }
+
+         /* Optimize popcount (x) >= 0.  */
+         if (GET_CODE (trueop0) == POPCOUNT && trueop1 == const0_rtx)
+           return const_true_rtx;
          break;
 
        case UNGE:
@@ -4620,13 +4849,22 @@ simplify_subreg (enum machine_mode outermode, rtx op,
      of real and imaginary part.  */
   if (GET_CODE (op) == CONCAT)
     {
-      unsigned int inner_size, final_offset;
+      unsigned int part_size, final_offset;
       rtx part, res;
 
-      inner_size = GET_MODE_UNIT_SIZE (innermode);
-      part = byte < inner_size ? XEXP (op, 0) : XEXP (op, 1);
-      final_offset = byte % inner_size;
-      if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
+      part_size = GET_MODE_UNIT_SIZE (GET_MODE (XEXP (op, 0)));
+      if (byte < part_size)
+       {
+         part = XEXP (op, 0);
+         final_offset = byte;
+       }
+      else
+       {
+         part = XEXP (op, 1);
+         final_offset = byte - part_size;
+       }
+
+      if (final_offset + GET_MODE_SIZE (outermode) > part_size)
        return NULL_RTX;
 
       res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
@@ -4825,9 +5063,9 @@ simplify_rtx (rtx x)
 
     case RTX_EXTRA:
       if (code == SUBREG)
-       return simplify_gen_subreg (mode, SUBREG_REG (x),
-                                   GET_MODE (SUBREG_REG (x)),
-                                   SUBREG_BYTE (x));
+       return simplify_subreg (mode, SUBREG_REG (x),
+                               GET_MODE (SUBREG_REG (x)),
+                               SUBREG_BYTE (x));
       break;
 
     case RTX_OBJ:
@@ -4845,4 +5083,3 @@ simplify_rtx (rtx x)
     }
   return NULL;
 }
-