OSDN Git Service

2009-01-03 Paul Thomas <pault@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index b71bf41..824fcf0 100644 (file)
@@ -63,26 +63,41 @@ along with GCC; see the file COPYING3.  If not see
    reg numbers to allocnos and vice versa.
    max_allocno gets the number of allocnos in use.
 
-   2. Allocate a max_allocno by max_allocno conflict bit matrix and
-   clear it.  This is called "conflict".
+   2. Allocate a max_allocno by max_allocno compressed triangular conflict
+   bit matrix (a triangular bit matrix with portions removed for which we
+   can guarantee there are no conflicts, example: two local pseudos that
+   live in different basic blocks) and clear it.  This is called "conflict".
+   Note that for triangular bit matrices, there are two possible equations
+   for computing the bit number for two allocnos: LOW and HIGH (LOW < HIGH):
+
+     1) BITNUM = f(HIGH) + LOW, where
+       f(HIGH) = (HIGH * (HIGH - 1)) / 2
+
+     2) BITNUM = f(LOW) + HIGH, where
+       f(LOW) = LOW * (max_allocno - LOW) + (LOW * (LOW - 1)) / 2 - LOW - 1
+
+   We use the second (and less common) equation as this gives us better
+   cache locality for local allocnos that are live within the same basic
+   block.  Also note that f(HIGH) and f(LOW) can be precalculated for all
+   values of HIGH and LOW, so all that is necessary to compute the bit
+   number for two allocnos LOW and HIGH is a load followed by an addition.
 
    Allocate a max_allocno by FIRST_PSEUDO_REGISTER conflict matrix for
    conflicts between allocnos and explicit hard register use (which
    includes use of pseudo-registers allocated by local_alloc).  This
    is the hard_reg_conflicts inside each allocno.
 
-   3. For each basic block
-    walk forward through the block, recording which
-    pseudo-registers and which hardware registers are live.
-    Build the conflict matrix between the pseudo-registers
-    and another of pseudo-registers versus hardware registers.
-    Also record the preferred hardware registers
-    for each pseudo-register.
+   3. For each basic block, walk backward through the block, recording
+   which pseudo-registers and which hardware registers are live.
+   Build the conflict matrix between the pseudo-registers and another of
+   pseudo-registers versus hardware registers.
+
+   4. For each basic block, walk backward through the block, recording
+   the preferred hardware registers for each pseudo-register.
 
-   4. Sort a table of the allocnos into order of
-   desirability of the variables.
+   5. Sort a table of the allocnos into order of desirability of the variables.
 
-   5. Allocate the variables in that order; each if possible into
+   6. Allocate the variables in that order; each if possible into
    a preferred register, else into another register.  */
 \f
 /* A vector of the integers from 0 to max_allocno-1,
@@ -90,12 +105,6 @@ along with GCC; see the file COPYING3.  If not see
 
 static int *allocno_order;
 
-/* Two macros to test or store 1 in an element of `conflicts'.  */
-
-#define CONFLICTP(I, J) \
- (conflicts[(I) * allocno_row_words + (unsigned) (J) / HOST_BITS_PER_WIDE_INT] \
-  & ((HOST_WIDE_INT) 1 << ((unsigned) (J) % HOST_BITS_PER_WIDE_INT)))
-
 /* Set of registers that global-alloc isn't supposed to use.  */
 
 static HARD_REG_SET no_global_alloc_regs;
@@ -122,31 +131,6 @@ static int local_reg_live_length[FIRST_PSEUDO_REGISTER];
 
 #define SET_REGBIT(TABLE, I, J)  SET_HARD_REG_BIT (allocno[I].TABLE, J)
 
-/* 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.)
-   The problem is that it isn't true that there is NO possibility of conflict;
-   only that there is no conflict if the two pseudos get the exact same regs.
-   If they were allocated with a partial overlap, there would be a conflict.
-   We can't safely turn off the conflict unless we have another way to
-   prevent the partial overlap.
-
-   Idea: change hard_reg_conflicts so that instead of recording which
-   hard regs the allocno may not overlap, it records where the allocno
-   may not start.  Change both where it is used and where it is updated.
-   Then there is a way to record that (reg:DI 108) may start at 10
-   but not at 9 or 11.  There is still the question of how to record
-   this semi-conflict between two pseudos.  */
-#if 0
-/* Reg pairs for which conflict after the current insn
-   is inhibited by a REG_NO_CONFLICT note.
-   If the table gets full, we ignore any other notes--that is conservative.  */
-#define NUM_NO_CONFLICT_PAIRS 4
-/* Number of pairs in use in this insn.  */
-int n_no_conflict_pairs;
-static struct { int allocno1, allocno2;}
-  no_conflict_pairs[NUM_NO_CONFLICT_PAIRS];
-#endif /* 0 */
-
 /* Return true if *LOC contains an asm.  */
 
 static int
