OSDN Git Service

* config/alpha/alpha.c (alpha_emit_floatuns): Ensure we pass a REG
[pf3gnuchains/gcc-fork.git] / gcc / rtlanal.c
index 573bed0..d9087cd 100644 (file)
@@ -1,5 +1,6 @@
 /* Analyze RTL for C-Compiler
-   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -23,13 +24,13 @@ Boston, MA 02111-1307, USA.  */
 #include "system.h"
 #include "rtl.h"
 
-static int rtx_addr_can_trap_p PROTO((rtx));
-static void reg_set_p_1                PROTO((rtx, rtx, void *));
-static void reg_set_last_1     PROTO((rtx, rtx, void *));
+static int rtx_addr_can_trap_p PARAMS ((rtx));
+static void reg_set_p_1                PARAMS ((rtx, rtx, void *));
+static void reg_set_last_1     PARAMS ((rtx, rtx, void *));
 
 
 /* Forward declarations */
-static int jmp_uses_reg_or_mem         PROTO((rtx));
+static int jmp_uses_reg_or_mem         PARAMS ((rtx));
 
 /* Bit flags that specify the machine subtype we are compiling for.
    Bits are tested using macros TARGET_... defined in the tm.h file
@@ -403,6 +404,7 @@ reg_referenced_p (x, body)
 
     case CALL:
     case USE:
+    case IF_THEN_ELSE:
       return reg_overlap_mentioned_p (x, body);
 
     case TRAP_IF:
@@ -421,6 +423,17 @@ reg_referenced_p (x, body)
          return 1;
       return 0;
       
+    case CLOBBER:
+      if (GET_CODE (XEXP (body, 0)) == MEM)
+       if (reg_overlap_mentioned_p (x, XEXP (XEXP (body, 0), 0)))
+         return 1;
+      return 0;
+
+    case COND_EXEC:
+      if (reg_overlap_mentioned_p (x, COND_EXEC_TEST (body)))
+       return 1;
+      return reg_referenced_p (x, COND_EXEC_CODE (body));
+
     default:
       return 0;
     }
@@ -611,7 +624,7 @@ modified_between_p (x, start, end)
       if (fmt[i] == 'e' && modified_between_p (XEXP (x, i), start, end))
        return 1;
 
-      if (fmt[i] == 'E')
+      else if (fmt[i] == 'E')
        for (j = XVECLEN (x, i) - 1; j >= 0; j--)
          if (modified_between_p (XVECEXP (x, i, j), start, end))
            return 1;
@@ -666,7 +679,7 @@ modified_in_p (x, insn)
       if (fmt[i] == 'e' && modified_in_p (XEXP (x, i), insn))
        return 1;
 
-      if (fmt[i] == 'E')
+      else if (fmt[i] == 'E')
        for (j = XVECLEN (x, i) - 1; j >= 0; j--)
          if (modified_in_p (XVECEXP (x, i, j), insn))
            return 1;
@@ -695,16 +708,30 @@ single_set (insn)
   else if (GET_CODE (PATTERN (insn)) == PARALLEL)
     {
       for (i = 0, set = 0; i < XVECLEN (PATTERN (insn), 0); i++)
-       if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
-           && (! find_reg_note (insn, REG_UNUSED,
-                                SET_DEST (XVECEXP (PATTERN (insn), 0, i)))
-               || side_effects_p (XVECEXP (PATTERN (insn), 0, i))))
-         {
-           if (set)
+       {
+         rtx sub = XVECEXP (PATTERN (insn), 0, i);
+
+         switch (GET_CODE (sub))
+           {
+           case USE:
+           case CLOBBER:
+             break;
+
+           case SET:
+             if (! find_reg_note (insn, REG_UNUSED, SET_DEST (sub))
+                 || side_effects_p (sub))
+               {
+                 if (set)
+                   return 0;
+                 else
+                   set = sub;
+               }
+             break;
+
+           default:
              return 0;
-           else
-             set = XVECEXP (PATTERN (insn), 0, i);
-         }
+           }
+       }
       return set;
     }
   
@@ -743,11 +770,12 @@ multiple_sets (insn)
   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.  
-   ALLOW_HWREG is set to 1 if hardware registers are allowed to be the src.  */
+/* Return the last thing that X was assigned from before *PINSN.  If VALID_TO
+   is not NULL_RTX then verify that the object is not modified up to VALID_TO.
+   If the object was modified, 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.  ALLOW_HWREG is set to 1 if hardware registers are allowed to
+   be the src.  */
 
 rtx
 find_last_value (x, pinsn, valid_to, allow_hwreg)
