OSDN Git Service

* collect2.c (find_a_file): Use HAVE_DOS_BASED_FILE_SYSTEM in place
[pf3gnuchains/gcc-fork.git] / gcc / rtlanal.c
index 4d75e79..d39071b 100644 (file)
@@ -1,5 +1,5 @@
 /* Analyze RTL for C-Compiler
-   Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -24,6 +24,8 @@ Boston, MA 02111-1307, USA.  */
 #include "rtl.h"
 
 static int rtx_addr_can_trap_p PROTO((rtx));
+static void reg_set_p_1                PROTO((rtx, rtx));
+static void reg_set_last_1     PROTO((rtx, rtx));
 
 
 /* Forward declarations */
@@ -324,6 +326,20 @@ no_labels_between_p (beg, end)
   return 1;
 }
 
+/* Return 1 if in between BEG and END, exclusive of BEG and END, there is
+   no JUMP_INSN insn.  */
+
+int
+no_jumps_between_p (beg, end)
+     rtx beg, end;
+{
+  register rtx p;
+  for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))
+    if (GET_CODE (p) == JUMP_INSN)
+      return 0;
+  return 1;
+}
+
 /* Nonzero if register REG is used in an insn between
    FROM_INSN and TO_INSN (exclusive of those two).  */
 
@@ -453,7 +469,8 @@ static int reg_set_flag;
 
 static void
 reg_set_p_1 (x, pat)
-     rtx x, pat;
+     rtx x;
+     rtx pat ATTRIBUTE_UNUSED;
 {
   /* We don't want to return 1 if X is a MEM that contains a register
      within REG_SET_REG.  */
@@ -497,6 +514,52 @@ reg_set_p (reg, insn)
 }
 
 /* Similar to reg_set_between_p, but check all registers in X.  Return 0
+   only if none of them are modified between START and END.  Do not
+   consider non-registers one way or the other.  */
+
+int
+regs_set_between_p (x, start, end)
+     rtx x;
+     rtx start, end;
+{
+  enum rtx_code code = GET_CODE (x);
+  char *fmt;
+  int i, j;
+
+  switch (code)
+    {
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+    case PC:
+    case CC0:
+      return 0;
+
+    case REG:
+      return reg_set_between_p (x, start, end);
+      
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e' && regs_set_between_p (XEXP (x, i), start, end))
+       return 1;
+
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         if (regs_set_between_p (XVECEXP (x, i, j), start, end))
+           return 1;
+    }
+
+  return 0;
+}
+
+/* Similar to reg_set_between_p, but check all registers in X.  Return 0
    only if none of them are modified between START and END.  Return 1 if
    X contains a MEM; this routine does not perform any memory aliasing.  */
 
@@ -641,17 +704,51 @@ single_set (insn)
   
   return 0;
 }