@@ -181,11 +165,11 @@ compute_regs_asm_clobbered (char *regs_asm_clobbered)
       rtx insn;
       FOR_BB_INSNS_REVERSE (bb, insn)
        {
-         struct df_ref **def_rec;
+         df_ref *def_rec;
          if (insn_contains_asm (insn))
            for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
              {
-               struct df_ref *def = *def_rec;
+               df_ref def = *def_rec;
                unsigned int dregno = DF_REF_REGNO (def);
                if (dregno < FIRST_PSEUDO_REGISTER)
                  {
@@ -204,16 +188,15 @@ compute_regs_asm_clobbered (char *regs_asm_clobbered)
 
 /* All registers that can be eliminated.  */
 
-static HARD_REG_SET eliminable_regset;
+HARD_REG_SET eliminable_regset;
 
+static int regno_compare (const void *, const void *);
 static int allocno_compare (const void *, const void *);
-static void mirror_conflicts (void);
 static void expand_preferences (void);
 static void prune_preferences (void);
 static void set_preferences (void);
 static void find_reg (int, HARD_REG_SET, int, int, int);
 static void dump_conflicts (FILE *);
-static void build_insn_chain (void);
 \f
 
 /* Look through the list of eliminable registers.  Set ELIM_SET to the
@@ -222,7 +205,9 @@ static void build_insn_chain (void);
 
    This will normally be called with ELIM_SET as the file static
    variable eliminable_regset, and NO_GLOBAL_SET as the file static
-   variable NO_GLOBAL_ALLOC_REGS.  */
+   variable NO_GLOBAL_ALLOC_REGS.
+
+   It also initializes global flag frame_pointer_needed.  */
 
 static void
 compute_regsets (HARD_REG_SET *elim_set, 
@@ -232,17 +217,26 @@ compute_regsets (HARD_REG_SET *elim_set,
 /* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
    Unlike regs_ever_live, elements of this array corresponding to
    eliminable regs like the frame pointer are set if an asm sets them.  */
-  char *regs_asm_clobbered = alloca (FIRST_PSEUDO_REGISTER * sizeof (char));
+  char *regs_asm_clobbered = XALLOCAVEC (char, FIRST_PSEUDO_REGISTER);
 
 #ifdef ELIMINABLE_REGS
   static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
   size_t i;
 #endif
+
+  /* FIXME: If EXIT_IGNORE_STACK is set, we will not save and restore
+     sp for alloca.  So we can't eliminate the frame pointer in that
+     case.  At some point, we should improve this by emitting the
+     sp-adjusting insns for this case.  */
   int need_fp
     = (! flag_omit_frame_pointer
-       || (current_function_calls_alloca && EXIT_IGNORE_STACK)
+       || (cfun->calls_alloca && EXIT_IGNORE_STACK)
+       || crtl->accesses_prior_frames
+       || crtl->stack_realign_needed
        || FRAME_POINTER_REQUIRED);
 
+  frame_pointer_needed = need_fp;
+
   max_regno = max_reg_num ();
   compact_blocks ();
 
@@ -262,7 +256,10 @@ compute_regsets (HARD_REG_SET *elim_set,
     {
       bool cannot_elim
        = (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
-          || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp));
+          || (eliminables[i].to == STACK_POINTER_REGNUM
+              && need_fp 
+              && (! SUPPORTS_STACK_ALIGNMENT
+                  || ! stack_realign_fp)));
 
       if (!regs_asm_clobbered[eliminables[i].from])
        {
@@ -315,6 +312,8 @@ global_alloc (void)
 {
   int retval;
   size_t i;
+  int max_blk;
+  int *num_allocnos_per_blk;
 
   compute_regsets (&eliminable_regset, &no_global_alloc_regs);
 
@@ -357,9 +356,8 @@ global_alloc (void)
 
   reg_allocno = XNEWVEC (int, max_regno);
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    reg_allocno[i] = -1;
-
+  /* Initially fill the reg_allocno array with regno's...  */
+  max_blk = 0;
   max_allocno = 0;
   for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
     /* Note that reg_live_length[i] < 0 indicates a "constant" reg
@@ -368,31 +366,96 @@ global_alloc (void)
     if (REG_N_REFS (i) != 0 && REG_LIVE_LENGTH (i) != -1
        /* Don't allocate pseudos that cross calls,
           if this function receives a nonlocal goto.  */
-       && (! current_function_has_nonlocal_label
+       && (! cfun->has_nonlocal_label
            || REG_N_CALLS_CROSSED (i) == 0))
       {
-       reg_allocno[i] = max_allocno++;
+       int blk = regno_basic_block (i);
+       reg_allocno[max_allocno++] = i;
+       if (blk > max_blk)
+         max_blk = blk;
        gcc_assert (REG_LIVE_LENGTH (i));
       }
-    else
-      reg_allocno[i] = -1;
 
   allocno = XCNEWVEC (struct allocno, max_allocno);
+  partial_bitnum = XNEWVEC (HOST_WIDE_INT, max_allocno);
+  num_allocnos_per_blk = XCNEWVEC (int, max_blk + 1);
 
-  for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
-    if (reg_allocno[i] >= 0)
-      {
-       int num = reg_allocno[i];
-       allocno[num].reg = i;
-       allocno[num].size = PSEUDO_REGNO_SIZE (i);
-       allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
-       allocno[num].throwing_calls_crossed
-         += REG_N_THROWING_CALLS_CROSSED (i);
-       allocno[num].n_refs += REG_N_REFS (i);
-       allocno[num].freq += REG_FREQ (i);
-       if (allocno[num].live_length < REG_LIVE_LENGTH (i))
-         allocno[num].live_length = REG_LIVE_LENGTH (i);
-      }
+  /* ...so we can sort them in the order we want them to receive
+     their allocnos.  */
+  qsort (reg_allocno, max_allocno, sizeof (int), regno_compare);
+
+  for (i = 0; i < (size_t) max_allocno; i++)
+    {
+      int regno = reg_allocno[i];
+      int blk = regno_basic_block (regno);
+      num_allocnos_per_blk[blk]++;
+      allocno[i].reg = regno;
+      allocno[i].size = PSEUDO_REGNO_SIZE (regno);
+      allocno[i].calls_crossed += REG_N_CALLS_CROSSED (regno);
+      allocno[i].freq_calls_crossed += REG_FREQ_CALLS_CROSSED (regno);
+      allocno[i].throwing_calls_crossed
+       += REG_N_THROWING_CALLS_CROSSED (regno);
+      allocno[i].n_refs += REG_N_REFS (regno);
+      allocno[i].freq += REG_FREQ (regno);
+      if (allocno[i].live_length < REG_LIVE_LENGTH (regno))
+       allocno[i].live_length = REG_LIVE_LENGTH (regno);
+    }
+
+  /* The "global" block must contain all allocnos.  */
+  num_allocnos_per_blk[0] = max_allocno;
+
+  /* Now reinitialize the reg_allocno array in terms of the
+     optimized regno to allocno mapping we created above.  */
+  for (i = 0; i < (size_t) max_regno; i++)
+    reg_allocno[i] = -1;
+
+  max_bitnum = 0;
+  for (i = 0; i < (size_t) max_allocno; i++)
+    {
+      int regno = allocno[i].reg;
+      int blk = regno_basic_block (regno);
+      int row_size = --num_allocnos_per_blk[blk];
+      reg_allocno[regno] = (int) i;
+      partial_bitnum[i] = (row_size > 0) ? max_bitnum - ((int) i + 1) : -1;
+      max_bitnum += row_size;
+    }
+
+#ifdef ENABLE_CHECKING
+  gcc_assert (max_bitnum <=
+             (((HOST_WIDE_INT) max_allocno *
+               ((HOST_WIDE_INT) max_allocno - 1)) / 2));
+#endif
+
+  if (dump_file)
+    {
+      HOST_WIDE_INT num_bits, num_bytes, actual_bytes;
+
+      fprintf (dump_file, "## max_blk:     %d\n", max_blk);
+      fprintf (dump_file, "## max_regno:   %d\n", max_regno);
+      fprintf (dump_file, "## max_allocno: %d\n", max_allocno);
+
+      num_bits = max_bitnum;
+      num_bytes = CEIL (num_bits, 8);
+      actual_bytes = num_bytes;
+      fprintf (dump_file, "## Compressed triangular bitmatrix size: ");
+      fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bits, ", num_bits);
+      fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bytes\n", num_bytes);
+
+      num_bits = ((HOST_WIDE_INT) max_allocno *
+                 ((HOST_WIDE_INT) max_allocno - 1)) / 2;
+      num_bytes = CEIL (num_bits, 8);
+      fprintf (dump_file, "## Standard triangular bitmatrix size:   ");
+      fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bits, ", num_bits);
+      fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bytes [%.2f%%]\n",
+              num_bytes, 100.0 * ((double) actual_bytes / (double) num_bytes));
+
+      num_bits = (HOST_WIDE_INT) max_allocno * (HOST_WIDE_INT) max_allocno;
+      num_bytes = CEIL (num_bits, 8);
+      fprintf (dump_file, "## Square bitmatrix size:                ");
+      fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bits, ", num_bits);
+      fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bytes [%.2f%%]\n",
+              num_bytes, 100.0 * ((double) actual_bytes / (double) num_bytes));
+    }
 
   /* Calculate amount of usage of each hard reg by pseudos
      allocated by local-alloc.  This is to see if we want to
@@ -433,18 +496,26 @@ global_alloc (void)
          fprintf (dump_file, " %d", (int)i);
       fprintf (dump_file, "\n");
     }
-  allocno_row_words = (max_allocno + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT;
 
-  /* We used to use alloca here, but the size of what it would try to
-     allocate would occasionally cause it to exceed the stack limit and
-     cause unpredictable core dumps.  Some examples were > 2Mb in size.  */
-  conflicts = XCNEWVEC (HOST_WIDE_INT, max_allocno * allocno_row_words);
+  conflicts = NULL;
+  adjacency = NULL;
+  adjacency_pool = NULL;
 
   /* If there is work to be done (at least one reg to allocate),
      perform global conflict analysis and allocate the regs.  */
 
   if (max_allocno > 0)
     {
+      /* We used to use alloca here, but the size of what it would try to
+        allocate would occasionally cause it to exceed the stack limit and
+        cause unpredictable core dumps.  Some examples were > 2Mb in size.  */
+      conflicts = XCNEWVEC (HOST_WIDEST_FAST_INT,
+                           CEIL(max_bitnum, HOST_BITS_PER_WIDEST_FAST_INT));
+
+      adjacency = XCNEWVEC (adjacency_t *, max_allocno);
+      adjacency_pool = create_alloc_pool ("global_alloc adjacency list pool",
+                                         sizeof (adjacency_t), 1024);
+
       /* Scan all the insns and compute the conflicts among allocnos
         and between allocnos and hard regs.  */
 
@@ -460,8 +531,6 @@ global_alloc (void)
         global_conflicts.  */
       df_set_flags (DF_NO_INSN_RESCAN);
 
-      mirror_conflicts ();
-
       /* Eliminate conflicts between pseudos and eliminable registers.  If
         the register is not eliminated, the pseudo won't really be able to
         live in the eliminable register, so the conflict doesn't matter.
@@ -536,6 +605,7 @@ global_alloc (void)
          }
 
       free (allocno_order);
+      free (conflicts);
     }
 
   /* Do the reloads now while the allocno data still exists, so that we can
@@ -552,12 +622,44 @@ global_alloc (void)
 
   /* Clean up.  */
   free (reg_allocno);
+  free (num_allocnos_per_blk);
+  free (partial_bitnum);
   free (allocno);
-  free (conflicts);
+  if (adjacency != NULL)
+    {
+      free_alloc_pool (adjacency_pool);
+      free (adjacency);
+    }
 
   return retval;
 }
 
+/* Sort predicate for ordering the regnos.  We want the regno to allocno
+   mapping to have the property that all "global" regnos (ie, regnos that
+   are referenced in more than one basic block) have smaller allocno values
+   than "local" regnos (ie, regnos referenced in only one basic block).
+   In addition, for two basic blocks "i" and "j" with i < j, all regnos
+   local to basic block i should have smaller allocno values than regnos
+   local to basic block j.
+   Returns -1 (1) if *v1p should be allocated before (after) *v2p.  */
+
+static int
+regno_compare (const void *v1p, const void *v2p)
+{
+  int regno1 = *(const int *)v1p;
+  int regno2 = *(const int *)v2p;
+  int blk1 = REG_BASIC_BLOCK (regno1);
+  int blk2 = REG_BASIC_BLOCK (regno2);
+
+  /* Prefer lower numbered basic blocks.  Note that global and unknown
+     blocks have negative values, giving them high precedence.  */
+  if (blk1 - blk2)
+    return blk1 - blk2;
+
+  /* If both regs are referenced from the same block, sort by regno.  */
+  return regno1 - regno2;
+}
+
 /* Sort predicate for ordering the allocnos.
    Returns -1 (1) if *v1 should be allocated before (after) *v2.  */
 
@@ -609,8 +711,8 @@ expand_preferences (void)
        if (REG_NOTE_KIND (link) == REG_DEAD
            && REG_P (XEXP (link, 0))
            && reg_allocno[REGNO (XEXP (link, 0))] >= 0
-           && ! CONFLICTP (reg_allocno[REGNO (SET_DEST (set))],
-                           reg_allocno[REGNO (XEXP (link, 0))]))
+           && ! conflict_p (reg_allocno[REGNO (SET_DEST (set))],
+                            reg_allocno[REGNO (XEXP (link, 0))]))
          {
            int a1 = reg_allocno[REGNO (SET_DEST (set))];
            int a2 = reg_allocno[REGNO (XEXP (link, 0))];
@@ -828,14 +930,14 @@ prune_preferences (void)
         these registers).  */
       HARD_REG_SET temp, temp2;
       int allocno2;
+      adjacency_iter ai;
 
       num = allocno_order[i];
 
       CLEAR_HARD_REG_SET (temp);
       CLEAR_HARD_REG_SET (temp2);
 
-      EXECUTE_IF_SET_IN_ALLOCNO_SET (conflicts + num * allocno_row_words,
-                                    allocno2,
+      FOR_EACH_CONFLICT (num, allocno2, ai)
        {
          if (allocno_to_order[allocno2] > i)
            {
@@ -846,7 +948,7 @@ prune_preferences (void)
                IOR_HARD_REG_SET (temp2,
                                  allocno[allocno2].hard_reg_full_preferences);
            }
-       });
+       }
 
       AND_COMPL_HARD_REG_SET (temp, allocno[num].hard_reg_full_preferences);
       IOR_HARD_REG_SET (temp, temp2);
@@ -879,7 +981,7 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
   int i, best_reg, pass;
   HARD_REG_SET used, used1, used2;
 
-  enum reg_class class = (alt_regs_p
+  enum reg_class rclass = (alt_regs_p
                          ? reg_alternate_class (allocno[num].reg)
                          : reg_preferred_class (allocno[num].reg));
   enum machine_mode mode = PSEUDO_REGNO_MODE (allocno[num].reg);
@@ -896,7 +998,22 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
   if (losers)
     IOR_HARD_REG_SET (used1, losers);
 
-  IOR_COMPL_HARD_REG_SET (used1, reg_class_contents[(int) class]);
+  IOR_COMPL_HARD_REG_SET (used1, reg_class_contents[(int) rclass]);
+
+#ifdef EH_RETURN_DATA_REGNO
+  if (allocno[num].no_eh_reg)
+    {
+      unsigned int j;
+      for (j = 0; ; ++j)
+       {
+         unsigned int regno = EH_RETURN_DATA_REGNO (j);
+         if (regno == INVALID_REGNUM)
+           break;
+         SET_HARD_REG_BIT (used1, regno);
+       }
+    }
+#endif
+
   COPY_HARD_REG_SET (used2, used1);
 
   IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts);
@@ -1051,8 +1168,9 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
       if (! accept_call_clobbered
          && allocno[num].calls_crossed != 0
          && allocno[num].throwing_calls_crossed == 0
-         && CALLER_SAVE_PROFITABLE (allocno[num].n_refs,
-                                    allocno[num].calls_crossed))
+         && CALLER_SAVE_PROFITABLE (optimize_function_for_size_p (cfun) ? allocno[num].n_refs : allocno[num].freq,
+                                    optimize_function_for_size_p (cfun) ? allocno[num].calls_crossed
+                                    : allocno[num].freq_calls_crossed))
        {
          HARD_REG_SET new_losers;
          if (! losers)
@@ -1167,6 +1285,7 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
     {
       int lim, j;
       HARD_REG_SET this_reg;
+      adjacency_iter ai;
 
       /* Yes.  Record it as the hard register of this pseudo-reg.  */
       reg_renumber[allocno[num].reg] = best_reg;
@@ -1184,11 +1303,10 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
        }
       /* For each other pseudo-reg conflicting with this one,
         mark it as conflicting with the hard regs this one occupies.  */
-      lim = num;
-      EXECUTE_IF_SET_IN_ALLOCNO_SET (conflicts + lim * allocno_row_words, j,
+      FOR_EACH_CONFLICT (num, j, ai)
        {
          IOR_HARD_REG_SET (allocno[j].hard_reg_conflicts, this_reg);
-       });
+       }
     }
 }
 \f
