OSDN Git Service

(c_sizeof, build_c_cast): Set TREE_OVERFLOW in addition
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index 9bdfd10..967526e 100644 (file)
@@ -91,11 +91,18 @@ static int *allocno_order;
 static int *allocno_size;
 
 /* Indexed by (pseudo) reg number, gives the number of another
-   lower-numbered pseudo reg which can share a hard reg with this peudo
+   lower-numbered pseudo reg which can share a hard reg with this pseudo
    *even if the two pseudos would otherwise appear to conflict*.  */
 
 static int *reg_may_share;
 
+/* Define the number of bits in each element of `conflicts' and what
+   type that element has.  We use the largest integer format on the
+   host machine.  */
+
+#define INT_BITS HOST_BITS_PER_WIDE_INT
+#define INT_TYPE HOST_WIDE_INT
+
 /* max_allocno by max_allocno array of bits,
    recording whether two allocno's conflict (can't go in the same
    hardware register).
@@ -103,7 +110,7 @@ static int *reg_may_share;
    `conflicts' is not symmetric; a conflict between allocno's i and j
    is recorded either in element i,j or in element j,i.  */
 
-static int *conflicts;
+static INT_TYPE *conflicts;
 
 /* Number of ints require to hold max_allocno bits.
    This is the length of a row in `conflicts'.  */
@@ -114,11 +121,11 @@ static int allocno_row_words;
 
 #define CONFLICTP(I, J) \
  (conflicts[(I) * allocno_row_words + (J) / INT_BITS]  \
-  & (1 << ((J) % INT_BITS)))
+  & ((INT_TYPE) 1 << ((J) % INT_BITS)))
 
 #define SET_CONFLICT(I, J) \
  (conflicts[(I) * allocno_row_words + (J) / INT_BITS]  \
-  |= (1 << ((J) % INT_BITS)))
+  |= ((INT_TYPE) 1 << ((J) % INT_BITS)))
 
 /* Set of hard regs currently live (during scan of all insns).  */
 
@@ -194,21 +201,19 @@ static int local_reg_live_length[FIRST_PSEUDO_REGISTER];
 
 /* Bit mask for allocnos live at current point in the scan.  */
 
-static int *allocnos_live;
-
-#define INT_BITS HOST_BITS_PER_INT
+static INT_TYPE *allocnos_live;
 
 /* Test, set or clear bit number I in allocnos_live,
    a bit vector indexed by allocno.  */
 
 #define ALLOCNO_LIVE_P(I) \
-  (allocnos_live[(I) / INT_BITS] & (1 << ((I) % INT_BITS)))
+  (allocnos_live[(I) / INT_BITS] & ((INT_TYPE) 1 << ((I) % INT_BITS)))
 
 #define SET_ALLOCNO_LIVE(I) \
-  (allocnos_live[(I) / INT_BITS] |= (1 << ((I) % INT_BITS)))
+  (allocnos_live[(I) / INT_BITS] |= ((INT_TYPE) 1 << ((I) % INT_BITS)))
 
 #define CLEAR_ALLOCNO_LIVE(I) \
-  (allocnos_live[(I) / INT_BITS] &= ~(1 << ((I) % INT_BITS)))
+  (allocnos_live[(I) / INT_BITS] &= ~((INT_TYPE) 1 << ((I) % INT_BITS)))
 
 /* This is turned off because it doesn't work right for DImode.
    (And it is only used for DImode, so the other cases are worthless.)
@@ -248,6 +253,7 @@ static HARD_REG_SET eliminable_regset;
 static int allocno_compare ();
 static void mark_reg_store ();
 static void mark_reg_clobber ();
+static void mark_reg_conflicts ();
 static void mark_reg_live_nc ();
 static void mark_reg_death ();
 static void dump_conflicts ();
@@ -261,9 +267,12 @@ static void set_preference ();
 \f
 /* Perform allocation of pseudo-registers not allocated by local_alloc.
    FILE is a file to output debugging information on,
-   or zero if such output is not desired.  */
+   or zero if such output is not desired.
 
-void
+   Return value is nonzero if reload failed
+   and we must not do any more for this function.  */
+
+int
 global_alloc (file)
      FILE *file;
 {
@@ -453,10 +462,12 @@ global_alloc (file)
 
   allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
 
-  conflicts = (int *) alloca (max_allocno * allocno_row_words * sizeof (int));
-  bzero (conflicts, max_allocno * allocno_row_words * sizeof (int));
+  conflicts = (INT_TYPE *) alloca (max_allocno * allocno_row_words
+                                  * sizeof (INT_TYPE));
+  bzero (conflicts, max_allocno * allocno_row_words
+        * sizeof (INT_TYPE));
 
-  allocnos_live = (int *) alloca (allocno_row_words * sizeof (int));
+  allocnos_live = (INT_TYPE *) alloca (allocno_row_words * sizeof (INT_TYPE));
 
   /* If there is work to be done (at least one reg to allocate),
      perform global conflict analysis and allocate the regs.  */
@@ -530,7 +541,7 @@ global_alloc (file)
                if (reg_renumber[allocno_reg[allocno_order[i]]] >= 0)
                  continue;
              }
