OSDN Git Service

Make `solaris' reflect the most recent major release.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 6293bbc..5b44d66 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -74,6 +74,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    combine anyway.  */
 
 #include "config.h"
+/* Must precede rtl.h for FFS.  */
+#include <stdio.h>
+
 #include "gvarargs.h"
 #include "rtl.h"
 #include "flags.h"
@@ -87,7 +90,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "insn-attr.h"
 #include "recog.h"
 #include "real.h"
-#include <stdio.h>
 
 /* It is not safe to use ordinary gen_lowpart in combine.
    Use gen_lowpart_for_combine instead.  See comments there.  */
@@ -666,10 +668,18 @@ set_nonzero_bits_and_sign_copies (x, set)
       && REGNO (x) >= FIRST_PSEUDO_REGISTER
       && reg_n_sets[REGNO (x)] > 1
       && reg_basic_block[REGNO (x)] < 0
+      /* If this register is undefined at the start of the file, we can't
+        say what its contents were.  */
+      && ! (basic_block_live_at_start[0][REGNO (x) / REGSET_ELT_BITS]
+           & ((REGSET_ELT_TYPE) 1 << (REGNO (x) % REGSET_ELT_BITS)))
       && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
     {
       if (GET_CODE (set) == CLOBBER)
-       return;
+       {
+         reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
+         reg_sign_bit_copies[REGNO (x)] = 0;
+         return;
+       }
 
       /* If this is a complex assignment, see if we can convert it into a
         simple assignment.  */
@@ -684,8 +694,31 @@ set_nonzero_bits_and_sign_copies (x, set)
                  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (set)))))
              && SUBREG_REG (SET_DEST (set)) == x))
        {
+         rtx src = SET_SRC (set);
+
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+         /* If X is narrower than a word and SRC is a non-negative
+            constant that would appear negative in the mode of X,
+            sign-extend it for use in reg_nonzero_bits because some
+            machines (maybe most) will actually do the sign-extension
+            and this is the conservative approach. 
+
+            ??? For 2.5, try to tighten up the MD files in this regard
+            instead of this kludge.  */
+
+         if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
+             && GET_CODE (src) == CONST_INT
+             && INTVAL (src) > 0
+             && 0 != (INTVAL (src)
+                      & ((HOST_WIDE_INT) 1
+                         << GET_MODE_BITSIZE (GET_MODE (x)))))
+           src = GEN_INT (INTVAL (src)
+                          | ((HOST_WIDE_INT) (-1)
+                             << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+
          reg_nonzero_bits[REGNO (x)]
-           |= nonzero_bits (SET_SRC (set), nonzero_bits_mode);
+           |= nonzero_bits (src, nonzero_bits_mode);
          num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
          if (reg_sign_bit_copies[REGNO (x)] == 0
              || reg_sign_bit_copies[REGNO (x)] > num)
@@ -1043,9 +1076,18 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
        return 0;
 
       /* If DEST is used in I3, it is being killed in this insn,
-        so record that for later.  */
+        so record that for later. 
+        Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
+        STACK_POINTER_REGNUM, since these are always considered to be
+        live.  Similarly for ARG_POINTER_REGNUM if it is fixed.  */
       if (pi3dest_killed && GET_CODE (dest) == REG
-         && reg_referenced_p (dest, PATTERN (i3)))
+         && reg_referenced_p (dest, PATTERN (i3))
+         && REGNO (dest) != FRAME_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
+         && (REGNO (dest) != ARG_POINTER_REGNUM
+             || ! fixed_regs [REGNO (dest)])
+#endif
+         && REGNO (dest) != STACK_POINTER_REGNUM)
        {
          if (*pi3dest_killed)
            return 0;
@@ -2891,7 +2933,8 @@ subst (x, from, to, in_dest, unique_copy)
     x = temp, code = GET_CODE (temp);
 
   /* First see if we can apply the inverse distributive law.  */
-  if (code == PLUS || code == MINUS || code == IOR || code == XOR)
+  if (code == PLUS || code == MINUS
+      || code == AND || code == IOR || code == XOR)
     {
       x = apply_distributive_law (x);
       code = GET_CODE (x);
@@ -2904,7 +2947,7 @@ subst (x, from, to, in_dest, unique_copy)
        || code == MULT || code == AND || code == IOR || code == XOR
        || code == DIV || code == UDIV
        || code == SMAX || code == SMIN || code == UMAX || code == UMIN)
-      && GET_MODE_CLASS (mode) == MODE_INT)
+      && INTEGRAL_MODE_P (mode))
     {
       if (GET_CODE (XEXP (x, 0)) == code)
        {
@@ -3045,8 +3088,16 @@ subst (x, from, to, in_dest, unique_copy)
            return temp;
        }
        
+      /* If we want a subreg of a constant, at offset 0,
+        take the low bits.  On a little-endian machine, that's
+        always valid.  On a big-endian machine, it's valid
+        only if the constant's mode fits in one word.  */
       if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
-         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode))
+         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode)
+#if WORDS_BIG_ENDIAN
+         && GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD
+#endif
+         )
        return gen_lowpart_for_combine (mode, SUBREG_REG (x));
 
       /* If we are narrowing the object, we need to see if we can simplify
@@ -3186,7 +3237,7 @@ subst (x, from, to, in_dest, unique_copy)
 
       /* (neg (minus X Y)) can become (minus Y X).  */
       if (GET_CODE (XEXP (x, 0)) == MINUS
-         && (GET_MODE_CLASS (mode) != MODE_FLOAT
+         && (! FLOAT_MODE_P (mode)
              /* x-y != -(y-x) with IEEE floating point. */
              || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT))
        {
@@ -3281,7 +3332,7 @@ subst (x, from, to, in_dest, unique_copy)
 
       /* In IEEE floating point, x-0 is not the same as x.  */
       if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-          || GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) == MODE_INT)
+          || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))))
          && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
        return XEXP (x, 0);
       break;
@@ -3345,7 +3396,22 @@ subst (x, from, to, in_dest, unique_copy)
          goto restart;
        }
 
-      /* If only the low-order bit of X is possible nonzero, (plus x -1)
+      /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
+        C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
+        is 1.  This produces better code than the alternative immediately
+        below.  */
+      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+         && reversible_comparison_p (XEXP (x, 0))
+         && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
+             || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx)))
+       {
+         x = gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))),
+                         mode, XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1));
+         x = gen_unary (NEG, mode, x);
+         goto restart;
+       }
+
+      /* If only the low-order bit of X is possibly nonzero, (plus x -1)
         can become (ashiftrt (ashift (xor x 1) C) C) where C is
         the bitsize of the mode - 1.  This allows simplification of
         "a = (b & 8) == 0;"  */
@@ -3654,7 +3720,7 @@ subst (x, from, to, in_dest, unique_copy)
 
       /* Look for MIN or MAX.  */
 
-      if (GET_MODE_CLASS (mode) == MODE_INT
+      if (! FLOAT_MODE_P (mode)
          && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
          && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
          && rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 2))
@@ -3766,6 +3832,25 @@ subst (x, from, to, in_dest, unique_copy)
              return temp;
            }
        }
+
+      /* If we have (if_then_else (ne A 0) C1 0) and either A is known to 
+        be 0 or 1 and C1 is a single bit or A is known to be 0 or -1 and
+        C1 is the negation of a single bit, we can convert this operation
+        to a shift.  We can actually do this in more general cases, but it
+        doesn't seem worth it.  */
+
+      if (GET_CODE (XEXP (x, 0)) == NE && XEXP (XEXP (x, 0), 1) == const0_rtx
+         && XEXP (x, 2) == const0_rtx && GET_CODE (XEXP (x, 1)) == CONST_INT
+         && ((1 == nonzero_bits (XEXP (XEXP (x, 0), 0), mode)
+              && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
+             || ((num_sign_bit_copies (XEXP (XEXP (x, 0), 0), mode)
+                  == GET_MODE_BITSIZE (mode))
+                 && (i = exact_log2 (- INTVAL (XEXP (x, 1)))) >= 0)))
+       return
+         simplify_shift_const (NULL_RTX, ASHIFT, mode,
+                               gen_lowpart_for_combine (mode,
+                                                        XEXP (XEXP (x, 0), 0)),
+                               i);
       break;
          
     case ZERO_EXTRACT:
@@ -3929,7 +4014,7 @@ subst (x, from, to, in_dest, unique_copy)
         means that we only care about the low bits of the result.
 
         However, on most machines (those with neither BYTE_LOADS_ZERO_EXTEND
-        nor BYTES_LOADS_SIGN_EXTEND defined), we cannot perform a
+        nor BYTE_LOADS_SIGN_EXTEND defined), we cannot perform a
         narrower operation that requested since the high-order bits will
         be undefined.  On machine where BYTE_LOADS_*_EXTEND is defined,
         however, this transformation is safe as long as M1 and M2 have
@@ -5169,7 +5254,7 @@ make_compound_operation (x, in_code)
                                 gen_binary (GET_CODE (XEXP (x, 0)), mode, new,
                                             GEN_INT (newop1)),
                                 INTVAL (c2) - INTVAL (c1),
-                                NULL_RTX, mode_width - INTVAL (c1),
+                                NULL_RTX, mode_width - INTVAL (c2),
                                 code == LSHIFTRT, 0, in_code == COMPARE);
        }
 
@@ -5705,7 +5790,7 @@ apply_distributive_law (x)
   /* Distributivity is not true for floating point.
      It can change the value.  So don't do it.
      -- rms and moshier@world.std.com.  */
-  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+  if (FLOAT_MODE_P (GET_MODE (x)))
     return x;
 
   /* The outer operation can only be one of the following:  */
@@ -5920,13 +6005,18 @@ simplify_and_const_int (x, mode, varop, constop)
        case XOR:
          /* If VAROP is (ior (lshiftrt FOO C1) C2), try to commute the IOR and
             LSHIFT so we end up with an (and (lshiftrt (ior ...) ...) ...)
-            operation which may be a bitfield extraction.  */
+            operation which may be a bitfield extraction.  Ensure
+            that the constant we form is not wider than the mode of
+            VAROP.  */
 
          if (GET_CODE (XEXP (varop, 0)) == LSHIFTRT
              && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
              && INTVAL (XEXP (XEXP (varop, 0), 1)) >= 0
              && INTVAL (XEXP (XEXP (varop, 0), 1)) < HOST_BITS_PER_WIDE_INT
              && GET_CODE (XEXP (varop, 1)) == CONST_INT
+             && ((INTVAL (XEXP (XEXP (varop, 0), 1))
+                 + floor_log2 (INTVAL (XEXP (varop, 1))))
+                 < GET_MODE_BITSIZE (GET_MODE (varop)))
              && (INTVAL (XEXP (varop, 1))
                  & ~ nonzero_bits (XEXP (varop, 0), GET_MODE (varop)) == 0))
            {
@@ -5955,12 +6045,15 @@ simplify_and_const_int (x, mode, varop, constop)
                                         XEXP (varop, 1), constop))));
 
        case NOT:
-         /* (and (not FOO)) is (and (xor FOO CONST_OP)) so if FOO is an
-            LSHIFTRT we can do the same as above.  */
+         /* (and (not FOO)) is (and (xor FOO CONST)), so if FOO is an
+            LSHIFTRT, we can do the same as above.  Ensure that the constant
+            we form is not wider than the mode of VAROP.  */
 
          if (GET_CODE (XEXP (varop, 0)) == LSHIFTRT
              && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
              && INTVAL (XEXP (XEXP (varop, 0), 1)) >= 0
+             && (INTVAL (XEXP (XEXP (varop, 0), 1)) + floor_log2 (constop)
+                 < GET_MODE_BITSIZE (GET_MODE (varop)))
              && INTVAL (XEXP (XEXP (varop, 0), 1)) < HOST_BITS_PER_WIDE_INT)
            {
              temp = GEN_INT (constop << INTVAL (XEXP (XEXP (varop, 0), 1)));
@@ -6027,7 +6120,10 @@ simplify_and_const_int (x, mode, varop, constop)
                   + num_sign_bit_copies (XEXP (varop, 0),
                                          GET_MODE (XEXP (varop, 0))))
                  >= GET_MODE_BITSIZE (GET_MODE (varop)))
-             && exact_log2 (constop + 1) >= 0)
+             && exact_log2 (constop + 1) >= 0
+             && (num_sign_bit_copies (XEXP (varop, 0),
+                                      GET_MODE (XEXP (varop, 0)))
+                 >= exact_log2 (constop + 1)))
            varop
              = gen_rtx_combine (LSHIFTRT, GET_MODE (varop), XEXP (varop, 0),
                                 GEN_INT (GET_MODE_BITSIZE (GET_MODE (varop))
@@ -6205,14 +6301,46 @@ nonzero_bits (x, mode)
        return reg_last_set_nonzero_bits[REGNO (x)];
 
       tem = get_last_value (x);
+
       if (tem)
-       return nonzero_bits (tem, mode);
+       {
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+         /* If X is narrower than MODE and TEM is a non-negative
+            constant that would appear negative in the mode of X,
+            sign-extend it for use in reg_nonzero_bits because some
+            machines (maybe most) will actually do the sign-extension
+            and this is the conservative approach. 
+
+            ??? For 2.5, try to tighten up the MD files in this regard
+            instead of this kludge.  */
+
+         if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width
+             && GET_CODE (tem) == CONST_INT
+             && INTVAL (tem) > 0
+             && 0 != (INTVAL (tem)
+                      & ((HOST_WIDE_INT) 1
+                         << GET_MODE_BITSIZE (GET_MODE (x)))))
+           tem = GEN_INT (INTVAL (tem)
+                          | ((HOST_WIDE_INT) (-1)
+                             << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+         return nonzero_bits (tem, mode);
+       }
       else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
        return reg_nonzero_bits[REGNO (x)] & nonzero;
       else
        return nonzero;
 
     case CONST_INT:
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+      /* If X is negative in MODE, sign-extend the value.  */
+      if (INTVAL (x) > 0
+         && 0 != (INTVAL (x)
+                  & ((HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (GET_MODE (x)))))
+       return (INTVAL (x)
+               | ((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+
       return INTVAL (x);
 
 #ifdef BYTE_LOADS_ZERO_EXTEND
@@ -6519,8 +6647,8 @@ num_sign_bit_copies (x, mode)
         high-order bits are known to be sign bit copies.  */
 
       if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
-       return (GET_MODE_BITSIZE (mode) - GET_MODE_BITSIZE (GET_MODE (x))
-               + num_sign_bit_copies (SUBREG_REG (x), GET_MODE (x)));
+       return MAX (bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1,
+                   num_sign_bit_copies (SUBREG_REG (x), mode));
 
       /* For a smaller object, just ignore the high bits. */
       if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
@@ -6713,7 +6841,7 @@ num_sign_bit_copies (x, mode)
     return 1;
 
   nonzero = nonzero_bits (x, mode);
-  return (nonzero == GET_MODE_MASK (mode)
+  return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))
          ? 1 : bitwidth - floor_log2 (nonzero) - 1);
 }
 \f
@@ -7527,6 +7655,16 @@ simplify_shift_const (x, code, result_mode, varop, count)
       SUBST (XEXP (x, 1), const_rtx);
     }
 
+  /* If we have an outer operation and we just made a shift, it is
+     possible that we could have simplified the shift were it not
+     for the outer operation.  So try to do the simplification
+     recursively.  */
+
+  if (outer_op != NIL && GET_CODE (x) == code
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
+                             INTVAL (XEXP (x, 1)));
+
   /* If we were doing a LSHIFTRT in a wider mode than it was originally,
      turn off all the bits that the shift would have turned off.  */
   if (orig_code == LSHIFTRT && result_mode != shift_mode)
@@ -8595,7 +8733,7 @@ simplify_comparison (code, pop0, pop1)
              && ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
                  < HOST_BITS_PER_WIDE_INT)
              && ((const_op
-                  &  ((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1) == 0)
+                  & (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0)
              && mode_width <= HOST_BITS_PER_WIDE_INT
              && (nonzero_bits (XEXP (op0, 0), mode)
                  & ~ (mask >> (INTVAL (XEXP (op0, 1))
@@ -8805,12 +8943,14 @@ reversible_comparison_p (x)
   switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))))
     {
     case MODE_INT:
+    case MODE_PARTIAL_INT:
+    case MODE_COMPLEX_INT:
       return 1;
 
     case MODE_CC:
       x = get_last_value (XEXP (x, 0));
       return (x && GET_CODE (x) == COMPARE
-             && GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) == MODE_INT);
+             && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))));
     }
 
   return 0;
@@ -9773,6 +9913,16 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                        all_used = 0;
                      }
 
+                 /* Check for the case where the register dying partially
+                    overlaps the register set by this insn.  */
+                 if (all_used)
+                   for (i = regno; i < endregno; i++)
+                     if (dead_or_set_regno_p (place, i))
+                         {
+                           all_used = 0;
+                           break;
+                         }
+
                  if (! all_used)
                    {
                      /* Put only REG_DEAD notes for pieces that are