@@ -1224,38 +1342,6 @@ retry_global_alloc (int regno, HARD_REG_SET forbidden_regs)
     }
 }
 \f
-/* If CONFLICTP (i, j) is true, make sure CONFLICTP (j, i) is also true.  */
-static void
-mirror_conflicts (void)
-{
-  int i, j;
-  int rw = allocno_row_words;
-  int rwb = rw * HOST_BITS_PER_WIDE_INT;
-  HOST_WIDE_INT *p = conflicts;
-  HOST_WIDE_INT *q0 = conflicts, *q1, *q2;
-  unsigned HOST_WIDE_INT mask;
-
-  for (i = max_allocno - 1, mask = 1; i >= 0; i--, mask <<= 1)
-    {
-      if (! mask)
-       {
-         mask = 1;
-         q0++;
-       }
-      for (j = allocno_row_words - 1, q1 = q0; j >= 0; j--, q1 += rwb)
-       {
-         unsigned HOST_WIDE_INT word;
-
-         for (word = (unsigned HOST_WIDE_INT) *p++, q2 = q1; word;
-              word >>= 1, q2 += rw)
-           {
-             if (word & 1)
-               *q2 |= mask;
-           }
-       }
-    }
-}
-\f
 /* Indicate that hard register number FROM was eliminated and replaced with
    an offset from hard register number TO.  The status of hard registers live
    at the start of a basic block is updated by replacing a use of FROM with
@@ -1268,7 +1354,8 @@ mark_elimination (int from, int to)
 
   FOR_EACH_BB (bb)
     {
-      regset r = DF_LIVE_IN (bb);
+      /* We don't use LIVE info in IRA.  */
+      regset r = (flag_ira ? DF_LR_IN (bb) : DF_LIVE_IN (bb));
       if (REGNO_REG_SET_P (r, from))
        {
          CLEAR_REGNO_REG_SET (r, from);
@@ -1277,6 +1364,8 @@ mark_elimination (int from, int to)
     }
 }
 \f