+
+/* Given an INSN, return nonzero if it has more than one SET, else return
+   zero.  */
+
+int
+multiple_sets (insn)
+     rtx insn;
+{
+  int found;
+  int i;
+  
+  /* INSN must be an insn.  */
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+    return 0;
+
+  /* Only a PARALLEL can have multiple SETs.  */
+  if (GET_CODE (PATTERN (insn)) == PARALLEL)
+    {
+      for (i = 0, found = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+       if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
+         {
+           /* If we have already found a SET, then return now.  */
+           if (found)
+             return 1;
+           else
+             found = 1;
+         }
+    }
+  
+  /* Either zero or one SET.  */
+  return 0;
+}
 \f
 /* Return the last thing that X was assigned from before *PINSN.  Verify that
    the object is not modified up to VALID_TO.  If it was, if we hit
    a partial assignment to X, or hit a CODE_LABEL first, return X.  If we
-   found an assignment, update *PINSN to point to it.  */
+   found an assignment, update *PINSN to point to it.  
+   ALLOW_HWREG is set to 1 if hardware registers are allowed to be the src.  */
 
 rtx
-find_last_value (x, pinsn, valid_to)
+find_last_value (x, pinsn, valid_to, allow_hwreg)
      rtx x;
      rtx *pinsn;
      rtx valid_to;
+     int allow_hwreg;
 {
   rtx p;
 
@@ -672,8 +769,8 @@ find_last_value (x, pinsn, valid_to)
            if (! modified_between_p (src, PREV_INSN (p), valid_to)
                /* Reject hard registers because we don't usually want
                   to use them; we'd rather use a pseudo.  */
-               && ! (GET_CODE (src) == REG
-                     && REGNO (src) < FIRST_PSEUDO_REGISTER))
+               && (! (GET_CODE (src) == REG
+                     && REGNO (src) < FIRST_PSEUDO_REGISTER) || allow_hwreg))
              {
                *pinsn = p;
                return src;
@@ -814,7 +911,14 @@ reg_overlap_mentioned_p (x, in)
 {
   int regno, endregno;
 
-  if (GET_CODE (x) == SUBREG)
+  /* Overly conservative.  */
+  if (GET_CODE (x) == STRICT_LOW_PART)
+    x = XEXP (x, 0);
+
+  /* If either argument is a constant, then modifying X can not affect IN.  */
+  if (CONSTANT_P (x) || CONSTANT_P (in))
+    return 0;
+  else if (GET_CODE (x) == SUBREG)
     {
       regno = REGNO (SUBREG_REG (x));
       if (regno < FIRST_PSEUDO_REGISTER)
@@ -822,8 +926,6 @@ reg_overlap_mentioned_p (x, in)
     }
   else if (GET_CODE (x) == REG)
     regno = REGNO (x);
-  else if (CONSTANT_P (x))
-    return 0;
   else if (GET_CODE (x) == MEM)
     {
       char *fmt;
@@ -843,6 +945,18 @@ reg_overlap_mentioned_p (x, in)
   else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC
           || GET_CODE (x) == CC0)
     return reg_mentioned_p (x, in);
+  else if (GET_CODE (x) == PARALLEL
+          && GET_MODE (x) == BLKmode)
+    {
+      register int i;
+
+      /* If any register in here refers to it
+        we return true.  */
+      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+       if (reg_overlap_mentioned_p (SET_DEST (XVECEXP (x, 0, i)), in))
+         return 1;
+      return 0;
+    }
   else
     abort ();
 
@@ -1066,7 +1180,7 @@ rtx_equal_p (x, y)
 void
 note_stores (x, fun)
      register rtx x;
-     void (*fun) ();
+     void (*fun) PROTO ((rtx, rtx));
 {
   if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER))
     {
@@ -1078,7 +1192,16 @@ note_stores (x, fun)
             || GET_CODE (dest) == SIGN_EXTRACT
             || GET_CODE (dest) == STRICT_LOW_PART)
        dest = XEXP (dest, 0);
-      (*fun) (dest, x);
+
+      if (GET_CODE (dest) == PARALLEL
+         && GET_MODE (dest) == BLKmode)
+       {
+         register int i;
+         for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
+           (*fun) (SET_DEST (XVECEXP (dest, 0, i)), x);
+       }
+      else
+       (*fun) (dest, x);
     }
   else if (GET_CODE (x) == PARALLEL)
     {
@@ -1097,7 +1220,15 @@ note_stores (x, fun)
                     || GET_CODE (dest) == SIGN_EXTRACT
                     || GET_CODE (dest) == STRICT_LOW_PART)
                dest = XEXP (dest, 0);
-             (*fun) (dest, y);
+             if (GET_CODE (dest) == PARALLEL
+                 && GET_MODE (dest) == BLKmode)
+               {
+                 register int i;
+                 for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
+                   (*fun) (SET_DEST (XVECEXP (dest, 0, i)), y);
+               }
+             else
+               (*fun) (dest, y);
            }
        }
     }
@@ -1157,30 +1288,21 @@ dead_or_set_regno_p (insn, test_regno)
   int regno, endregno;
   rtx link;
 
-  /* REG_READ notes are not normally maintained after reload, so we
-     ignore them if the are invalid.  */
-  if (! reload_completed
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
-      || PRESERVE_DEATH_INFO_REGNO_P (test_regno)
-#endif
-      )
+  /* See if there is a death note for something that includes
+     TEST_REGNO.  */
+  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     {
-      /* See if there is a death note for something that includes
-         TEST_REGNO.  */
-      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-       {
-         if (REG_NOTE_KIND (link) != REG_DEAD
-             || GET_CODE (XEXP (link, 0)) != REG)
-           continue;
+      if (REG_NOTE_KIND (link) != REG_DEAD
+         || GET_CODE (XEXP (link, 0)) != REG)
+       continue;
 
-         regno = REGNO (XEXP (link, 0));
-         endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1
-                     : regno + HARD_REGNO_NREGS (regno,
-                                                 GET_MODE (XEXP (link, 0))));
+      regno = REGNO (XEXP (link, 0));
+      endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1
+                 : regno + HARD_REGNO_NREGS (regno,
+                                             GET_MODE (XEXP (link, 0))));
 