@@ -772,7 +800,8 @@ find_last_value (x, pinsn, valid_to, allow_hwreg)
            if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
              src = XEXP (note, 0);
 
-           if (! modified_between_p (src, PREV_INSN (p), valid_to)
+           if ((valid_to == NULL_RTX
+                || ! 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
@@ -800,13 +829,14 @@ find_last_value (x, pinsn, valid_to, allow_hwreg)
 
 int
 refers_to_regno_p (regno, endregno, x, loc)
-     int regno, endregno;
+     unsigned int regno, endregno;
      rtx x;
      rtx *loc;
 {
-  register int i;
-  register RTX_CODE code;
-  register const char *fmt;
+  int i;
+  unsigned int x_regno;
+  RTX_CODE code;
+  const char *fmt;
 
  repeat:
   /* The contents of a REG_NONNEG note is always zero, so we must come here
@@ -819,22 +849,22 @@ refers_to_regno_p (regno, endregno, x, loc)
   switch (code)
     {
     case REG:
-      i = REGNO (x);
+      x_regno = REGNO (x);
 
       /* If we modifying the stack, frame, or argument pointer, it will
         clobber a virtual register.  In fact, we could be more precise,
         but it isn't worth it.  */
-      if ((i == STACK_POINTER_REGNUM
+      if ((x_regno == STACK_POINTER_REGNUM
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-          || i == ARG_POINTER_REGNUM
+          || x_regno == ARG_POINTER_REGNUM
 #endif
-          || i == FRAME_POINTER_REGNUM)
+          || x_regno == FRAME_POINTER_REGNUM)
          && regno >= FIRST_VIRTUAL_REGISTER && regno <= LAST_VIRTUAL_REGISTER)
        return 1;
 
-      return (endregno > i
-             && regno < i + (i < FIRST_PSEUDO_REGISTER 
-                             ? HARD_REGNO_NREGS (i, GET_MODE (x))
+      return (endregno > x_regno
+             && regno < x_regno + (x_regno < FIRST_PSEUDO_REGISTER 
+                                   ? HARD_REGNO_NREGS (x_regno, GET_MODE (x))
                              : 1));
 
     case SUBREG:
@@ -843,8 +873,8 @@ refers_to_regno_p (regno, endregno, x, loc)
       if (GET_CODE (SUBREG_REG (x)) == REG
          && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
        {
-         int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
-         int inner_endregno
+         unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+         unsigned int inner_endregno
            = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
                             ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
 
@@ -915,7 +945,7 @@ int
 reg_overlap_mentioned_p (x, in)
      rtx x, in;
 {
-  int regno, endregno;
+  unsigned int regno, endregno;
 
   /* Overly conservative.  */
   if (GET_CODE (x) == STRICT_LOW_PART)
@@ -924,59 +954,68 @@ reg_overlap_mentioned_p (x, in)
   /* 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)
+
+  switch (GET_CODE (x))
     {
+    case SUBREG:
       regno = REGNO (SUBREG_REG (x));
       if (regno < FIRST_PSEUDO_REGISTER)
        regno += SUBREG_WORD (x);
-    }
-  else if (GET_CODE (x) == REG)
-    regno = REGNO (x);
-  else if (GET_CODE (x) == MEM)
-    {
-      const char *fmt;
-      int i;
+      goto do_reg;
 
-      if (GET_CODE (in) == MEM)
-       return 1;
+    case REG:
+      regno = REGNO (x);
+    do_reg:
+      endregno = regno + (regno < FIRST_PSEUDO_REGISTER
+                         ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+      return refers_to_regno_p (regno, endregno, in, NULL_PTR);
 
-      fmt = GET_RTX_FORMAT (GET_CODE (in));
+    case MEM:
+      {
+       const char *fmt;
+       int i;
 
-      for (i = GET_RTX_LENGTH (GET_CODE (in)) - 1; i >= 0; i--)
-       if (fmt[i] == 'e' && reg_overlap_mentioned_p (x, XEXP (in, i)))
+       if (GET_CODE (in) == MEM)
          return 1;
 
-      return 0;
-    }
-  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;
+       fmt = GET_RTX_FORMAT (GET_CODE (in));
+       for (i = GET_RTX_LENGTH (GET_CODE (in)) - 1; i >= 0; i--)
+         if (fmt[i] == 'e' && reg_overlap_mentioned_p (x, XEXP (in, i)))
+           return 1;
 
-      /* 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 ();
+       return 0;
+      }
+
+    case SCRATCH:
+    case PC:
+    case CC0:
+      return reg_mentioned_p (x, in);
+
+    case PARALLEL:
+      if (GET_MODE (x) == BLKmode)
+       {
+         register int i;
 
-  endregno = regno + (regno < FIRST_PSEUDO_REGISTER
-                     ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+         /* 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;
+       }
+      break;
 
-  return refers_to_regno_p (regno, endregno, in, NULL_PTR);
+    default:
+      break;
+    }
+
+  abort ();
 }
 \f
 /* Used for communications between the next few functions.  */
 
 static int reg_set_last_unknown;
 static rtx reg_set_last_value;
-static int reg_set_last_first_regno, reg_set_last_last_regno;
+static unsigned int reg_set_last_first_regno, reg_set_last_last_regno;
 
 /* Called via note_stores from reg_set_last.  */
 
@@ -986,7 +1025,7 @@ reg_set_last_1 (x, pat, data)
      rtx pat;
      void *data ATTRIBUTE_UNUSED;
 {
-  int first, last;
+  unsigned int first, last;
 
   /* If X is not a register, or is not one in the range we care
      about, ignore.  */
@@ -1068,114 +1107,6 @@ reg_set_last (x, insn)
   return 0;
 }
 \f
-/* This is 1 until after the rtl generation pass.  */
-int rtx_equal_function_value_matters;
-
-/* Return 1 if X and Y are identical-looking rtx's.
-   This is the Lisp function EQUAL for rtx arguments.  */
-
-int
-rtx_equal_p (x, y)
-     rtx x, y;
-{
-  register int i;
-  register int j;
-  register enum rtx_code code;
-  register const char *fmt;
-
-  if (x == y)
-    return 1;
-  if (x == 0 || y == 0)
-    return 0;
-
-  code = GET_CODE (x);
-  /* Rtx's of different codes cannot be equal.  */
-  if (code != GET_CODE (y))
-    return 0;
-
-  /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
-     (REG:SI x) and (REG:HI x) are NOT equivalent.  */
-
-  if (GET_MODE (x) != GET_MODE (y))
-    return 0;
-
-  /* REG, LABEL_REF, and SYMBOL_REF can be compared nonrecursively.  */
-
-  if (code == REG)
-    /* Until rtl generation is complete, don't consider a reference to the
-       return register of the current function the same as the return from a
-       called function.  This eases the job of function integration.  Once the
-       distinction is no longer needed, they can be considered equivalent.  */
-    return (REGNO (x) == REGNO (y)
-           && (! rtx_equal_function_value_matters
-               || REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y)));
-  else if (code == LABEL_REF)
-    return XEXP (x, 0) == XEXP (y, 0);
-  else if (code == SYMBOL_REF)
-    return XSTR (x, 0) == XSTR (y, 0);
-  else if (code == SCRATCH || code == CONST_DOUBLE)
-    return 0;
-
-  /* Compare the elements.  If any pair of corresponding elements
-     fail to match, return 0 for the whole things.  */
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      switch (fmt[i])
-       {
-       case 'w':
-         if (XWINT (x, i) != XWINT (y, i))
-           return 0;
-         break;
-
-       case 'n':
-       case 'i':
-         if (XINT (x, i) != XINT (y, i))
-           return 0;
-         break;
-
-       case 'V':
-       case 'E':
-         /* Two vectors must have the same length.  */
-         if (XVECLEN (x, i) != XVECLEN (y, i))
-           return 0;
-
-         /* And the corresponding elements must match.  */
-         for (j = 0; j < XVECLEN (x, i); j++)
-           if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
-             return 0;
-         break;
-
-       case 'e':
-         if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
-           return 0;
-         break;
-
-       case 'S':
-       case 's':
-         if (strcmp (XSTR (x, i), XSTR (y, i)))
-           return 0;
-         break;
-
-       case 'u':
-         /* These are just backpointers, so they don't matter.  */
-         break;
-
-       case '0':
-       case 't':
-         break;
-
-         /* It is believed that rtx's at this level will never
-            contain anything but integers and other rtx's,
-            except for within LABEL_REFs and SYMBOL_REFs.  */
-       default:
-         abort ();
-       }
-    }
-  return 1;
-}
-\f
 /* Call FUN on each register or MEM that is stored into or clobbered by X.
    (X would be the pattern of an insn).
    FUN receives two arguments:
@@ -1188,10 +1119,12 @@ rtx_equal_p (x, y)
 void
 note_stores (x, fun, data)
      register rtx x;
-     void (*fun) PROTO ((rtx, rtx, void *));
+     void (*fun) PARAMS ((rtx, rtx, void *));
      void *data;
 {
-  if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER))
+  if (GET_CODE (x) == COND_EXEC)
+    x = COND_EXEC_CODE (x);
+  if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
     {
       register rtx dest = SET_DEST (x);
       while ((GET_CODE (dest) == SUBREG
@@ -1218,6 +1151,8 @@ note_stores (x, fun, data)
       for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
        {
          register rtx y = XVECEXP (x, 0, i);
+         if (GET_CODE (y) == COND_EXEC)
+           y = COND_EXEC_CODE (y);
          if (GET_CODE (y) == SET || GET_CODE (y) == CLOBBER)
            {
              register rtx dest = SET_DEST (y);
@@ -1233,6 +1168,7 @@ note_stores (x, fun, data)
                  && GET_MODE (dest) == BLKmode)
                {
                  register int i;
+
                  for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
                    (*fun) (SET_DEST (XVECEXP (dest, 0, i)), y, data);
                }
@@ -1265,8 +1201,8 @@ dead_or_set_p (insn, x)
      rtx insn;
      rtx x;
 {
-  register int regno, last_regno;
-  register int i;
+  unsigned int regno, last_regno;
+  unsigned int i;
 
   /* Can't use cc0_rtx below since this file is used by genattrtab.c.  */
   if (GET_CODE (x) == CC0)
@@ -1292,10 +1228,10 @@ dead_or_set_p (insn, x)
 int
 dead_or_set_regno_p (insn, test_regno)
      rtx insn;
-     int test_regno;
+     unsigned int test_regno;
 {
-  int regno, endregno;
-  rtx link;
+  unsigned int regno, endregno;
+  rtx link, pattern;
 
   /* See if there is a death note for something that includes
      TEST_REGNO.  */
@@ -1318,7 +1254,12 @@ dead_or_set_regno_p (insn, test_regno)
       && find_regno_fusage (insn, CLOBBER, test_regno))
     return 1;
 
-  if (GET_CODE (PATTERN (insn)) == SET)
+  pattern = PATTERN (insn);
+
+  if (GET_CODE (pattern) == COND_EXEC)
+    pattern = COND_EXEC_CODE (pattern);
+
+  if (GET_CODE (pattern) == SET)
     {
       rtx dest = SET_DEST (PATTERN (insn));
  
@@ -1341,13 +1282,16 @@ dead_or_set_regno_p (insn, test_regno)
 
       return (test_regno >= regno && test_regno < endregno);
     }
-  else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+  else if (GET_CODE (pattern) == PARALLEL)
     {
       register int i;
 
-      for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+      for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
        {
-         rtx body = XVECEXP (PATTERN (insn), 0, i);
+         rtx body = XVECEXP (pattern, 0, i);
+
+         if (GET_CODE (body) == COND_EXEC)
+           body = COND_EXEC_CODE (body);
 
          if (GET_CODE (body) == SET || GET_CODE (body) == CLOBBER)
            {
@@ -1407,7 +1351,7 @@ rtx
 find_regno_note (insn, kind, regno)
      rtx insn;
      enum reg_note kind;
-     int regno;
+     unsigned int regno;
 {
   register rtx link;
 
@@ -1460,15 +1404,16 @@ find_reg_fusage (insn, code, datum)
     }
   else
     {
-      register int regno = REGNO (datum);
+      unsigned int regno = REGNO (datum);
 
       /* CALL_INSN_FUNCTION_USAGE information cannot contain references
         to pseudo registers, so don't bother checking.  */
 
       if (regno < FIRST_PSEUDO_REGISTER)
         {
-         int end_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (datum));
-         int i;
+         unsigned int end_regno
+           = regno + HARD_REGNO_NREGS (regno, GET_MODE (datum));
+         unsigned int i;
 
          for (i = regno; i < end_regno; i++)
            if (find_regno_fusage (insn, code, i))
@@ -1486,7 +1431,7 @@ int
 find_regno_fusage (insn, code, regno)
      rtx insn;
      enum rtx_code code;
-     int regno;
+     unsigned int regno;
 {
   register rtx link;
 
@@ -1499,8 +1444,8 @@ find_regno_fusage (insn, code, regno)
 
   for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
     {
-      register int regnote;
-      register rtx op, reg;
+      unsigned int regnote;
+      rtx op, reg;
 
       if (GET_CODE (op = XEXP (link, 0)) == code
          && GET_CODE (reg = XEXP (op, 0)) == REG
@@ -1626,7 +1571,7 @@ volatile_insn_p (x)
            if (volatile_insn_p (XEXP (x, i)))
              return 1;
          }
-       if (fmt[i] == 'E')
+       else if (fmt[i] == 'E')
          {
            register int j;
            for (j = 0; j < XVECLEN (x, i); j++)
@@ -1692,7 +1637,7 @@ volatile_refs_p (x)
            if (volatile_refs_p (XEXP (x, i)))
              return 1;
          }
-       if (fmt[i] == 'E')
+       else if (fmt[i] == 'E')
          {
            register int j;
            for (j = 0; j < XVECLEN (x, i); j++)
@@ -1767,7 +1712,7 @@ side_effects_p (x)
            if (side_effects_p (XEXP (x, i)))
              return 1;
          }
-       if (fmt[i] == 'E')
+       else if (fmt[i] == 'E')
          {
            register int j;
            for (j = 0; j < XVECLEN (x, i); j++)
@@ -1973,7 +1918,7 @@ rtx
 replace_regs (x, reg_map, nregs, replace_dest)
      rtx x;
      rtx *reg_map;
-     int nregs;
+     unsigned int nregs;
      int replace_dest;
 {
   register enum rtx_code code;
@@ -2066,7 +2011,7 @@ replace_regs (x, reg_map, nregs, replace_dest)
     {
       if (fmt[i] == 'e')
        XEXP (x, i) = replace_regs (XEXP (x, i), reg_map, nregs, replace_dest);
-      if (fmt[i] == 'E')
+      else if (fmt[i] == 'E')
        {
          register int j;
          for (j = 0; j < XVECLEN (x, i); j++)
@@ -2121,7 +2066,7 @@ jmp_uses_reg_or_mem (x)
          && jmp_uses_reg_or_mem (XEXP (x, i)))
        return 1;
 
-      if (fmt[i] == 'E')
+      else if (fmt[i] == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
          if (jmp_uses_reg_or_mem (XVECEXP (x, i, j)))
            return 1;
@@ -2249,7 +2194,7 @@ for_each_rtx (x, f, data)
 
 rtx
 regno_use_in (regno, x)
-     int regno;
+     unsigned int regno;
      rtx x;
 {
   register const char *fmt;