+/* Print chain C to FILE.  */
+
 static void
 print_insn_chain (FILE *file, struct insn_chain *c)
 {
@@ -1285,6 +1374,9 @@ print_insn_chain (FILE *file, struct insn_chain *c)
   bitmap_print (file, &c->dead_or_set, "dead_or_set: ", "\n");
 }
 
+
+/* Print all reload_insn_chains to FILE.  */
+
 static void
 print_insn_chains (FILE *file)
 {
@@ -1292,9 +1384,23 @@ print_insn_chains (FILE *file)
   for (c = reload_insn_chain; c ; c = c->next)
     print_insn_chain (file, c);
 }
+
+/* Return true if pseudo REGNO should be added to set live_throughout
+   or dead_or_set of the insn chains for reload consideration.  */
+
+static bool
+pseudo_for_reload_consideration_p (int regno)
+{
+  /* Consider spilled pseudos too for IRA because they still have a
+     chance to get hard-registers in the reload when IRA is used.  */
+  return (reg_renumber[regno] >= 0
+         || (flag_ira && optimize && flag_ira_share_spill_slots));
+}
+
 /* Walk the insns of the current function and build reload_insn_chain,
    and record register life information.  */
-static void
+
+void
 build_insn_chain (void)
 {
   unsigned int i;
@@ -1317,7 +1423,6 @@ build_insn_chain (void)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (TEST_HARD_REG_BIT (eliminable_regset, i))
       bitmap_set_bit (elim_regset, i);
-
   FOR_EACH_BB_REVERSE (bb)
     {
       bitmap_iterator bi;
@@ -1335,7 +1440,7 @@ build_insn_chain (void)
 
       EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), FIRST_PSEUDO_REGISTER, i, bi)
        {
-         if (reg_renumber[i] >= 0)
+         if (pseudo_for_reload_consideration_p (i))
            bitmap_set_bit (live_relevant_regs, i);
        }
 