-         if (test_regno >= regno && test_regno < endregno)
-           return 1;
-       }
+      if (test_regno >= regno && test_regno < endregno)
+       return 1;
     }
 
   if (GET_CODE (insn) == CALL_INSN
@@ -1194,7 +1316,7 @@ dead_or_set_regno_p (insn, test_regno)
       /* A value is totally replaced if it is the destination or the
         destination is a SUBREG of REGNO that does not change the number of
         words in it.  */
-     if (GET_CODE (dest) == SUBREG
+      if (GET_CODE (dest) == SUBREG
          && (((GET_MODE_SIZE (GET_MODE (dest))
                + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
              == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
@@ -1256,6 +1378,10 @@ find_reg_note (insn, kind, datum)
 {
   register rtx link;
 
+  /* Ignore anything that is not an INSN, JUMP_INSN or CALL_INSN.  */
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+    return 0;
+
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     if (REG_NOTE_KIND (link) == kind
        && (datum == 0 || datum == XEXP (link, 0)))
@@ -1276,6 +1402,10 @@ find_regno_note (insn, kind, regno)
 {
   register rtx link;
 
+  /* Ignore anything that is not an INSN, JUMP_INSN or CALL_INSN.  */
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+    return 0;
+
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     if (REG_NOTE_KIND (link) == kind
        /* Verify that it is a register, so that scratch and MEM won't cause a
@@ -1749,7 +1879,8 @@ inequality_comparisons_p (x)
   return 0;
 }
 \f
-/* Replace any occurrence of FROM in X with TO.
+/* Replace any occurrence of FROM in X with TO.  The function does
+   not enter into CONST_DOUBLE for the replace.
 
    Note that copying is not done so X must not be shared unless all copies
    are to be modified.  */
@@ -1761,6 +1892,11 @@ replace_rtx (x, from, to)
   register int i, j;
   register char *fmt;
 
+  /* The following prevents loops occurrence when we change MEM in
+     CONST_DOUBLE onto the same CONST_DOUBLE. */
+  if (x != 0 && GET_CODE (x) == CONST_DOUBLE)
+    return x;
+
   if (x == from)
     return to;
 
@@ -1993,3 +2129,133 @@ computed_jump_p (insn)
     }
   return 0;
 }
+
+/* Traverse X via depth-first search, calling F for each
+   sub-expression (including X itself).  F is also passed the DATA.
+   If F returns -1, do not traverse sub-expressions, but continue
+   traversing the rest of the tree.  If F ever returns any other
+   non-zero value, stop the traversal, and return the value returned
+   by F.  Otherwise, return 0.  This function does not traverse inside
+   tree structure that contains RTX_EXPRs, or into sub-expressions
+   whose format code is `0' since it is not known whether or not those
+   codes are actually RTL.
+
+   This routine is very general, and could (should?) be used to
+   implement many of the other routines in this file.  */
+
+int
+for_each_rtx (x, f, data)
+     rtx *x;
+     rtx_function f;
+     void *data;
+{
+  int result;
+  int length;
+  char* format;
+  int i;
+
+  /* Call F on X.  */
+  result = (*f)(x, data);
+  if (result == -1)
+    /* Do not traverse sub-expressions.  */
+    return 0;
+  else if (result != 0)
+    /* Stop the traversal.  */
+    return result;
+
+  if (*x == NULL_RTX)
+    /* There are no sub-expressions.  */
+    return 0;
+
+  length = GET_RTX_LENGTH (GET_CODE (*x));
+  format = GET_RTX_FORMAT (GET_CODE (*x));
+
+  for (i = 0; i < length; ++i) 
+    {
+      switch (format[i]) 
+       {
+       case 'e':
+         result = for_each_rtx (&XEXP (*x, i), f, data);
+         if (result != 0)
+           return result;
+         break;
+
+       case 'V':
+       case 'E':
+         if (XVEC (*x, i) != 0) 
+           {
+             int j;
+             for (j = 0; j < XVECLEN (*x, i); ++j)
+               {
+                 result = for_each_rtx (&XVECEXP (*x, i, j), f, data);
+                 if (result != 0)
+                   return result;
+               }
+           }
+         break; 
+
+       default:
+         /* Nothing to do.  */
+         break;
+       }
+
+    }
+
+  return 0;
+}
+
+/* Searches X for any reference to REGNO, returning the rtx of the
+   reference found if any.  Otherwise, returns NULL_RTX.  */
+
+rtx
+regno_use_in (regno, x)
+     int regno;
+     rtx x;
+{
+  register char *fmt;
+  int i, j;
+  rtx tem;
+
+  if (GET_CODE (x) == REG && REGNO (x) == regno)
+    return x;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         if ((tem = regno_use_in (regno, XEXP (x, i))))
+           return tem;
+       }
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         if ((tem = regno_use_in (regno , XVECEXP (x, i, j))))
+           return tem;
+    }
+
+  return NULL_RTX;
+}
+
+
+/* Return 1 if X is an autoincrement side effect and the register is
+   not the stack pointer.  */
+int
+auto_inc_p (x)
+     rtx x;
+{
+  switch (GET_CODE (x))
+    {
+    case PRE_INC:
+    case POST_INC:
+    case PRE_DEC:
+    case POST_DEC:
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      /* There are no REG_INC notes for SP.  */
+      if (XEXP (x, 0) != stack_pointer_rtx)
+       return 1;
+    default:
+      break;
+    }
+  return 0;
+}