OSDN Git Service

2004-11-26 Paolo Carlini <pcarlini@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 24ebbc9..ce198bb 100644 (file)
@@ -1176,6 +1176,8 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
       /* Don't substitute into an incremented register.  */
       || FIND_REG_INC_NOTE (i3, dest)
       || (succ && FIND_REG_INC_NOTE (succ, dest))
+      /* Don't substitute into a non-local goto, this confuses CFG.  */
+      || (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX))
 #if 0
       /* Don't combine the end of a libcall into anything.  */
       /* ??? This gives worse code, and appears to be unnecessary, since no
@@ -6904,11 +6906,6 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       && (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
     return gen_lowpart (mode, x);
 
-  /* If we aren't changing the mode, X is not a SUBREG, and all zero bits in
-     MASK are already known to be zero in X, we need not do anything.  */
-  if (GET_MODE (x) == mode && code != SUBREG && (~mask & nonzero) == 0)
-    return x;
-
   switch (code)
     {
     case CLOBBER:
@@ -7341,6 +7338,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         in STORE_FLAG_VALUE and FOO has a single bit that might be nonzero,
         which is equal to STORE_FLAG_VALUE.  */
       if ((mask & ~STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
+         && GET_MODE (XEXP (x, 0)) == mode
          && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
          && (nonzero_bits (XEXP (x, 0), mode)
              == (unsigned HOST_WIDE_INT) STORE_FLAG_VALUE))
@@ -9024,6 +9022,26 @@ simplify_shift_const (rtx x, enum rtx_code code,
              varop = XEXP (varop, 0);
              continue;
            }
+
+         /* Check for 'PLUS signbit', which is the canonical form of 'XOR
+            signbit', and attempt to change the PLUS to an XOR and move it to
+            the outer operation as is done above in the AND/IOR/XOR case
+            leg for shift(logical). See details in logical handling above
+            for reasoning in doing so.  */
+         if (code == LSHIFTRT
+             && GET_CODE (XEXP (varop, 1)) == CONST_INT
+             && mode_signbit_p (result_mode, XEXP (varop, 1))
+             && (new = simplify_binary_operation (code, result_mode,
+                                                  XEXP (varop, 1),
+                                                  GEN_INT (count))) != 0
+             && GET_CODE (new) == CONST_INT
+             && merge_outer_ops (&outer_op, &outer_const, XOR,
+                                 INTVAL (new), result_mode, &complement_p))
+           {
+             varop = XEXP (varop, 0);
+             continue;
+           }
+
          break;
 
        case MINUS:
@@ -9290,16 +9308,18 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
    An insn containing that will not be recognized.  */
 
 static rtx
-gen_lowpart_for_combine (enum machine_mode mode, rtx x)
+gen_lowpart_for_combine (enum machine_mode omode, rtx x)
 {
+  enum machine_mode imode = GET_MODE (x);
+  unsigned int osize = GET_MODE_SIZE (omode);
+  unsigned int isize = GET_MODE_SIZE (imode);
   rtx result;
 
-  if (GET_MODE (x) == mode)
+  if (omode == imode)
     return x;
 
-  /* Return identity if this is a CONST or symbolic
-     reference.  */
-  if (mode == Pmode
+  /* Return identity if this is a CONST or symbolic reference.  */
+  if (omode == Pmode
       && (GET_CODE (x) == CONST
          || GET_CODE (x) == SYMBOL_REF
          || GET_CODE (x) == LABEL_REF))
@@ -9307,13 +9327,12 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
 
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
-
-  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
-      && ! ((GET_MODE (x) == VOIDmode
+  if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
+      && ! ((imode == VOIDmode
             && (GET_CODE (x) == CONST_INT
                 || GET_CODE (x) == CONST_DOUBLE))
-           || GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode)))
-    return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+           || isize == osize))
+    goto fail;
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
      won't know what to do.  So we will strip off the SUBREG here and
@@ -9321,19 +9340,15 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
   if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x)))
     {
       x = SUBREG_REG (x);
-      if (GET_MODE (x) == mode)
+      if (GET_MODE (x) == omode)
        return x;
     }
 
-  result = gen_lowpart_common (mode, x);
+  result = gen_lowpart_common (omode, x);
+
 #ifdef CANNOT_CHANGE_MODE_CLASS
-  if (result != 0
-      && GET_CODE (result) == SUBREG
-      && REG_P (SUBREG_REG (result))
-      && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER)
-    bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (result))
-                                     * MAX_MACHINE_MODE
-                                     + GET_MODE (result));
+  if (result != 0 && GET_CODE (result) == SUBREG)
+    record_subregs_of_mode (result);
 #endif
 
   if (result)
@@ -9346,33 +9361,28 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
       /* Refuse to work on a volatile memory ref or one with a mode-dependent
         address.  */
       if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
-       return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+       goto fail;
 
       /* If we want to refer to something bigger than the original memref,
         generate a paradoxical subreg instead.  That will force a reload
         of the original memref X.  */
-      if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
-       return gen_rtx_SUBREG (mode, x, 0);
+      if (isize < osize)
+       return gen_rtx_SUBREG (omode, x, 0);
 
       if (WORDS_BIG_ENDIAN)
-       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
-                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
+       offset = MAX (isize, UNITS_PER_WORD) - MAX (osize, UNITS_PER_WORD);
 
+      /* Adjust the address so that the address-after-the-data is unchanged. */
       if (BYTES_BIG_ENDIAN)
-       {
-         /* Adjust the address so that the address-after-the-data is
-            unchanged.  */
-         offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
-                    - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-       }
+       offset -= MIN (UNITS_PER_WORD, osize) - MIN (UNITS_PER_WORD, isize);
 
-      return adjust_address_nv (x, mode, offset);
+      return adjust_address_nv (x, omode, offset);
     }
 
   /* If X is a comparison operator, rewrite it in a new mode.  This
      probably won't match, but may allow further simplifications.  */
   else if (COMPARISON_P (x))
-    return gen_rtx_fmt_ee (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
+    return gen_rtx_fmt_ee (GET_CODE (x), omode, XEXP (x, 0), XEXP (x, 1));
 
   /* If we couldn't simplify X any other way, just enclose it in a
      SUBREG.  Normally, this SUBREG won't match, but some patterns may
@@ -9381,21 +9391,22 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
     {
       int offset = 0;
       rtx res;
-      enum machine_mode sub_mode = GET_MODE (x);
 
-      offset = subreg_lowpart_offset (mode, sub_mode);
-      if (sub_mode == VOIDmode)
+      offset = subreg_lowpart_offset (omode, imode);
+      if (imode == VOIDmode)
        {
-         sub_mode = int_mode_for_mode (mode);
-         x = gen_lowpart_common (sub_mode, x);
-         if (x == 0)
-           return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+         imode = int_mode_for_mode (omode);
+         x = gen_lowpart_common (imode, x);
+         if (x == NULL)
+           goto fail;
        }
-      res = simplify_gen_subreg (mode, x, sub_mode, offset);
+      res = simplify_gen_subreg (omode, x, imode, offset);
       if (res)
        return res;
-      return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
     }
+
+ fail:
+  return gen_rtx_CLOBBER (imode, const0_rtx);
 }
 \f
 /* These routines make binary and unary operations by first seeing if they