@@ -1344,8 +1449,8 @@ build_insn_chain (void)
          if (!NOTE_P (insn) && !BARRIER_P (insn))
            {
              unsigned int uid = INSN_UID (insn);
-             struct df_ref **def_rec;
-             struct df_ref **use_rec;
+             df_ref *def_rec;
+             df_ref *use_rec;
 
              c = new_insn_chain ();
              c->next = next;
@@ -1359,7 +1464,7 @@ build_insn_chain (void)
              if (INSN_P (insn))
                for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
                  {
-                   struct df_ref *def = *def_rec;
+                   df_ref def = *def_rec;
                    unsigned int regno = DF_REF_REGNO (def);
                    
                    /* Ignore may clobbers because these are generated
@@ -1369,28 +1474,45 @@ build_insn_chain (void)
                      {
                        if (regno < FIRST_PSEUDO_REGISTER)
                          {
-                           if (! fixed_regs[regno])
+                           if (!fixed_regs[regno])
                              bitmap_set_bit (&c->dead_or_set, regno);
                          }
-                       else if (reg_renumber[regno] >= 0)
+                       else if (pseudo_for_reload_consideration_p (regno))
                          bitmap_set_bit (&c->dead_or_set, regno);
                      }
 
-                   if ((regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+                   if ((regno < FIRST_PSEUDO_REGISTER
+                        || reg_renumber[regno] >= 0
+                        || (flag_ira && optimize))
                        && (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
                      {
                        rtx reg = DF_REF_REG (def);
+
                        /* We can model subregs, but not if they are
                           wrapped in ZERO_EXTRACTS.  */
                        if (GET_CODE (reg) == SUBREG
-                           && !DF_REF_FLAGS_IS_SET (def, DF_REF_EXTRACT))
+                           && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
                          {
                            unsigned int start = SUBREG_BYTE (reg);
-                           unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
+                           unsigned int last = start 
+                             + GET_MODE_SIZE (GET_MODE (reg));
 
-                           ra_init_live_subregs (bitmap_bit_p (live_relevant_regs, regno), 
-                                                 live_subregs, live_subregs_used,
+                           ra_init_live_subregs (bitmap_bit_p (live_relevant_regs, 
+                                                               regno), 
+                                                 live_subregs, 
+                                                 live_subregs_used,
                                                  regno, reg);
+
+                           if (!DF_REF_FLAGS_IS_SET
+                               (def, DF_REF_STRICT_LOW_PART))
+                             {
+                               /* Expand the range to cover entire words.
+                                  Bytes added here are "don't care".  */
+                               start = start / UNITS_PER_WORD * UNITS_PER_WORD;
+                               last = ((last + UNITS_PER_WORD - 1)
+                                       / UNITS_PER_WORD * UNITS_PER_WORD);
+                             }
+
                            /* Ignore the paradoxical bits.  */
                            if ((int)last > live_subregs_used[regno])
                              last = live_subregs_used[regno];
@@ -1434,7 +1556,7 @@ build_insn_chain (void)
              if (INSN_P (insn))
                for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
                  {
-                   struct df_ref *use = *use_rec;
+                   df_ref use = *use_rec;
                    unsigned int regno = DF_REF_REGNO (use);
                    rtx reg = DF_REF_REG (use);
                    
@@ -1445,7 +1567,7 @@ build_insn_chain (void)
                       precisely so we do not need to look at the
                       fabricated use. */
                    if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE) 
-                       && !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT) 
+                       && !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT) 
                        && DF_REF_FLAGS_IS_SET (use, DF_REF_SUBREG))
                      continue;
                    
@@ -1454,23 +1576,28 @@ build_insn_chain (void)
                      {
                        if (regno < FIRST_PSEUDO_REGISTER)
                          {
-                           if (! fixed_regs[regno])
+                           if (!fixed_regs[regno])
                              bitmap_set_bit (&c->dead_or_set, regno);
                          }
-                       else if (reg_renumber[regno] >= 0)
+                       else if (pseudo_for_reload_consideration_p (regno))
                          bitmap_set_bit (&c->dead_or_set, regno);
                      }
                    
-                   if (regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+                   if (regno < FIRST_PSEUDO_REGISTER
+                       || pseudo_for_reload_consideration_p (regno))
                      {
                        if (GET_CODE (reg) == SUBREG
-                           && !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT)) 
+                           && !DF_REF_FLAGS_IS_SET (use,
+                                                    DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT)) 
                          {
                            unsigned int start = SUBREG_BYTE (reg);
-                           unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
+                           unsigned int last = start 
+                             + GET_MODE_SIZE (GET_MODE (reg));
                            
-                           ra_init_live_subregs (bitmap_bit_p (live_relevant_regs, regno), 
-                                                 live_subregs, live_subregs_used,
+                           ra_init_live_subregs (bitmap_bit_p (live_relevant_regs, 
+                                                               regno), 
+                                                 live_subregs, 
+                                                 live_subregs_used,
                                                  regno, reg);
                            
                            /* Ignore the paradoxical bits.  */
@@ -1494,9 +1621,44 @@ build_insn_chain (void)
                  }
            }
        }
