OSDN Git Service

Update.
[pf3gnuchains/gcc-fork.git] / gcc / stupid.c
index f8fc9d9..d064f97 100644 (file)
@@ -1,5 +1,5 @@
 /* Dummy data flow analysis for GNU compiler in nonoptimizing mode.
-   Copyright (C) 1987, 1991, 1994, 1995, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 91, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -22,7 +22,7 @@ Boston, MA 02111-1307, USA.  */
 /* This file performs stupid register allocation, which is used
    when cc1 gets the -noreg switch (which is when cc does not get -O).
 
-   Stupid register allocation goes in place of the the flow_analysis,
+   Stupid register allocation goes in place of the flow_analysis,
    local_alloc and global_alloc passes.  combine_instructions cannot
    be done with stupid allocation because the data flow info that it needs
    is not computed here.
@@ -42,8 +42,9 @@ Boston, MA 02111-1307, USA.  */
    pseudo reg is computed.  Then the pseudo regs are ordered by priority
    and assigned hard regs in priority order.  */
 
-#include <stdio.h>
 #include "config.h"
+#include "system.h"
+
 #include "rtl.h"
 #include "hard-reg-set.h"
 #include "regs.h"
@@ -106,7 +107,7 @@ static HARD_REG_SET *after_insn_hard_regs;
 #define MARK_LIVE_AFTER(INSN,REGNO)  \
   SET_HARD_REG_BIT (after_insn_hard_regs[INSN_SUID (INSN)], (REGNO))
 
-static int stupid_reg_compare  PROTO((int *, int *));
+static int stupid_reg_compare  PROTO((const GENERIC_PTR,const GENERIC_PTR));
 static int stupid_find_reg     PROTO((int, enum reg_class, enum machine_mode,
                                       int, int, int));
 static void stupid_mark_refs   PROTO((rtx, rtx));
@@ -129,6 +130,8 @@ stupid_life_analysis (f, nregs, file)
   register rtx last, insn;
   int max_uid, max_suid;
 
+  current_function_has_computed_jump = 0;
+
   bzero (regs_ever_live, sizeof regs_ever_live);
 
   regs_live = (char *) alloca (nregs);
@@ -179,13 +182,11 @@ stupid_life_analysis (f, nregs, file)
   regs_crosses_setjmp = (char *) alloca (nregs * sizeof (char));
   bzero ((char *) regs_crosses_setjmp, nregs * sizeof (char));
 
-  reg_renumber = (short *) oballoc (nregs * sizeof (short));
+  /* Allocate the reg_renumber array */
+  allocate_reg_info (max_regno, FALSE, TRUE);
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     reg_renumber[i] = i;
 
-  for (i = FIRST_VIRTUAL_REGISTER; i < max_regno; i++)
-    reg_renumber[i] = -1;
-
   after_insn_hard_regs
     = (HARD_REG_SET *) alloca (max_suid * sizeof (HARD_REG_SET));
 
@@ -197,7 +198,7 @@ stupid_life_analysis (f, nregs, file)
   allocate_for_life_analysis ();
 
   for (i = 0; i < max_regno; i++)
-    reg_n_deaths[i] = 1;
+    REG_N_DEATHS (i) = 1;
 
   bzero (regs_live, nregs);
 
@@ -232,27 +233,42 @@ stupid_life_analysis (f, nregs, file)
          && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
        last_setjmp_suid = INSN_SUID (insn);
 
-      /* Mark all call-clobbered regs as live after each call insn
-        so that a pseudo whose life span includes this insn
-        will not go in one of them.
+      /* Mark all call-clobbered regs as dead after each call insn so that
+        a pseudo whose life span includes this insn will not go in one of
+        them.  If the function contains a non-local goto, mark all hard
+        registers dead (except for stack related bits).
+
         Then mark those regs as all dead for the continuing scan
         of the insns before the call.  */
 
       if (GET_CODE (insn) == CALL_INSN)
        {
          last_call_suid = INSN_SUID (insn);
-         IOR_HARD_REG_SET (after_insn_hard_regs[last_call_suid],
-                           call_used_reg_set);
 
-         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-           if (call_used_regs[i])
-             regs_live[i] = 0;
+         if (current_function_has_nonlocal_label)
+           {
+             IOR_COMPL_HARD_REG_SET (after_insn_hard_regs[last_call_suid],
+                                     fixed_reg_set);
+             for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+               if (! fixed_regs[i])
+                 regs_live[i] = 0;
+           }
+         else
+           {
+             IOR_HARD_REG_SET (after_insn_hard_regs[last_call_suid],
+                               call_used_reg_set);
+             for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+               if (call_used_regs[i])
+                 regs_live[i] = 0;
+           }
 
          /* It is important that this be done after processing the insn's
             pattern because we want the function result register to still
             be live if it's also used to pass arguments.  */
          stupid_mark_refs (CALL_INSN_FUNCTION_USAGE (insn), insn);
        }
+      if (GET_CODE (insn) == JUMP_INSN && computed_jump_p (insn))
+       current_function_has_computed_jump = 1;
     }
 
   /* Now decide the order in which to allocate the pseudo registers.  */