-           if (!reg_preferred_or_nothing (allocno_reg[allocno_order[i]]))
+           if (reg_alternate_class (allocno_reg[allocno_order[i]]) != NO_REGS)
              find_reg (allocno_order[i], HARD_CONST (0), 1, 0, 0);
          }
     }
@@ -542,7 +553,7 @@ global_alloc (file)
         for the sake of debugging information.  */
   if (n_basic_blocks > 0)
 #endif
-    reload (basic_block_head[0], 1, file);
+    return reload (get_insns (), 1, file);
 }
 
 /* Sort predicate for ordering the allocnos.
@@ -589,7 +600,7 @@ global_conflicts ()
 
   for (b = 0; b < n_basic_blocks; b++)
     {
-      bzero (allocnos_live, allocno_row_words * sizeof (int));
+      bzero (allocnos_live, allocno_row_words * sizeof (INT_TYPE));
 
       /* Initialize table of registers currently live
         to the state at the beginning of this basic block.
@@ -605,7 +616,8 @@ global_conflicts ()
         are explicitly marked in basic_block_live_at_start.  */
 
       {
-       register int offset, bit;
+       register int offset;
+       REGSET_ELT_TYPE bit;
        register regset old = basic_block_live_at_start[b];
        int ax = 0;
 
@@ -616,7 +628,7 @@ global_conflicts ()
 #endif
        for (offset = 0, i = 0; offset < regset_size; offset++)
          if (old[offset] == 0)
-           i += HOST_BITS_PER_INT;
+           i += REGSET_ELT_BITS;
          else
            for (bit = 1; bit; bit <<= 1, i++)
              {
@@ -695,9 +707,34 @@ global_conflicts ()
 #ifdef AUTO_INC_DEC
              for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
                if (REG_NOTE_KIND (link) == REG_INC)
-                 mark_reg_store (XEXP (link, 0), 0);
+                 mark_reg_store (XEXP (link, 0), NULL_RTX);
 #endif
 
+             /* If INSN has multiple outputs, then any reg that dies here
+                and is used inside of an output
+                must conflict with the other outputs.  */
+
+             if (GET_CODE (PATTERN (insn)) == PARALLEL && !single_set (insn))
+               for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+                 if (REG_NOTE_KIND (link) == REG_DEAD)
+                   {
+                     int used_in_output = 0;
+                     int i;
+                     rtx reg = XEXP (link, 0);
+
+                     for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+                       {
+                         rtx set = XVECEXP (PATTERN (insn), 0, i);
+                         if (GET_CODE (set) == SET
+                             && GET_CODE (SET_DEST (set)) != REG
+                             && !rtx_equal_p (reg, SET_DEST (set))
+                             && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+                           used_in_output = 1;
+                       }
+                     if (used_in_output)
+                       mark_reg_conflicts (reg);
+                   }
+
              /* Mark any registers set in INSN and then never used.  */
 
              while (n_regs_set > 0)
@@ -778,7 +815,7 @@ prune_preferences ()
   /* Scan least most important to most important.
      For each allocno, remove from preferences registers that cannot be used,
      either because of conflicts or register type.  Then compute all registers
-     prefered by each lower-priority register that conflicts.  */
+     preferred by each lower-priority register that conflicts.  */
 
   for (i = max_allocno - 1; i >= 0; i--)
     {
@@ -828,8 +865,8 @@ prune_preferences ()
    LOSERS, if non-zero, is a HARD_REG_SET indicating registers that cannot
    be used for this allocation.
 
-   If ALL_REGS_P is zero, consider only the preferred class of ALLOCNO's reg.
-   Otherwise ignore that preferred class.
+   If ALT_REGS_P is zero, consider only the preferred class of ALLOCNO's reg.
+   Otherwise ignore that preferred class and use the alternate class.
 
    If ACCEPT_CALL_CLOBBERED is nonzero, accept a call-clobbered hard reg that
    will have to be saved and restored at calls.
@@ -840,10 +877,10 @@ prune_preferences ()
    If not, do nothing.  */
 
 static void
-find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
+find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
      int allocno;
      HARD_REG_SET losers;
-     int all_regs_p;
+     int alt_regs_p;
      int accept_call_clobbered;
      int retrying;
 {
@@ -853,8 +890,9 @@ find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
 #endif
     HARD_REG_SET used, used1, used2;
 
-  enum reg_class class 
-    = all_regs_p ? ALL_REGS : reg_preferred_class (allocno_reg[allocno]);
+  enum reg_class class = (alt_regs_p
+                         ? reg_alternate_class (allocno_reg[allocno])
+                         : reg_preferred_class (allocno_reg[allocno]));
   enum machine_mode mode = PSEUDO_REGNO_MODE (allocno_reg[allocno]);
 
   if (accept_call_clobbered)
@@ -875,7 +913,7 @@ find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
   IOR_HARD_REG_SET (used1, hard_reg_conflicts[allocno]);
 
   /* Try each hard reg to see if it fits.  Do this in two passes.
-     In the first pass, skip registers that are prefered by some other pseudo
+     In the first pass, skip registers that are preferred by some other pseudo
      to give it a better chance of getting one of those registers.  Only if
      we can't get a register when excluding those do we take one of them.
      However, we never allocate a register for the first time in pass 0.  */
@@ -1002,7 +1040,11 @@ find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
     }
  no_prefs:
 
-  /* If we haven't succeeded yet, try with caller-saves.  */
+  /* If we haven't succeeded yet, try with caller-saves. 
+     We need not check to see if the current function has nonlocal
+     labels because we don't put any pseudos that are live over calls in
+     registers in that case.  */
+
   if (flag_caller_saves && best_reg < 0)
     {
       /* Did not find a register.  If it would be profitable to
@@ -1013,7 +1055,7 @@ find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
          && CALLER_SAVE_PROFITABLE (allocno_n_refs[allocno],
                                     allocno_calls_crossed[allocno]))
        {
-         find_reg (allocno, losers, all_regs_p, 1, retrying);
+         find_reg (allocno, losers, alt_regs_p, 1, retrying);
          if (reg_renumber[allocno_reg[allocno]] >= 0)
            {
              caller_save_needed = 1;
@@ -1117,7 +1159,7 @@ retry_global_alloc (regno, forbidden_regs)
       if (N_REG_CLASSES > 1)
        find_reg (allocno, forbidden_regs, 0, 0, 1);
       if (reg_renumber[regno] < 0
-         && !reg_preferred_or_nothing (regno))
+         && reg_alternate_class (regno) != NO_REGS)
        find_reg (allocno, forbidden_regs, 1, 0, 1);
 
       /* If we found a register, modify the RTL for the register to
@@ -1334,6 +1376,45 @@ mark_reg_clobber (reg, setter)
        }
     }
 }
+
+/* Record that REG has conflicts with all the regs currently live.
+   Do not mark REG itself as live.  */
+
+static void
+mark_reg_conflicts (reg)
+     rtx reg;
+{
+  register int regno;
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (GET_CODE (reg) != REG)
+    return;
+
+  regno = REGNO (reg);
+
+  if (reg_renumber[regno] >= 0)
+    regno = reg_renumber[regno];
+
+  /* Either this is one of the max_allocno pseudo regs not allocated,
+     or it is or has a hardware reg.  First handle the pseudo-regs.  */
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      if (reg_allocno[regno] >= 0)
+       record_one_conflict (regno);
+    }
+  /* Handle hardware regs (and pseudos allocated to hard regs).  */
+  else if (! fixed_regs[regno])
+    {
+      register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      while (regno < last)
+       {
+         record_one_conflict (regno);
+         regno++;
+       }
+    }
+}
 \f
 /* Mark REG as being dead (following the insn being scanned now).
    Store a 0 in regs_live or allocnos_live for this register.  */
@@ -1393,7 +1474,7 @@ mark_reg_live_nc (regno, mode)
    try to set a preference.  If one of the two is a hard register and the other
    is a pseudo-register, mark the preference.
    
-   Note that we are not as agressive as local-alloc in trying to tie a
+   Note that we are not as aggressive as local-alloc in trying to tie a
    pseudo-register to a hard register.  */
 
 static void
@@ -1495,13 +1576,13 @@ mark_elimination (from, to)
   int i;
 
   for (i = 0; i < n_basic_blocks; i++)
-    if ((basic_block_live_at_start[i][from / HOST_BITS_PER_INT]
-        & (1 << (from % HOST_BITS_PER_INT))) != 0)
+    if ((basic_block_live_at_start[i][from / REGSET_ELT_BITS]
+        & ((REGSET_ELT_TYPE) 1 << (from % REGSET_ELT_BITS))) != 0)
       {
-       basic_block_live_at_start[i][from / HOST_BITS_PER_INT]
-         &= ~ (1 << (from % HOST_BITS_PER_INT));
-       basic_block_live_at_start[i][to / HOST_BITS_PER_INT]
-         |= (1 << (to % HOST_BITS_PER_INT));
+       basic_block_live_at_start[i][from / REGSET_ELT_BITS]
+         &= ~ ((REGSET_ELT_TYPE) 1 << (from % REGSET_ELT_BITS));
+       basic_block_live_at_start[i][to / REGSET_ELT_BITS]
+         |= ((REGSET_ELT_TYPE) 1 << (to % REGSET_ELT_BITS));
       }
 }
 \f