+
+      /* FIXME!! The following code is a disaster.  Reload needs to see the
+        labels and jump tables that are just hanging out in between
+        the basic blocks.  See pr33676.  */
+      insn = BB_HEAD (bb);
+      
+      /* Skip over the barriers and cruft.  */
+      while (insn && (BARRIER_P (insn) || NOTE_P (insn) 
+                     || BLOCK_FOR_INSN (insn) == bb))
+       insn = PREV_INSN (insn);
+      
+      /* While we add anything except barriers and notes, the focus is
+        to get the labels and jump tables into the
+        reload_insn_chain.  */
+      while (insn)
+       {
+         if (!NOTE_P (insn) && !BARRIER_P (insn))
+           {
+             if (BLOCK_FOR_INSN (insn))
+               break;
+             
+             c = new_insn_chain ();
+             c->next = next;
+             next = c;
+             *p = c;
+             p = &c->prev;
+             
+             /* The block makes no sense here, but it is what the old
+                code did.  */
+             c->block = bb->index;
+             c->insn = insn;
+             bitmap_copy (&c->live_throughout, live_relevant_regs);
+           }     
+         insn = PREV_INSN (insn);
+       }
     }
 
-  for (i = 0; i < (unsigned int)max_regno; i++)
+  for (i = 0; i < (unsigned int) max_regno; i++)
     if (live_subregs[i])
       free (live_subregs[i]);
 