@@ -271,13 +287,16 @@ stupid_life_analysis (f, nregs, file)
       register int r = reg_order[i];
 
       /* Some regnos disappear from the rtl.  Ignore them to avoid crash. 
-        Also don't allocate registers that cross a setjmp.  */
-      if (regno_reg_rtx[r] == 0 || regs_crosses_setjmp[r])
+        Also don't allocate registers that cross a setjmp, or live across
+        a call if this function receives a nonlocal goto.  */
+      if (regno_reg_rtx[r] == 0 || regs_crosses_setjmp[r]
+         || (REG_N_CALLS_CROSSED (r) > 0 
+             && current_function_has_nonlocal_label))
        continue;
 
       /* Now find the best hard-register class for this pseudo register */
       if (N_REG_CLASSES > 1)
-       reg_renumber[r] = stupid_find_reg (reg_n_calls_crossed[r]
+       reg_renumber[r] = stupid_find_reg (REG_N_CALLS_CROSSED (r)
                                           reg_preferred_class (r),
                                           PSEUDO_REGNO_MODE (r),
                                           reg_where_born[r],
@@ -286,7 +305,7 @@ stupid_life_analysis (f, nregs, file)
 
       /* If no reg available in that class, try alternate class.  */
       if (reg_renumber[r] == -1 && reg_alternate_class (r) != NO_REGS)
-       reg_renumber[r] = stupid_find_reg (reg_n_calls_crossed[r],
+       reg_renumber[r] = stupid_find_reg (REG_N_CALLS_CROSSED (r),
                                           reg_alternate_class (r),
                                           PSEUDO_REGNO_MODE (r),
                                           reg_where_born[r],
@@ -303,9 +322,10 @@ stupid_life_analysis (f, nregs, file)
 
 static int
 stupid_reg_compare (r1p, r2p)
-     int *r1p, *r2p;
+     const GENERIC_PTR r1p;
+     const GENERIC_PTR r2p;
 {
-  register int r1 = *r1p, r2 = *r2p;
+  register int r1 = *(int *)r1p, r2 = *(int *)r2p;
   register int len1 = reg_where_dead[r1] - reg_where_born[r1];
   register int len2 = reg_where_dead[r2] - reg_where_born[r2];
   int tem;
@@ -314,7 +334,7 @@ stupid_reg_compare (r1p, r2p)
   if (tem != 0)
     return tem;
 
-  tem = reg_n_refs[r1] - reg_n_refs[r2];
+  tem = REG_N_REFS (r1) - REG_N_REFS (r2);
   if (tem != 0)
     return tem;
 
@@ -356,7 +376,7 @@ stupid_find_reg (call_preserved, class, mode,
 #endif
 
   /* If this register's life is more than 5,000 insns, we probably
-     can't allocate it, so don't waste the time trying.  This avoid
+     can't allocate it, so don't waste the time trying.  This avoids
      quadratic behavior on programs that have regularly-occurring
      SAVE_EXPRs.  */
   if (dead_insn > born_insn + 5000)
@@ -378,6 +398,12 @@ stupid_find_reg (call_preserved, class, mode,
   for (ins = born_insn; ins < dead_insn; ins++)
     IOR_HARD_REG_SET (used, after_insn_hard_regs[ins]);
 
+#ifdef STACK_REGS
+  if (current_function_has_computed_jump)
+    for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
+      SET_HARD_REG_BIT (used, i);
+#endif
+  
   IOR_COMPL_HARD_REG_SET (used, reg_class_contents[(int) class]);
 
 #ifdef CLASS_CANNOT_CHANGE_SIZE
@@ -508,13 +534,27 @@ stupid_mark_refs (x, insn)
                }
 
              /* Count the refs of this reg.  */
-             reg_n_refs[regno]++;
+             REG_N_REFS (regno)++;
 
              if (last_call_suid < reg_where_dead[regno])
-               reg_n_calls_crossed[regno] += 1;
+               REG_N_CALLS_CROSSED (regno) += 1;
 
              if (last_setjmp_suid < reg_where_dead[regno])
                regs_crosses_setjmp[regno] = 1;
+
+             /* If this register is only used in this insn and is only
+                set, mark it unused.  We have to do this even when not 
+                optimizing so that MD patterns which count on this
+                behavior (e.g., it not causing an output reload on
+                an insn setting CC) will operate correctly.  */
+             if (GET_CODE (SET_DEST (x)) == REG
+                 && REGNO_FIRST_UID (regno) == INSN_UID (insn)
+                 && REGNO_LAST_UID (regno) == INSN_UID (insn)
+                 && (code == CLOBBER || ! reg_mentioned_p (SET_DEST (x),
+                                                           SET_SRC (x))))
+               REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
+                                                     SET_DEST (x),
+                                                     REG_NOTES (insn));
            }
        }
 
@@ -559,7 +599,7 @@ stupid_mark_refs (x, insn)
          /* Pseudo reg: record first use, last use and number of uses.  */
 
          reg_where_born[regno] = INSN_SUID (insn);
-         reg_n_refs[regno]++;
+         REG_N_REFS (regno)++;
          if (regs_live[regno] == 0)
            {
              regs_live[regno] = 1;