@@ -1519,6 +1681,7 @@ static void
 dump_conflicts (FILE *file)
 {
   int i;
+  int regno;
   int has_preferences;
   int nregs;
   nregs = 0;
@@ -1529,46 +1692,51 @@ dump_conflicts (FILE *file)
       nregs++;
     }
   fprintf (file, ";; %d regs to allocate:", nregs);
-  for (i = 0; i < max_allocno; i++)
-    {
-      int j;
-      if (reg_renumber[allocno[allocno_order[i]].reg] >= 0)
-       continue;
-      fprintf (file, " %d", allocno[allocno_order[i]].reg);
-      for (j = 0; j < max_regno; j++)
-       if (reg_allocno[j] == allocno_order[i]
-           && j != allocno[allocno_order[i]].reg)
-         fprintf (file, "+%d", j);
-      if (allocno[allocno_order[i]].size != 1)
-       fprintf (file, " (%d)", allocno[allocno_order[i]].size);
-    }
+  for (regno = 0; regno < max_regno; regno++)
+    if ((i = reg_allocno[regno]) >= 0)
+      {
+       int j;
+       if (reg_renumber[allocno[allocno_order[i]].reg] >= 0)
+         continue;
+       fprintf (file, " %d", allocno[allocno_order[i]].reg);
+       for (j = 0; j < max_regno; j++)
+         if (reg_allocno[j] == allocno_order[i]
+             && j != allocno[allocno_order[i]].reg)
+           fprintf (file, "+%d", j);
+       if (allocno[allocno_order[i]].size != 1)
+         fprintf (file, " (%d)", allocno[allocno_order[i]].size);
+      }
   fprintf (file, "\n");
 
-  for (i = 0; i < max_allocno; i++)
-    {
-      int j;
-      fprintf (file, ";; %d conflicts:", allocno[i].reg);
-      for (j = 0; j < max_allocno; j++)
-       if (CONFLICTP (j, i))
-         fprintf (file, " %d", allocno[j].reg);
-      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
-       if (TEST_HARD_REG_BIT (allocno[i].hard_reg_conflicts, j) && ! fixed_regs[j])
-         fprintf (file, " %d", j);
-      fprintf (file, "\n");
-
-      has_preferences = 0;
-      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
-       if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
-         has_preferences = 1;
-
-      if (! has_preferences)
-       continue;
-      fprintf (file, ";; %d preferences:", allocno[i].reg);
-      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
-       if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
-         fprintf (file, " %d", j);
-      fprintf (file, "\n");
-    }
+  for (regno = 0; regno < max_regno; regno++)
+    if ((i = reg_allocno[regno]) >= 0)
+      {
+       int j;
+       adjacency_iter ai;
+       fprintf (file, ";; %d conflicts:", allocno[i].reg);
+       FOR_EACH_CONFLICT (i, j, ai)
+         {
+           fprintf (file, " %d", allocno[j].reg);
+         }
+       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+         if (TEST_HARD_REG_BIT (allocno[i].hard_reg_conflicts, j)
+             && !fixed_regs[j])
+           fprintf (file, " %d", j);
+       fprintf (file, "\n");
+
+       has_preferences = 0;
+       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+         if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
+           has_preferences = 1;
+
+       if (!has_preferences)
+         continue;
+       fprintf (file, ";; %d preferences:", allocno[i].reg);
+       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+         if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
+           fprintf (file, " %d", j);
+       fprintf (file, "\n");
+      }
   fprintf (file, "\n");
 }
 
@@ -1593,6 +1761,13 @@ dump_global_regs (FILE *file)
   fprintf (file, "\n\n");
 }
 
+
+static bool
+gate_handle_global_alloc (void)
+{
+  return ! flag_ira;
+}
+
 /* Run old register allocator.  Return TRUE if we must exit
    rest_of_compilation upon return.  */
 static unsigned int
@@ -1617,7 +1792,7 @@ rest_of_handle_global_alloc (void)
       failure = reload (get_insns (), 0);
     }
 
-  if (dump_enabled_p (pass_global_alloc.static_pass_number))
+  if (dump_enabled_p (pass_global_alloc.pass.static_pass_number))
     {
       timevar_push (TV_DUMP);
       dump_global_regs (dump_file);
@@ -1634,7 +1809,7 @@ rest_of_handle_global_alloc (void)
   reload_completed = !failure;
 
   /* The world has changed so much that at this point we might as well
-     just rescan everything.  Not that df_rescan_all_insns is not
+     just rescan everything.  Note that df_rescan_all_insns is not
      going to help here because it does not touch the artificial uses
      and defs.  */
   df_finish_pass (true);
@@ -1651,10 +1826,12 @@ rest_of_handle_global_alloc (void)
   return 0;
 }
 
-struct tree_opt_pass pass_global_alloc =
+struct rtl_opt_pass pass_global_alloc =
 {
+ {
+  RTL_PASS,
   "greg",                               /* name */
-  NULL,                                 /* gate */
+  gate_handle_global_alloc,             /* gate */
   rest_of_handle_global_alloc,          /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
@@ -1665,7 +1842,7 @@ struct tree_opt_pass pass_global_alloc =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func | TODO_verify_rtl_sharing
-  | TODO_ggc_collect,                   /* todo_flags_finish */
-  'g'                                   /* letter */
+  | TODO_ggc_collect                    /* todo_flags_finish */
+ }
 };