This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA] The Integrated Register Allocator


Vladimir Makarov wrote:
Kenneth Zadeck wrote:
Vladimir Makarov wrote:
Ian Lance Taylor wrote:
Vladimir Makarov <vmakarov@redhat.com> writes:

One more change was taking subregs into account in building conflict
graph. But I did not see a report (may be I missed) what kind code
performance improvement it gives. I don't think it is important after
we have subreg lowering pass which breaks subregs of muti-word pseudos
in different pseudos. If it is really important and you can show this
we could talk more about implementation of it in IRA.

For background, the subreg lowering pass that has been committed already does only part of the job. Not every large pseudo-register can be split. The reason that it is useful to track subreg lifetimes is to see cases where two large pseudo-registers can be allocated to the same set of hard registers. When you don't track subreg dependencies, you see conflicts between the inputs and outputs, but in some cases the output can be allocated to the same set of registers as one of the inputs. This optimization is the sole reason for the existence of the REG_NO_CONFLICT register note, and the associated machinery in emit_no_conflict_block. This is of course most important on small register machines like the x86.

I haven't looked at the patch; I don't know what IRA does here. But I
expect that if IRA doesn't track subreg lifetimes, that that can be
added.
IRA does nothing with REG_NO_CONFLICTS yet.
One of the reasons that steven caught this was that steven and i have been actually working pretty hard to get rid of all libcall blocks, and the only one that still seems to be relevant are the REG_NO_CONFLICT blocks.
I have privately circulated a patch to my conflict builder that builds "special" interferences that could be used to guide the ra to allocate two multiword pseudos to the same set of hard registers, thus eliminating the need for the blocks even if some part of one psudo is written too while another part is live.


Since your conflict builder is radically different from mine, i do not know how much the patch would help you. Certainly the code where i detect the legal overlaps may be adapted, even if the way that i represent them would be completely different. Michael Matz was then going to help me hack global this into global. When you look into this problem, you should view it from the point of view of being able to do the same kind of allocation without the need of the notes to tell you that you can do it, because we really want to proceed with the process of getting rid of all libcalls, and this one appears to be the only one left of any use.

I will be happy to send you my patch if that will help.
Yes, thanks. It would be interesting for me. If it is hard to incorporate it in IRA, it still useful to know for me what could be done.
I will most likely get all of the scanning changes in because they are generally useful for passes that want to understand subregs in the df framework.

it is highly unlikely that the datastructure that i build here to represent these pairs of pseudos is the correct datastructure, even for global. The important content of the patch is how you scan the block to find the pairs, not how you represent the answer.
Index: fwprop.c
===================================================================
--- fwprop.c	(revision 133475)
+++ fwprop.c	(working copy)
@@ -644,6 +644,7 @@ update_df (rtx insn, rtx *loc, struct df
       struct df_ref *orig_use = use, *new_use;
       int width = -1;
       int offset = -1;
+      enum machine_mode mode = 0;
       rtx *new_loc = find_occurrence (loc, DF_REF_REG (orig_use));
       use_rec++;
 
@@ -652,15 +653,17 @@ update_df (rtx insn, rtx *loc, struct df
 
       if (DF_REF_FLAGS_IS_SET (orig_use, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
 	{
-	  width = DF_REF_WIDTH (orig_use);
-	  offset = DF_REF_OFFSET (orig_use);
+	  width = DF_REF_EXTRACT_WIDTH (orig_use);
+	  offset = DF_REF_EXTRACT_OFFSET (orig_use);
+	  mode = DF_REF_EXTRACT_MODE (orig_use);
 	}
 
       /* Add a new insn use.  Use the original type, because it says if the
          use was within a MEM.  */
       new_use = df_ref_create (DF_REF_REG (orig_use), new_loc,
 			       insn, BLOCK_FOR_INSN (insn),
-			       type, DF_REF_FLAGS (orig_use) | new_flags, width, offset);
+			       type, DF_REF_FLAGS (orig_use) | new_flags, 
+			       width, offset, mode);
 
       /* Set up the use-def chain.  */
       df_chain_copy (new_use, DF_REF_CHAIN (orig_use));
Index: sbitmap.c
===================================================================
--- sbitmap.c	(revision 133475)
+++ sbitmap.c	(working copy)
@@ -1,5 +1,5 @@
 /* Simple bitmaps.
-   Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006, 2007
+   Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -273,6 +273,57 @@ sbitmap_empty_p (const_sbitmap bmap)
   return true;
 }
 
+/* Return false if any of the N bits are set in MAP starting at
+   START.  */
+
+bool 
+sbitmap_range_empty_p (const_sbitmap bmap, unsigned int start, unsigned int n)
+{
+  unsigned int i = start / SBITMAP_ELT_BITS;
+  SBITMAP_ELT_TYPE elm;
+  unsigned int shift = start % SBITMAP_ELT_BITS;
+
+  gcc_assert (bmap->n_bits >= start + n);
+
+  elm = bmap->elms[i];
+  elm = elm >> shift;
+
+  if (shift + n <= SBITMAP_ELT_BITS)
+    {
+      /* The bits are totally contained in a single element.  */
+      if (shift + n < SBITMAP_ELT_BITS)
+        elm &= ((1 << n) - 1);
+      return (elm == 0);
+    }
+
+  if (elm) 
+    return false;
+
+  n -= SBITMAP_ELT_BITS - shift;
+  i++;
+
+  /* Deal with full elts.  */
+  while (n >= SBITMAP_ELT_BITS)
+    {
+      if (bmap->elms[i])
+	return false;
+      i++;
+      n -= SBITMAP_ELT_BITS;
+    }
+
+  /* The leftover bits.  */
+  if (n)
+    {
+      elm = bmap->elms[i];
+      elm &= ((1 << n) - 1);
+      return (elm == 0);
+    }  
+
+  return true;
+}
+
+
+
 /* Zero all elements in a bitmap.  */
 
 void
@@ -687,6 +738,7 @@ sbitmap_a_and_b_or_c (sbitmap dst, const
     *dstp++ = *ap++ & (*bp++ | *cp++);
 }
 
+
 #ifdef IN_GCC
 /* Set the bitmap DST to the intersection of SRC of successors of
    block number BB, using the new flow graph structures.  */
Index: sbitmap.h
===================================================================
--- sbitmap.h	(revision 133475)
+++ sbitmap.h	(working copy)
@@ -1,5 +1,5 @@
 /* Simple bitmaps.
-   Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006, 2007 
+   Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -219,6 +219,7 @@ extern void sbitmap_copy (sbitmap, const
 extern void sbitmap_copy_n (sbitmap, const_sbitmap, unsigned int);
 extern int sbitmap_equal (const_sbitmap, const_sbitmap);
 extern bool sbitmap_empty_p (const_sbitmap);
+extern bool sbitmap_range_empty_p (const_sbitmap, unsigned int, unsigned int);
 extern void sbitmap_zero (sbitmap);
 extern void sbitmap_ones (sbitmap);
 extern void sbitmap_vector_zero (sbitmap *, unsigned int);
Index: dbgcnt.def
===================================================================
--- dbgcnt.def	(revision 133475)
+++ dbgcnt.def	(working copy)
@@ -61,6 +61,83 @@ along with GCC; see the file COPYING3.  
    Use -fdbg-cnt=counter1:N,counter2:M,...
    which sets the limit for counter1 to N, and the limit for counter2 to M, etc.
    e.g. setting a limit to zero will make dbg_cnt () return false *always*.
+
+   The following shell file can then be used to binary search for
+   exact transformation that causes the bug.  A second shell script
+   should be written, say "tryTest", which exits with 1 if the
+   compiled program fails and exits with 0 if the program succeeds.
+   This shell script should take 1 parameter, the value to be passed
+   to set the counter of the compilation command in tryTest.  Then,
+   assuming that the following script is called binarySearch,
+   the command:
+
+	binarySearch tryTest 
+
+   will automatically find the highest value of the counter for which
+   the program fails.  If tryTest never fails, binarySearch will
+   produce unpredictable results as it will try to find an upper bound
+   that does not exist.
+
+   When dbgcnt does hits the limit, it writes a comment in the current
+   dump_file of the form:
+
+       ***dbgcnt: limit reached for %s.***
+	
+   Assuming that the dump file is logging the analysis/transformations
+   it is making, this pinpoints the exact position in the log file
+   where the problem transformation is being logged.
+
+=====================================
+#!/bin/bash
+
+while getopts "l:u:i:" opt
+do
+    case $opt in
+        l) lb="$OPTARG";;
+        u) ub="$OPTARG";;
+        i) init="$OPTARG";;
+        ?) usage; exit 3;;
+    esac
+done
+
+shift $(($OPTIND - 1))
+echo $@
+cmd=${1+"${@}"}
+
+lb=${lb:=0}
+init=${init:=100}
+
+$cmd $lb
+lb_val=$?
+if [ -z "$ub" ]; then
+    # find the upper bound
+    ub=$(($init + $lb))
+    true
+    while [ $? -eq $lb_val ]; do
+        ub=$(($ub * 10))
+        #ub=`expr $ub \* 10`
+        $cmd $ub
+    done
+fi
+
+echo command: $cmd
+
+true
+while [ `expr $ub - $lb` -gt 1 ]; do
+    try=$(($lb + ( $ub - $lb ) / 2))
+    $cmd $try
+    if [ $? -eq $lb_val ]; then
+        lb=$try
+    else
+        ub=$try
+    fi
+done
+
+echo lbound: $lb
+echo ubound: $ub
+
+=====================================
+
 */
 
 /* Debug counter definitions.  */
@@ -73,6 +150,7 @@ DEBUG_COUNTER (dce)
 DEBUG_COUNTER (dce_fast)
 DEBUG_COUNTER (dce_ud)
 DEBUG_COUNTER (delete_trivial_dead)
+DEBUG_COUNTER (df_byte_scan)
 DEBUG_COUNTER (dse)
 DEBUG_COUNTER (dse1)
 DEBUG_COUNTER (dse2)
Index: optabs.c
===================================================================
--- optabs.c	(revision 133475)
+++ optabs.c	(working copy)
@@ -3877,8 +3877,11 @@ emit_no_conflict_block (rtx insns, rtx t
 {
   rtx prev, next, first, last, insn;
 
+#if 1
   if (!REG_P (target) || reload_in_progress)
+#endif
     return emit_insn (insns);
+#if 1
   else
     for (insn = insns; insn; insn = NEXT_INSN (insn))
       if (!NONJUMP_INSN_P (insn)
@@ -3968,6 +3971,7 @@ emit_no_conflict_block (rtx insns, rtx t
   maybe_encapsulate_block (first, last, equiv);
 
   return last;
+#endif
 }
 
 /* Emit code to make a call to a constant function or a library call.
Index: ra-conflict.c
===================================================================
--- ra-conflict.c	(revision 133475)
+++ ra-conflict.c	(working copy)
@@ -1,5 +1,5 @@
 /* Allocate registers for pseudo-registers that span basic blocks.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
 
 This file is part of GCC.
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  
 #include "ra.h"
 #include "sbitmap.h"
 #include "sparseset.h"
+#include "hashtab.h"
 
 /* Externs defined in regs.h.  */
 
@@ -67,8 +68,25 @@ DEF_VEC_ALLOC_P(df_ref_t,heap);
 #define CONFLICT_BITNUM_FAST(I, I_PARTIAL_BITNUM, J) \
   (((I) < (J)) ? ((I_PARTIAL_BITNUM) + (J)) : (partial_bitnum[J] + (I)))
 
+static inline void
+add_neighbor (int alloc_no, int neighbor)
+{
+  adjacency_t *adjlist = adjacency[alloc_no];
+
+  if (adjlist == NULL || adjlist->index == ADJACENCY_VEC_LENGTH)
+    {
+      adjacency_t *new = pool_alloc (adjacency_pool);
+      new->index = 0;
+      new->next = adjlist;
+      adjlist = new;
+      adjacency[alloc_no] = adjlist;
+    }
+
+  adjlist->neighbors[adjlist->index++] = neighbor;
+}
+
 bool
-conflict_p (int allocno1, int allocno2)
+ra_conflict_p (int allocno1, int allocno2)
 {
   HOST_WIDE_INT bitnum;
   HOST_WIDEST_FAST_INT word, mask;
@@ -99,7 +117,14 @@ conflict_p (int allocno1, int allocno2)
   return (word & mask) != 0;
 }
 
-/* Add conflict edges between ALLOCNO1 and ALLOCNO2.  */
+
+/* Add conflict edges between ALLOCNO1 and ALLOCNO2.  Note that set
+   conflict is only called from two places: (1) from
+   record_one_conflict_between_regnos, which handles obscure cases,
+   and at the end to put in interferences that were not put in during
+   the first pass, because they were weak multiword reg interfences.
+   For this reason, this code does not check for aligned multiword
+   interferences as does the code in set_conflicts.  */
 
 static void
 set_conflict (int allocno1, int allocno2)
@@ -140,15 +165,267 @@ set_conflict (int allocno1, int allocno2
     }
 }
 
-/* Add conflict edges between ALLOCNO1 and all allocnos currently live.  */
+
+/* The following datastructures are to support allocation of multiword
+   pseudos.  There are many cases in gcc where it is desirable to
+   allocate two multiword pseudos to the same set of hard regsisters
+   even though one part of one pseudo may overlap the usage of
+   another.  This typically happens on a 32 bit machine which is doing
+   64 bit arithmetic in a series of insns that are reusing the same
+   pair of 64 bit registers.  
+
+   If we had a real register allocator, as opposed to the toy one we
+   have now, we would implement this differently.  Most likely
+   something along the lines of "Coloring Register Pairs" by Briggs,
+   P. and Cooper, K. D. and Torczon, L.  But that is a long way away.
+   
+   What we are doing here is having a hash table of allocno pairs that
+   if the pair is there, can be allocated to the same register
+   assuming perfect overlap of the two regs.
+
+   The Briggs papers would require a different meaning to our
+   interferenece graph.  Currently each pseudo is considered as one
+   blob to be allocated.  The Briggs model requires each word of a
+   multiword register as a different object and the interference graph
+   may put in N**2 interferences between two pseudos (where N is the
+   number of words in the psuedo) to properly model how the two
+   pseudos interact.
+
+   With the model here, we loose all of that information and so two
+   multiword regs can never be allocated to the same set hard reg with
+   any skew.  We also cannot allocate a single word regsister in any
+   of the holes that may exist in a multiword hard register.
+
+   However, this is better than forcing the multiword pseudos into
+   separate hard regs if there is any interference between any of the
+   parts.
+*/ 
+struct allocno2_slot {
+  int a1;
+  int a2;
+};
+
+static htab_t mw_pseudos_table;
+
+/* Helper functions for the hash table.  */
+static int
+eq_allocno2 (const void *p1, const void *p2)
+{
+  const struct allocno2_slot *ds1 =
+    (const struct allocno2_slot *) p1;
+  const struct allocno2_slot *ds2 =
+    (const struct allocno2_slot *) p2;
+
+  return ds1->a1 == ds2->a1 && ds1->a2 == ds2->a2;
+}
+
+static hashval_t
+hash_allocno2 (const void *p)
+{
+  const struct allocno2_slot *ds = (const struct allocno2_slot *) p;
+  return (hashval_t) ds->a1 * ds->a2;
+}
+
+
+/* Initialized the datastructures.  */
+static void 
+ra_init_aligned_mw_pseudos (void)
+{
+  mw_pseudos_table
+    = htab_create (37, hash_allocno2, eq_allocno2, free);
+}
+
+
+/* Called from global to get rid of the datastructures.  */
+
+void 
+ra_free_aligned_mw_pseudos (void)
+{
+  if (mw_pseudos_table)
+    htab_delete (mw_pseudos_table);
+  mw_pseudos_table = NULL;
+}
+
+
+/* Indicate that ALLOCNO1 and ALLOCNO2 can be allocated to the same
+   set of registers.  */
+
+static void 
+ra_add_aligned_mw_pseudos (int allocno1, int allocno2)
+{
+  void **slot;
+  struct allocno2_slot a_slot;
+
+  if (allocno1 == allocno2)
+    return;
+  if (allocno1 > allocno2)
+    {
+      int tmp = allocno1;
+      allocno1 = allocno2;
+      allocno2 = tmp;
+    }
+
+  a_slot.a1 = allocno1;
+  a_slot.a2 = allocno2;
+
+  slot = htab_find_slot (mw_pseudos_table, &a_slot, INSERT);
+  if (*slot == NULL)
+    {
+      struct allocno2_slot *new_slot = xmalloc (sizeof (struct allocno2_slot));
+
+      if (dump_file)
+	fprintf (dump_file, "    adding mw pair %d<->%d\n", allocno1, allocno2);
+
+      new_slot->a1 = allocno1;
+      new_slot->a2 = allocno2;
+      *slot = new_slot;
+    }
+}
+
+/* Return true if ALLOCNO1 and ALLOCNO2 can be allocated to the same
+   set of registers even though there is an interference between
+   ALLOCNO1 and ALLOCNO2.  */
+
+bool
+ra_aligned_mw_pseudos_p (int allocno1, int allocno2)
+{
+  struct allocno2_slot a_slot;
+
+  if (allocno1 == allocno2)
+    return true;
+  if (allocno1 > allocno2)
+    {
+      int tmp = allocno1;
+      allocno1 = allocno2;
+      allocno2 = tmp;
+    }
+
+  a_slot.a1 = allocno1;
+  a_slot.a2 = allocno2;
+
+  return htab_find_slot (mw_pseudos_table, &a_slot, NO_INSERT) != NULL;
+}
+
+
+/* Helper function for finalize_mw_pseudos.  */
+
+static int
+ra_reset_mw_interferences (void ** p, void * not_used ATTRIBUTE_UNUSED)
+{
+  const struct allocno2_slot *as =
+    *(const struct allocno2_slot **) p;
+
+  if (ra_conflict_p (as->a1, as->a2))
+    {
+      /* We see a real interference between these two pseudos, do not
+	 allow aligned allocation.  */
+      if (dump_file)
+	fprintf (dump_file, "    removing mw pair %d<->%d\n", as->a1, as->a2);
+      htab_clear_slot (mw_pseudos_table, p);
+    }
+  else
+    /* There was no real interference if the pseudos are allocated
+       perfectly aligned.  But we need to add an interference here
+       because this is the protocol.  */  
+    set_conflict (as->a1, as->a2);
+
+  return true;
+}
+
+/* Traverse all of the elements in the mw_pseudos_table fixing up the
+   places where the mw code thought that it was ok to put the two mw
+   pseudos in the same place but interference were generated for other
+   reasons.  */
+
+static void
+ra_finalize_mw_pseudos (void)
+{
+  htab_traverse_noresize (mw_pseudos_table, ra_reset_mw_interferences, NULL);
+}
+
+
+/* Helper function for finalize_mw_pseudos.  */
+
+static int
+ra_dump_mw_reg_pair (void ** p, void * vfile)
+{
+  const struct allocno2_slot *as =
+    *(const struct allocno2_slot **) p;
+
+  FILE *file = (FILE *)vfile; 
+
+  fprintf (file, ";; %d can be paired with %d\n", 
+	   allocno[as->a1].reg, allocno[as->a2].reg);
+
+  return true;
+}
+
+/* Traverse all of the elements in the mw_pseudos_table fixing up the
+   places where the mw code thought that it was ok to put the two mw
+   pseudos in the same place but interference were generated for other
+   reasons.  */
+
+void
+ra_dump_mw_reg_pairs (FILE *file)
+{
+  fprintf (file, "\n"); 
+  htab_traverse_noresize (mw_pseudos_table, ra_dump_mw_reg_pair, file);
+  fprintf (file, "\n"); 
+}
+
+
+/* Return true if ALLOCNO1 which is a partially live multiword reg
+   with mode MODE1 does not conflict with ALLOCNO2 if the two regs are
+   perfectly aligned.  At this point no check has been done to assure
+   that ALLOCNO2 is even a proper mwreg.  */
+
+static bool
+ra_check_mw (sbitmap *live_subregs, bitmap live_subregs_used,
+	  int allocno1, enum machine_mode mode1, int allocno2)
+{
+  rtx mw_reg2 = regno_reg_rtx[allocno[allocno2].reg];
+  enum machine_mode mode2 = GET_MODE (mw_reg2);
+  int size = GET_MODE_SIZE (mode1);
+  int i;
+ 
+  /* FIXME!!, This may be too restrictive, it may be enough to just
+     check that they are the same size.  */
+  if (mode1 != mode2)
+    return false;
+
+  if (!bitmap_bit_p (live_subregs_used, allocno2))
+    return false;
+
+  /* The two regs can be allocated on an aligned basis if, for every
+     word in the reg, at least one of the regs is not live.  */
+  for (i = 0; i < size; i += UNITS_PER_WORD)
+    if (sbitmap_range_empty_p (live_subregs[allocno1], i, UNITS_PER_WORD)
+	|| sbitmap_range_empty_p (live_subregs[allocno2], i, UNITS_PER_WORD))
+      continue;
+    else
+      return false;
+
+  ra_add_aligned_mw_pseudos (allocno1, allocno2);
+
+  return true;
+}
+
+ 
+/* Add conflict edges between ALLOCNO1 and all allocnos currently
+   live.  */
 
 static void
-set_conflicts (int allocno1, sparseset live)
+set_conflicts (sbitmap *live_subregs, bitmap live_subregs_used,
+	       int allocno1, sparseset live)
 {
   int i;
   HOST_WIDE_INT bitnum, index;
   HOST_WIDEST_FAST_INT word, mask;
   HOST_WIDE_INT partial_bitnum_allocno1;
+  rtx mw_reg = regno_reg_rtx[allocno[allocno1].reg];
+  enum machine_mode mw_mode = GET_MODE (mw_reg);
+  bool need_mw_check = (GET_MODE_SIZE (mw_mode) > UNITS_PER_WORD) 
+    && bitmap_bit_p (live_subregs_used, allocno1);
 
 #ifdef ENABLE_CHECKING
   gcc_assert (allocno1 >= 0 && allocno1 < max_allocno);
@@ -162,6 +439,13 @@ set_conflicts (int allocno1, sparseset l
     if (allocno1 == i)
       continue;
 
+    /* If allocno1 is a multiword reg that only some of the subregs
+       are used, check to see if i can be allocated in the same
+       reg.  */
+    if (need_mw_check 
+	&& ra_check_mw (live_subregs, live_subregs_used, allocno1, mw_mode, i))
+      continue;
+
 #ifdef ENABLE_CHECKING
     gcc_assert (i >= 0 && i < max_allocno);
 #endif
@@ -186,7 +470,10 @@ set_conflicts (int allocno1, sparseset l
 }
 
 
-/* Add a conflict between R1 and R2.  */
+/* Add a conflict between R1 and R2.  Note that this function is only
+   called for oddball cases and it not called for the regular case of
+   adding interferences between where registers are set the other
+   registers are live.  */
 
 static void
 record_one_conflict_between_regnos (enum machine_mode mode1, int r1, 
@@ -226,7 +513,8 @@ record_one_conflict_between_regnos (enum
    before calling here.  */
 
 static void
-record_one_conflict (sparseset allocnos_live, 
+record_one_conflict (sparseset allocnos_live, sbitmap *live_subregs, 
+		     bitmap live_subregs_used,
 		     HARD_REG_SET *hard_regs_live, int regno)
 {
   int i;
@@ -256,14 +544,14 @@ record_one_conflict (sparseset allocnos_
 	  
 	  EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
 	    {
-	      if (!conflict_p (ialloc, i))
+	      if (!ra_conflict_p (ialloc, i))
 		fprintf (dump_file, "%d ", allocno[i].reg);
 	    }
 	  fprintf (dump_file, ")\n");
 	}
 
       IOR_HARD_REG_SET (allocno[ialloc].hard_reg_conflicts, *hard_regs_live);
-      set_conflicts (ialloc, allocnos_live);
+      set_conflicts (live_subregs, live_subregs_used, ialloc, allocnos_live);
     }
 }
 
@@ -277,6 +565,8 @@ record_one_conflict (sparseset allocnos_
 
 static void
 mark_reg_store (sparseset allocnos_live, 
+		sbitmap *live_subregs, 
+		bitmap live_subregs_used,
 		HARD_REG_SET *hard_regs_live, 
 		struct df_ref *ref)
 {
@@ -287,7 +577,8 @@ mark_reg_store (sparseset allocnos_live,
   /* 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 && reg_allocno[regno] >= 0)
-    record_one_conflict (allocnos_live, hard_regs_live, regno);
+    record_one_conflict (allocnos_live, live_subregs, live_subregs_used, 
+			 hard_regs_live, regno);
 
   if (reg_renumber[regno] >= 0)
     regno = reg_renumber[regno];
@@ -297,7 +588,8 @@ mark_reg_store (sparseset allocnos_live,
     {
       unsigned int start = regno;
       unsigned int last = end_hard_regno (mode, regno);
-      if ((GET_CODE (reg) == SUBREG) && !DF_REF_FLAGS_IS_SET (ref, DF_REF_ZERO_EXTRACT))
+      if ((GET_CODE (reg) == SUBREG) 
+	  && !DF_REF_FLAGS_IS_SET (ref, DF_REF_ZERO_EXTRACT))
 	{
 	  start += subreg_regno_offset (regno, GET_MODE (SUBREG_REG (reg)),
 					SUBREG_BYTE (reg), GET_MODE (reg));
@@ -306,7 +598,8 @@ mark_reg_store (sparseset allocnos_live,
 
       regno = start;
       while (regno < last)
-	record_one_conflict (allocnos_live, hard_regs_live, regno++);
+	record_one_conflict (allocnos_live, live_subregs, live_subregs_used, 
+			     hard_regs_live, regno++);
     }
 }
 
@@ -376,7 +669,8 @@ set_conflicts_for_earlyclobber (rtx insn
 	  if (GET_CODE (dreg) == SUBREG)
 	    dreg = SUBREG_REG (dreg);
 	  if (REG_P (dreg)
-	      &&  may_overlap_class_p (dmode, REGNO (dreg), recog_op_alt[def][alt].cl))
+	      &&  may_overlap_class_p (dmode, REGNO (dreg), 
+				       recog_op_alt[def][alt].cl))
 
 	    for (use = 0; use < recog_data.n_operands; use++)
 	      if (use != def
@@ -411,82 +705,69 @@ set_conflicts_for_earlyclobber (rtx insn
 void
 ra_init_live_subregs (bool init_value, 
 		      sbitmap *live_subregs, 
-		      int *live_subregs_used,
+		      bitmap live_subregs_used,
 		      int allocnum, 
 		      rtx reg)
 {
-  unsigned int regno = REGNO (SUBREG_REG (reg));
+  unsigned int regno 
+    = REGNO ((GET_CODE (reg) == SUBREG) ? SUBREG_REG (reg) : reg);
   int size = GET_MODE_SIZE (GET_MODE (regno_reg_rtx[regno]));
 
   gcc_assert (size > 0);
 
   /* Been there, done that.  */
-  if (live_subregs_used[allocnum])
+  if (bitmap_bit_p (live_subregs_used, allocnum))
     return;
-
+  
   /* Create a new one with zeros.  */
   if (live_subregs[allocnum] == NULL)
     live_subregs[allocnum] = sbitmap_alloc (size);
-
+  
   /* If the entire reg was live before blasting into subregs, we need
      to init all of the subregs to ones else init to 0.  */
   if (init_value)
     sbitmap_ones (live_subregs[allocnum]);
   else 
     sbitmap_zero (live_subregs[allocnum]);
-
+  
   /* Set the number of bits that we really want.  */
-  live_subregs_used[allocnum] = size;
+  bitmap_set_bit (live_subregs_used, allocnum);
 }
 
-
 /* Set REG to be not live in the sets ALLOCNOS_LIVE, LIVE_SUBREGS,
    HARD_REGS_LIVE.  DEF is the definition of the register.  */
 
 inline static void
 clear_reg_in_live (sparseset allocnos_live,
 		   sbitmap *live_subregs, 
-		   int *live_subregs_used,
+		   bitmap live_subregs_used,
 		   HARD_REG_SET *hard_regs_live, 
-		   rtx reg, struct df_ref *def)
+		   struct df_ref *def)
 {
+  rtx reg = DF_REF_REG (def);
   unsigned int regno = (GET_CODE (reg) == SUBREG) 
     ? REGNO (SUBREG_REG (reg)): REGNO (reg);
   int allocnum = reg_allocno[regno];
 
   if (allocnum >= 0)
     {
-      if (GET_CODE (reg) == SUBREG
-	  && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
+      unsigned int start;
+      unsigned int last;
+	  
+      if (!df_compute_accessed_bytes (def, &start, &last))
 	{
-	  unsigned int start = SUBREG_BYTE (reg);
-	  unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
-
 	  ra_init_live_subregs (sparseset_bit_p (allocnos_live, allocnum), 
 				live_subregs, live_subregs_used, allocnum, 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[allocnum])
-	    last = live_subregs_used[allocnum];
-
 	  while (start < last)
 	    {
 	      RESET_BIT (live_subregs[allocnum], start);
 	      start++;
 	    }
-
+	  
 	  if (sbitmap_empty_p (live_subregs[allocnum]))
 	    {
-	      live_subregs_used[allocnum] = 0;
+	      bitmap_clear_bit (live_subregs_used, allocnum);
 	      sparseset_clear_bit (allocnos_live, allocnum);
 	    }
 	  else
@@ -496,9 +777,10 @@ clear_reg_in_live (sparseset allocnos_li
 	}
       else
 	{
-	  /* Resetting the live_subregs_used is effectively saying do not use the 
-	     subregs because we are writing the whole pseudo.  */
-	  live_subregs_used[allocnum] = 0;
+	  /* Resetting the live_subregs_used is effectively saying do
+	     not use the subregs because we are writing the whole
+	     pseudo.  */
+	  bitmap_clear_bit (live_subregs_used, allocnum);
 	  sparseset_clear_bit (allocnos_live, allocnum);
 	}
     }
@@ -530,7 +812,6 @@ clear_reg_in_live (sparseset allocnos_li
 }
 
 
-
 /* Set REG to be live in the sets ALLOCNOS_LIVE, LIVE_SUBREGS,
    HARD_REGS_LIVE.  If EXTRACT is false, assume that the entire reg is
    set live even if REG is a subreg.  */
@@ -538,10 +819,9 @@ clear_reg_in_live (sparseset allocnos_li
 inline static void
 set_reg_in_live (sparseset allocnos_live, 
 		 sbitmap *live_subregs, 
-		 int *live_subregs_used,
+		 bitmap live_subregs_used,
 		 HARD_REG_SET *hard_regs_live, 
-		 rtx reg,
-		 bool extract)
+		 rtx reg, struct df_ref *def)
 {
   unsigned int regno = (GET_CODE (reg) == SUBREG) 
     ? REGNO (SUBREG_REG (reg)): REGNO (reg);
@@ -549,18 +829,17 @@ set_reg_in_live (sparseset allocnos_live
 
   if (allocnum >= 0)
     {
-      if ((GET_CODE (reg) == SUBREG) && !extract)
-	{
-	  unsigned int start = SUBREG_BYTE (reg);
-	  unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
+      unsigned int start;
+      unsigned int last;
 
+      /* Have to check that a def was passed, otherwise, this is
+	 called from the bottom of the block to get things started for
+	 that block and there are no df_refs there.  */
+      if (def && !df_compute_accessed_bytes (def, &start, &last))
+	{
 	  ra_init_live_subregs (sparseset_bit_p (allocnos_live, allocnum), 
 				live_subregs, live_subregs_used, allocnum, reg);
 	  
-	  /* Ignore the paradoxical bits.  */
-	  if ((int)last > live_subregs_used[allocnum])
-	    last = live_subregs_used[allocnum];
-
 	  while (start < last)
 	    {
 	      SET_BIT (live_subregs[allocnum], start);
@@ -568,20 +847,21 @@ set_reg_in_live (sparseset allocnos_live
 	    }
 	}
       else
-	/* Resetting the live_subregs_used is effectively saying do not use the 
-	   subregs because we are writing the whole pseudo.  */
-	  live_subregs_used[allocnum] = 0;
-     
+	/* Resetting the live_subregs_used is effectively saying do
+	   not use the subregs because we are writing the whole
+	   pseudo.  */
+	bitmap_clear_bit (live_subregs_used, allocnum);
+      
       sparseset_set_bit (allocnos_live, allocnum);
     }
-      
+
   if (regno >= FIRST_PSEUDO_REGISTER)
     return;
 
   /* Handle hardware regs (and pseudos allocated to hard regs).  */
   if (! fixed_regs[regno])
     {
-      if ((GET_CODE (reg) == SUBREG) && !extract)
+      if (def && (GET_CODE (reg) == SUBREG))
 	{
 	  unsigned int start = regno;
 	  unsigned int last;
@@ -609,17 +889,15 @@ set_reg_in_live (sparseset allocnos_live
 
    We are smart about the case where only subregs of REG have been
    set, as indicated by LIVE_SUBREGS[ALLOCNUM] and
-   LIVE_SUBREGS_USED[ALLOCNUM].  See global_conflicts for description
+   LIVE_SUBREGS_USED[ALLOCNUM].  See ra_global_conflicts for description
    of LIVE_SUBREGS and LIVE_SUBREGS_USED.  */
 
 inline static void
 set_renumbers_live (HARD_REG_SET *renumbers_live,   
 		    sbitmap *live_subregs, 
-		    int *live_subregs_used,
+		    bitmap live_subregs_used,
 		    int allocnum, int renumber)
 {
-  /* The width of the pseudo.  */
-  int nbytes = live_subregs_used[allocnum];
   int regno = allocno[allocnum].reg;
   enum machine_mode mode = GET_MODE (regno_reg_rtx[regno]);
 
@@ -627,10 +905,12 @@ set_renumbers_live (HARD_REG_SET *renumb
     fprintf (dump_file, "  set_renumbers_live %d->%d ", 
 	     regno, renumber);
 
-  if (nbytes > 0)
+  if (bitmap_bit_p (live_subregs_used, allocnum))
     {
       int i;
       sbitmap live_subs = live_subregs[allocnum];
+      /* The width of the pseudo.  */
+      int nbytes = live_subregs[allocnum]->n_bits;
 
       /* First figure out how many hard regs we are considering using.  */
       int target_nregs = hard_regno_nregs[renumber][mode];
@@ -679,19 +959,19 @@ dump_ref (FILE *file, 
 	  rtx reg,
 	  unsigned int regno,
 	  sbitmap *live_subregs, 
-	  int *live_subregs_used
+	  bitmap live_subregs_used
 )
 {
   int allocnum = reg_allocno[regno];
 
   fprintf (file, "%s %d", prefix, regno);
-  if (allocnum >= 0 
-      && live_subregs_used[allocnum] > 0)
+  if (allocnum >= 0 && bitmap_bit_p (live_subregs_used, allocnum))
     {
       int j;
       char s = '[';
-      
-      for (j = 0; j < live_subregs_used[allocnum]; j++)
+      int n_bytes = live_subregs[allocnum]->n_bits;
+
+      for (j = 0; j < n_bytes; j++)
 	if (TEST_BIT (live_subregs[allocnum], j))
 	  {
 	    fprintf (dump_file, "%c%d", s, j);
@@ -726,11 +1006,11 @@ dump_ref (FILE *file, 
 }
 
 
-/* Scan the rtl code and record all conflicts and register preferences in the
-   conflict matrices and preference tables.  */
+/* Scan the rtl code and record all conflicts and register preferences
+   in the conflict matrices and preference tables.  */
 
 void
-global_conflicts (void)
+ra_global_conflicts (void)
 {
   unsigned int i;
   basic_block bb;
@@ -745,18 +1025,19 @@ global_conflicts (void)
   HARD_REG_SET renumbers_live;
   sparseset allocnos_live;
   bitmap live = BITMAP_ALLOC (NULL);
-  VEC (df_ref_t, heap) *clobbers = NULL;
-  VEC (df_ref_t, heap) *dying_regs = NULL;
 
-  /* live_subregs is a vector used to keep accurate information about
-     which hardregs are live in multiword pseudos.  live_subregs and
+  /* Live_subregs is a vector used to keep accurate information about
+     which hardregs are live in multiword pseudos.  Live_subregs and
      live_subregs_used are indexed by reg_allocno.  The live_subreg
-     entry for a particular pseudo is a bitmap with one bit per byte
+     entry for a particular pseudo is an sbitmap with one bit per byte
      of the register.  It is only used if the corresponding element is
-     non zero in live_subregs_used.  The value in live_subregs_used is
-     number of bytes that the pseudo can occupy.  */
+     set in live_subregs_used.  */
   sbitmap *live_subregs = XCNEWVEC (sbitmap, max_allocno);
-  int *live_subregs_used = XNEWVEC (int, max_allocno);
+  bitmap live_subregs_used = BITMAP_ALLOC (NULL);
+
+  VEC (df_ref_t, heap) *clobbers = NULL;
+  VEC (df_ref_t, heap) *dying_regs = NULL;
+  ra_init_aligned_mw_pseudos ();
 
   if (dump_file)
     {
@@ -777,7 +1058,6 @@ global_conflicts (void)
       df_simulate_artificial_refs_at_end (bb, live);
 
       sparseset_clear (allocnos_live);
-      memset (live_subregs_used, 0, max_allocno * sizeof (int));
       CLEAR_HARD_REG_SET (hard_regs_live);
       CLEAR_HARD_REG_SET (renumbers_live);
 
@@ -800,9 +1080,10 @@ global_conflicts (void)
 	      rtx reg = regno_reg_rtx[i];
 
 	      set_reg_in_live (allocnos_live, live_subregs, live_subregs_used, 
-			       &hard_regs_live, reg, false);
+			       &hard_regs_live, reg, NULL);
 	      if (renumber >= 0 && renumber < FIRST_PSEUDO_REGISTER)
-		set_renumbers_live (&renumbers_live, live_subregs, live_subregs_used, 
+		set_renumbers_live (&renumbers_live, live_subregs, 
+				    live_subregs_used, 
 				    allocnum, renumber);
 	    }
 	} 
@@ -862,12 +1143,13 @@ global_conflicts (void)
 	      if (!DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER))
 		{
 		  rtx reg = DF_REF_REG (def);
-		  set_reg_in_live (allocnos_live, live_subregs, live_subregs_used, 
-				   &hard_regs_live, reg, 
-				   DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT));
+		  set_reg_in_live (allocnos_live, live_subregs, 
+				   live_subregs_used, 
+				   &hard_regs_live, reg, def);
 		  if (dump_file)
 		    dump_ref (dump_file, "  adding def", "\n",
-			      reg, DF_REF_REGNO (def), live_subregs, live_subregs_used);
+			      reg, DF_REF_REGNO (def), live_subregs, 
+			      live_subregs_used);
 		}
 	    }
 	  
@@ -882,7 +1164,8 @@ global_conflicts (void)
 	    {
 	      struct df_ref *def = *def_rec;
 	      if (!DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER))
-		mark_reg_store (allocnos_live, &renumbers_live, def);
+		mark_reg_store (allocnos_live, live_subregs, 
+				live_subregs_used, &renumbers_live, def);
 	    }
 	  
 	  /* Remove the defs from the live sets.  Leave the partial
@@ -897,11 +1180,13 @@ global_conflicts (void)
 		{
 		  rtx reg = DF_REF_REG (def);
 
-		  clear_reg_in_live (allocnos_live, live_subregs, live_subregs_used,
-				     &hard_regs_live, reg, def);
+		  clear_reg_in_live (allocnos_live, live_subregs, 
+				     live_subregs_used,
+				     &hard_regs_live, def);
 		  if (dump_file)
 		    dump_ref (dump_file, "  clearing def", "\n", 
-			      reg, DF_REF_REGNO (def), live_subregs, live_subregs_used);
+			      reg, DF_REF_REGNO (def), live_subregs, 
+			      live_subregs_used);
 		}
 	      
 	      if (DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER))
@@ -921,7 +1206,8 @@ global_conflicts (void)
 	      int renumber = reg_renumber[regno];
 
 	      if (renumber >= 0 && renumber < FIRST_PSEUDO_REGISTER)
-		set_renumbers_live (&renumbers_live, live_subregs, live_subregs_used, 
+		set_renumbers_live (&renumbers_live, live_subregs, 
+				    live_subregs_used, 
 				    i, renumber);
 	    }
 					 
@@ -939,15 +1225,13 @@ global_conflicts (void)
 	      bool renumbering = false;
 	      rtx reg = DF_REF_REG (use);
 
-	      /* DF_REF_READ_WRITE on a use means that this use is
-		 fabricated from a def that is a partial set to a
-		 multiword reg.  Here, we only model the subreg case
-		 precisely so we do not need to look at the fabricated
-		 use unless that set also happens to wrapped in a
-		 ZERO_EXTRACT. */
-	      if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE) 
-		  && (!DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT)) 
-		  && DF_REF_FLAGS_IS_SET (use, DF_REF_SUBREG))
+	      /* DF_REF_READ_WRITE on a use generally means that this
+		 use is fabricated from a def that is a partial set to
+		 a multiword reg.  Here, we only model those cases
+		 precisely so the only one to consider is the use put
+		 on a auto inc and dec insns.  */
+	      if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE)
+		  && (!DF_REF_FLAGS_IS_SET (use, DF_REF_PRE_POST_MODIFY)))
 		continue;
 	      
 	      if (dump_file)
@@ -956,25 +1240,24 @@ global_conflicts (void)
 
 	      if (allocnum >= 0)
 		{
-		  if (GET_CODE (reg) == SUBREG
-		      && !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT)) 
+		  unsigned int start;
+		  unsigned int last;
+		  
+		  if (!df_compute_accessed_bytes (use, &start, &last))
 		    {
-		      unsigned int start = SUBREG_BYTE (reg);
-		      unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
-
-		      ra_init_live_subregs (sparseset_bit_p (allocnos_live, allocnum), 
-					    live_subregs, live_subregs_used, allocnum, reg);
-		      
-		      /* Ignore the paradoxical bits.  */
-		      if ((int)last > live_subregs_used[allocnum])
-			last = live_subregs_used[allocnum];
+		      ra_init_live_subregs (sparseset_bit_p (allocnos_live, 
+							     allocnum), 
+					    live_subregs, live_subregs_used, 
+					    allocnum, reg);
 		      
 		      while (start < last)
 			{
 			  if (!TEST_BIT (live_subregs[allocnum], start)) 
 			    {
 			      if (dump_file)
-				fprintf (dump_file, "    dying pseudo subreg %d[%d]\n", regno, start);
+				fprintf (dump_file, 
+					 "    dying pseudo subreg %d[%d]\n", 
+					 regno, start);
 			      SET_BIT (live_subregs[allocnum], start);
 			      
 			      added = true;
@@ -984,22 +1267,25 @@ global_conflicts (void)
 		      
 		      sparseset_set_bit (allocnos_live, allocnum);
 		      if (renumber >= 0 && renumber < FIRST_PSEUDO_REGISTER)
-			set_renumbers_live (&renumbers_live, live_subregs, live_subregs_used, 
+			set_renumbers_live (&renumbers_live, live_subregs, 
+					    live_subregs_used, 
 					    allocnum, renumber);
 		    }
-		  else if (live_subregs_used[allocnum] > 0
+		  else if (bitmap_bit_p (live_subregs_used, allocnum)
 			   || !sparseset_bit_p (allocnos_live, allocnum))
 		    {
 		      if (dump_file)
 			fprintf (dump_file, "    %sdying pseudo\n", 
-				 (live_subregs_used[allocnum] > 0) ? "partially ": "");
+				 (bitmap_bit_p (live_subregs_used, allocnum)) 
+				 ? "partially ": "");
 		      /* Resetting the live_subregs_used is
 			 effectively saying do not use the subregs
 			 because we are reading the whole pseudo.  */
-		      live_subregs_used[allocnum] = 0;
+		      bitmap_clear_bit (live_subregs_used, allocnum);
 		      sparseset_set_bit (allocnos_live, allocnum);
 		      if (renumber >= 0 && renumber < FIRST_PSEUDO_REGISTER)
-			set_renumbers_live (&renumbers_live, live_subregs, live_subregs_used, 
+			set_renumbers_live (&renumbers_live, live_subregs, 
+					    live_subregs_used, 
 					    allocnum, renumber);
 		      added = true;
 		    }
@@ -1017,8 +1303,10 @@ global_conflicts (void)
 		  unsigned int last;
 		  if (GET_CODE (reg) == SUBREG)
 		    {
-		      start += subreg_regno_offset (regno, GET_MODE (SUBREG_REG (reg)),
-						    SUBREG_BYTE (reg), GET_MODE (reg));
+		      start += subreg_regno_offset (regno, 
+						    GET_MODE (SUBREG_REG (reg)),
+						    SUBREG_BYTE (reg), 
+						    GET_MODE (reg));
 		      last = start + subreg_nregs_with_regno (regno, reg);
 		    }
 		  else
@@ -1032,7 +1320,8 @@ global_conflicts (void)
 			  && ! fixed_regs[regno])
 			{
 			  if (dump_file)
-			    fprintf (dump_file, "    dying hard reg %d\n", regno);
+			    fprintf (dump_file, "    dying hard reg %d\n", 
+				     regno);
 			  if (renumbering)
 			    SET_HARD_REG_BIT (renumbers_live, regno);
 			  else
@@ -1189,7 +1478,8 @@ global_conflicts (void)
 	      unsigned int regno = EH_RETURN_DATA_REGNO (i);
 	      if (regno == INVALID_REGNUM)
 		break;
-	      record_one_conflict (allocnos_live, &hard_regs_live, regno);
+	      record_one_conflict (allocnos_live, live_subregs, live_subregs_used, 
+				   &hard_regs_live, regno);
 	    }
 
 	  EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
@@ -1214,7 +1504,8 @@ global_conflicts (void)
 	    }
 
 	  for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
-	    record_one_conflict (allocnos_live, &hard_regs_live, i);
+	    record_one_conflict (allocnos_live, live_subregs, live_subregs_used, 
+				 &hard_regs_live, i);
 #endif
 	  
 	  /* No need to record conflicts for call clobbered regs if we have
@@ -1223,7 +1514,8 @@ global_conflicts (void)
 	  if (! current_function_has_nonlocal_label)
 	    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	      if (call_used_regs [i])
-		record_one_conflict (allocnos_live, &hard_regs_live, i);
+		record_one_conflict (allocnos_live, live_subregs, live_subregs_used, 
+				     &hard_regs_live, i);
 	}
     }
   
@@ -1231,11 +1523,13 @@ global_conflicts (void)
     if (live_subregs[i])
       free (live_subregs[i]);
 
+  ra_finalize_mw_pseudos ();
+  
   /* Clean up.  */
-  free (allocnos_live);
+  sparseset_free (allocnos_live);
   free (live_subregs);
-  free (live_subregs_used);
   VEC_free (df_ref_t, heap, dying_regs);
   VEC_free (df_ref_t, heap, clobbers);
+  BITMAP_FREE (live_subregs_used);
   BITMAP_FREE (live);
 }
Index: bitmap.h
===================================================================
--- bitmap.h	(revision 133475)
+++ bitmap.h	(working copy)
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  
 #define GCC_BITMAP_H
 #include "hashtab.h"
 #include "statistics.h"
+#include "obstack.h"
 
 /* Fundamental storage type for bitmap.  */
 
Index: df-scan.c
===================================================================
--- df-scan.c	(revision 133475)
+++ df-scan.c	(working copy)
@@ -95,7 +95,7 @@ static struct df_mw_hardreg * df_null_mw
 static void df_ref_record (struct df_collection_rec *,
 			   rtx, rtx *, 
 			   basic_block, rtx, enum df_ref_type, 
-			   enum df_ref_flags, int, int);
+			   enum df_ref_flags, int, int, enum machine_mode);
 static void df_def_record_1 (struct df_collection_rec *,
 			     rtx, basic_block, rtx,
 			     enum df_ref_flags);
@@ -104,11 +104,13 @@ static void df_defs_record (struct df_co
 			    enum df_ref_flags);
 static void df_uses_record (struct df_collection_rec *,
 			    rtx *, enum df_ref_type,
-			    basic_block, rtx, enum df_ref_flags, int, int);
+			    basic_block, rtx, enum df_ref_flags, 
+			    int, int, enum machine_mode);
 
 static struct df_ref *df_ref_create_structure (struct df_collection_rec *, rtx, rtx *, 
 					       basic_block, rtx, enum df_ref_type, 
-					       enum df_ref_flags, int, int);
+					       enum df_ref_flags, 
+					       int, int, enum machine_mode);
 
 static void df_insn_refs_collect (struct df_collection_rec*, 
 				  basic_block, rtx); 
@@ -616,16 +618,16 @@ df_scan_blocks (void)
    LOC within INSN of BB.  This function is only used externally. 
 
    If the REF_FLAGS field contain DF_REF_SIGN_EXTRACT or
-   DF_REF_ZERO_EXTRACT.  WIDTH and OFFSET are used to access the fields
-   if they were constants.  Otherwise they should be -1 if those flags
-   were set.  */
+   DF_REF_ZERO_EXTRACT.  WIDTH, OFFSET and MODE are used to access the
+   fields if they were constants.  Otherwise they should be -1 if
+   those flags were set.  */
 
 struct df_ref *
 df_ref_create (rtx reg, rtx *loc, rtx insn, 
 	       basic_block bb,
 	       enum df_ref_type ref_type, 
 	       enum df_ref_flags ref_flags,
-	       int width, int offset)
+	       int width, int offset, enum machine_mode mode)
 {
   struct df_ref *ref;
   struct df_reg_info **reg_info;
@@ -640,7 +642,8 @@ df_ref_create (rtx reg, rtx *loc, rtx in
   /* You cannot hack artificial refs.  */
   gcc_assert (insn);
   ref = df_ref_create_structure (NULL, reg, loc, bb, insn,
-                                 ref_type, ref_flags, width, offset);
+                                 ref_type, ref_flags, 
+				 width, offset, mode);
 
   if (DF_REF_TYPE (ref) == DF_REF_REG_DEF)
     {
@@ -2066,7 +2069,7 @@ df_notes_rescan (rtx insn)
 	    case REG_EQUAL:
 	      df_uses_record (&collection_rec,
 			      &XEXP (note, 0), DF_REF_REG_USE,
-			      bb, insn, DF_REF_IN_NOTE, -1, -1);
+			      bb, insn, DF_REF_IN_NOTE, -1, -1, 0);
 	    default:
 	      break;
 	    }
@@ -2142,8 +2145,9 @@ df_ref_equal_p (struct df_ref *ref1, str
      compared in the next set of tests.  */
   if ((DF_REF_FLAGS_IS_SET (ref1, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
       && (DF_REF_FLAGS_IS_SET (ref2, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
-      && ((DF_REF_OFFSET (ref1) != DF_REF_OFFSET (ref2))
-	  || (DF_REF_WIDTH (ref1) != DF_REF_WIDTH (ref2))))
+      && ((DF_REF_EXTRACT_OFFSET (ref1) != DF_REF_EXTRACT_OFFSET (ref2))
+	  || (DF_REF_EXTRACT_WIDTH (ref1) != DF_REF_EXTRACT_WIDTH (ref2))
+	  || (DF_REF_EXTRACT_MODE (ref1) != DF_REF_EXTRACT_MODE (ref2))))
     return false;
 
   return (ref1 == ref2) ||
@@ -2199,10 +2203,12 @@ df_ref_compare (const void *r1, const vo
      at ref1.  */
   if (DF_REF_FLAGS_IS_SET (ref1, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
     {
-      if (DF_REF_OFFSET (ref1) != DF_REF_OFFSET (ref2))
-	return DF_REF_OFFSET (ref1) - DF_REF_OFFSET (ref2);
-      if (DF_REF_WIDTH (ref1) != DF_REF_WIDTH (ref2))
-	return DF_REF_WIDTH (ref1) - DF_REF_WIDTH (ref2);
+      if (DF_REF_EXTRACT_OFFSET (ref1) != DF_REF_EXTRACT_OFFSET (ref2))
+	return DF_REF_EXTRACT_OFFSET (ref1) - DF_REF_EXTRACT_OFFSET (ref2);
+      if (DF_REF_EXTRACT_WIDTH (ref1) != DF_REF_EXTRACT_WIDTH (ref2))
+	return DF_REF_EXTRACT_WIDTH (ref1) - DF_REF_EXTRACT_WIDTH (ref2);
+      if (DF_REF_EXTRACT_MODE (ref1) != DF_REF_EXTRACT_MODE (ref2))
+	return DF_REF_EXTRACT_MODE (ref1) - DF_REF_EXTRACT_MODE (ref2);
     }
   return 0;
 }
@@ -2583,7 +2589,7 @@ df_refs_add_to_chains (struct df_collect
 /* Allocate a ref and initialize its fields. 
 
    If the REF_FLAGS field contain DF_REF_SIGN_EXTRACT or
-   DF_REF_ZERO_EXTRACT.  WIDTH and OFFSET are used to access the fields
+   DF_REF_ZERO_EXTRACT.  WIDTH, OFFSET and MODE are used to access the fields
    if they were constants.  Otherwise they should be -1 if those flags
    were set.  */
 
@@ -2593,7 +2599,7 @@ df_ref_create_structure (struct df_colle
 			 basic_block bb, rtx insn, 
 			 enum df_ref_type ref_type, 
 			 enum df_ref_flags ref_flags,
-			 int width, int offset)
+			 int width, int offset, enum machine_mode mode)
 {
   struct df_ref *this_ref;
   int regno = REGNO (GET_CODE (reg) == SUBREG ? SUBREG_REG (reg) : reg);
@@ -2603,8 +2609,9 @@ df_ref_create_structure (struct df_colle
   if (ref_flags & (DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
     {
       this_ref = pool_alloc (problem_data->ref_extract_pool);
-      DF_REF_WIDTH (this_ref) = width;
-      DF_REF_OFFSET (this_ref) = offset;
+      DF_REF_EXTRACT_WIDTH (this_ref) = width;
+      DF_REF_EXTRACT_OFFSET (this_ref) = offset;
+      DF_REF_EXTRACT_MODE (this_ref) = mode;
     }
   else
     this_ref = pool_alloc (problem_data->ref_pool);
@@ -2659,9 +2666,9 @@ df_ref_create_structure (struct df_colle
    at address LOC within INSN of BB. 
 
    If the REF_FLAGS field contain DF_REF_SIGN_EXTRACT or
-   DF_REF_ZERO_EXTRACT.  WIDTH and OFFSET are used to access the fields
-   if they were constants.  Otherwise they should be -1 if those flags
-   were set.  */
+   DF_REF_ZERO_EXTRACT.  WIDTH, OFFSET and MODE are used to access the
+   fields if they were constants.  Otherwise they should be -1 if
+   those flags were set.  */
 
 
 static void
@@ -2670,7 +2677,7 @@ df_ref_record (struct df_collection_rec 
 	       basic_block bb, rtx insn, 
 	       enum df_ref_type ref_type, 
 	       enum df_ref_flags ref_flags,
-	       int width, int offset) 
+	       int width, int offset, enum machine_mode mode) 
 {
   unsigned int regno;
 
@@ -2719,7 +2726,8 @@ df_ref_record (struct df_collection_rec 
       for (i = regno; i < endregno; i++)
 	{
 	  ref = df_ref_create_structure (collection_rec, regno_reg_rtx[i], loc, 
-					 bb, insn, ref_type, ref_flags, width, offset);
+					 bb, insn, ref_type, ref_flags, 
+					 width, offset, mode);
 
           gcc_assert (ORIGINAL_REGNO (DF_REF_REG (ref)) == i);
 	}
@@ -2728,7 +2736,7 @@ df_ref_record (struct df_collection_rec 
     {
       struct df_ref *ref;
       ref = df_ref_create_structure (collection_rec, reg, loc, bb, insn, 
-                                     ref_type, ref_flags, width, offset);
+                                     ref_type, ref_flags, width, offset, mode);
     }
 }
 
@@ -2764,6 +2772,7 @@ df_def_record_1 (struct df_collection_re
   rtx dst;
   int offset = -1;
   int width = -1;
+  enum machine_mode mode = 0;
 
  /* We may recursively call ourselves on EXPR_LIST when dealing with PARALLEL
      construct.  */
@@ -2808,6 +2817,7 @@ df_def_record_1 (struct df_collection_re
 	{
 	  width = INTVAL (XEXP (dst, 1));
 	  offset = INTVAL (XEXP (dst, 2));
+	  mode = GET_MODE (dst);
 	}
 
       loc = &XEXP (dst, 0);
@@ -2818,13 +2828,15 @@ df_def_record_1 (struct df_collection_re
   if (REG_P (dst))
     {
       df_ref_record (collection_rec, 
-		     dst, loc, bb, insn, DF_REF_REG_DEF, flags, width, offset);
+		     dst, loc, bb, insn, DF_REF_REG_DEF, flags, 
+		     width, offset, mode);
 
       /* We want to keep sp alive everywhere - by making all
 	 writes to sp also use of sp. */
       if (REGNO (dst) == STACK_POINTER_REGNUM)
 	df_ref_record (collection_rec,
-		       dst, NULL, bb, insn, DF_REF_REG_USE, flags, width, offset);
+		       dst, NULL, bb, insn, DF_REF_REG_USE, flags, 
+		       width, offset, mode);
     }
   else if (GET_CODE (dst) == SUBREG && REG_P (SUBREG_REG (dst)))
     {
@@ -2834,7 +2846,8 @@ df_def_record_1 (struct df_collection_re
       flags |= DF_REF_SUBREG;
 
       df_ref_record (collection_rec, 
-		     dst, loc, bb, insn, DF_REF_REG_DEF, flags, width, offset);
+		     dst, loc, bb, insn, DF_REF_REG_DEF, flags, 
+		     width, offset, mode);
     }
 }
 
@@ -2873,15 +2886,15 @@ df_defs_record (struct df_collection_rec
 /* Process all the registers used in the rtx at address LOC.  
 
    If the REF_FLAGS field contain DF_REF_SIGN_EXTRACT or
-   DF_REF_ZERO_EXTRACT.  WIDTH and LOWER are used to access the fields
-   if they were constants.  Otherwise they should be -1 if those flags
-   were set.  */
+   DF_REF_ZERO_EXTRACT.  WIDTH, OFFSET and MODE are used to access the
+   fields if they were constants.  Otherwise they should be -1 if
+   those flags were set.  */
 
 static void
 df_uses_record (struct df_collection_rec *collection_rec,
                 rtx *loc, enum df_ref_type ref_type,
 		basic_block bb, rtx insn, enum df_ref_flags flags,
-		int width, int offset)
+		int width, int offset, enum machine_mode mode)
 {
   RTX_CODE code;
   rtx x;
@@ -2912,7 +2925,8 @@ df_uses_record (struct df_collection_rec
       if (MEM_P (XEXP (x, 0)))
 	df_uses_record (collection_rec,
 			&XEXP (XEXP (x, 0), 0),
-			DF_REF_REG_MEM_STORE, bb, insn, flags, width, offset);
+			DF_REF_REG_MEM_STORE, bb, insn, flags, 
+			width, offset, mode);
 
       /* If we're clobbering a REG then we have a def so ignore.  */
       return;
@@ -2920,7 +2934,8 @@ df_uses_record (struct df_collection_rec
     case MEM:
       df_uses_record (collection_rec,
 		      &XEXP (x, 0), DF_REF_REG_MEM_LOAD, 
-		      bb, insn, flags & DF_REF_IN_NOTE, width, offset);
+		      bb, insn, flags & DF_REF_IN_NOTE, 
+		      width, offset, mode);
       return;
 
     case SUBREG:
@@ -2930,14 +2945,16 @@ df_uses_record (struct df_collection_rec
       if (!REG_P (SUBREG_REG (x)))
 	{
 	  loc = &SUBREG_REG (x);
-	  df_uses_record (collection_rec, loc, ref_type, bb, insn, flags, width, offset);
+	  df_uses_record (collection_rec, loc, ref_type, bb, insn, flags, 
+			  width, offset, mode);
 	  return;
 	}
       /* ... Fall through ...  */
 
     case REG:
       df_ref_record (collection_rec, 
-		     x, loc, bb, insn, ref_type, flags, width, offset);
+		     x, loc, bb, insn, ref_type, flags, 
+		     width, offset, mode);
       return;
 
     case SIGN_EXTRACT:
@@ -2951,6 +2968,7 @@ df_uses_record (struct df_collection_rec
 	  {
 	    width = INTVAL (XEXP (x, 1));
 	    offset = INTVAL (XEXP (x, 2));
+	    mode = GET_MODE (x);
 
 	    if (code == ZERO_EXTRACT)
 	      flags |= DF_REF_ZERO_EXTRACT;
@@ -2958,7 +2976,8 @@ df_uses_record (struct df_collection_rec
 	      flags |= DF_REF_SIGN_EXTRACT;
 
 	    df_uses_record (collection_rec,
-			    &XEXP (x, 0), ref_type, bb, insn, flags, width, offset);
+			    &XEXP (x, 0), ref_type, bb, insn, flags, 
+			    width, offset, mode);
 	    return;
 	  }
       }
@@ -2969,7 +2988,8 @@ df_uses_record (struct df_collection_rec
 	rtx dst = SET_DEST (x);
 	gcc_assert (!(flags & DF_REF_IN_NOTE));
 	df_uses_record (collection_rec,
-			&SET_SRC (x), DF_REF_REG_USE, bb, insn, flags, width, offset);
+			&SET_SRC (x), DF_REF_REG_USE, bb, insn, flags, 
+			width, offset, mode);
 
 	switch (GET_CODE (dst))
 	  {
@@ -2978,7 +2998,8 @@ df_uses_record (struct df_collection_rec
 		{
 		  df_uses_record (collection_rec, &SUBREG_REG (dst), 
 				  DF_REF_REG_USE, bb, insn, 
-				  flags | DF_REF_READ_WRITE | DF_REF_SUBREG, width, offset);
+				  flags | DF_REF_READ_WRITE | DF_REF_SUBREG, 
+				  width, offset, mode);
 		  break;
 		}
 	      /* Fall through.  */
@@ -2990,7 +3011,8 @@ df_uses_record (struct df_collection_rec
 		break;
 	    case MEM:
 	      df_uses_record (collection_rec, &XEXP (dst, 0),
-			      DF_REF_REG_MEM_STORE, bb, insn, flags, width, offset);
+			      DF_REF_REG_MEM_STORE, bb, insn, flags, 
+			      width, offset, mode);
 	      break;
 	    case STRICT_LOW_PART:
 	      {
@@ -3001,7 +3023,8 @@ df_uses_record (struct df_collection_rec
 		df_uses_record (collection_rec, 
 				(GET_CODE (dst) == SUBREG) ? &SUBREG_REG (dst) : temp, 
 				DF_REF_REG_USE, bb, insn, 
-				DF_REF_READ_WRITE | DF_REF_STRICT_LOW_PART, width, offset);
+				DF_REF_READ_WRITE | DF_REF_STRICT_LOW_PART, 
+				width, offset, mode);
 	      }
 	      break;
 	    case ZERO_EXTRACT:
@@ -3011,18 +3034,22 @@ df_uses_record (struct df_collection_rec
 		  {
 		    width = INTVAL (XEXP (dst, 1));
 		    offset = INTVAL (XEXP (dst, 2));
+		    mode = GET_MODE (dst);
 		  }
 		else 
 		  {
 		    df_uses_record (collection_rec, &XEXP (dst, 1), 
-				    DF_REF_REG_USE, bb, insn, flags, width, offset);
+				    DF_REF_REG_USE, bb, insn, flags, 
+				    width, offset, mode);
 		    df_uses_record (collection_rec, &XEXP (dst, 2), 
-				    DF_REF_REG_USE, bb, insn, flags, width, offset);
+				    DF_REF_REG_USE, bb, insn, flags, 
+				    width, offset, mode);
 		  }
 
 		df_uses_record (collection_rec, &XEXP (dst, 0), 
 				DF_REF_REG_USE, bb, insn, 
-				DF_REF_READ_WRITE | DF_REF_ZERO_EXTRACT, width, offset);
+				DF_REF_READ_WRITE | DF_REF_ZERO_EXTRACT, 
+				width, offset, mode);
 	      }
 	      break;
 
@@ -3072,7 +3099,8 @@ df_uses_record (struct df_collection_rec
 
 	    for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
 	      df_uses_record (collection_rec, &ASM_OPERANDS_INPUT (x, j),
-			      DF_REF_REG_USE, bb, insn, flags, width, offset);
+			      DF_REF_REG_USE, bb, insn, flags, 
+			      width, offset, mode);
 	    return;
 	  }
 	break;
@@ -3087,7 +3115,8 @@ df_uses_record (struct df_collection_rec
       /* Catch the def of the register being modified.  */
       df_ref_record (collection_rec, XEXP (x, 0), &XEXP (x, 0), bb, insn, 
 		     DF_REF_REG_DEF,
-                     flags | DF_REF_READ_WRITE | DF_REF_PRE_POST_MODIFY, width, offset);
+                     flags | DF_REF_READ_WRITE | DF_REF_PRE_POST_MODIFY, 
+		     width, offset, mode);
 
       /* ... Fall through to handle uses ...  */
 
@@ -3111,7 +3140,8 @@ df_uses_record (struct df_collection_rec
 		goto retry;
 	      }
 	    df_uses_record (collection_rec, &XEXP (x, i), ref_type, 
-			    bb, insn, flags, width, offset);
+			    bb, insn, flags, 
+			    width, offset, mode);
 	  }
 	else if (fmt[i] == 'E')
 	  {
@@ -3119,7 +3149,8 @@ df_uses_record (struct df_collection_rec
 	    for (j = 0; j < XVECLEN (x, i); j++)
 	      df_uses_record (collection_rec,
 			      &XVECEXP (x, i, j), ref_type, 
-			      bb, insn, flags, width, offset);
+			      bb, insn, flags, 
+			      width, offset, mode);
 	  }
       }
   }
@@ -3141,19 +3172,21 @@ df_get_conditional_uses (struct df_colle
         {
 	  int width = -1;
 	  int offset = -1;
+	  enum machine_mode mode = 0;
           struct df_ref *use;
 
 	  if (DF_REF_FLAGS_IS_SET (ref, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
 	    {
-	      width = DF_REF_WIDTH (ref);
-	      offset = DF_REF_OFFSET (ref);
+	      width = DF_REF_EXTRACT_WIDTH (ref);
+	      offset = DF_REF_EXTRACT_OFFSET (ref);
+	      mode = DF_REF_EXTRACT_MODE (ref);
 	    }
 
           use = df_ref_create_structure (collection_rec, DF_REF_REG (ref),
 					 DF_REF_LOC (ref), DF_REF_BB (ref),
 					 DF_REF_INSN (ref), DF_REF_REG_USE,
 					 DF_REF_FLAGS (ref) & ~DF_REF_CONDITIONAL,
-					 width, offset);
+					 width, offset, mode);
           DF_REF_REGNO (use) = DF_REF_REGNO (ref);
         }
     }
@@ -3191,7 +3224,7 @@ df_get_call_refs (struct df_collection_r
     {
       if (GET_CODE (XEXP (note, 0)) == USE)
         df_uses_record (collection_rec, &XEXP (XEXP (note, 0), 0),
-			DF_REF_REG_USE, bb, insn, flags, -1, -1);
+			DF_REF_REG_USE, bb, insn, flags, -1, -1, 0);
       else if (GET_CODE (XEXP (note, 0)) == CLOBBER)
 	{
 	  if (REG_P (XEXP (XEXP (note, 0), 0)))
@@ -3203,13 +3236,14 @@ df_get_call_refs (struct df_collection_r
 	    }
 	  else
 	    df_uses_record (collection_rec, &XEXP (note, 0),
-		            DF_REF_REG_USE, bb, insn, flags, -1, -1);
+		            DF_REF_REG_USE, bb, insn, flags, -1, -1, 0);
 	}
     }
 
   /* The stack ptr is used (honorarily) by a CALL insn.  */
   df_ref_record (collection_rec, regno_reg_rtx[STACK_POINTER_REGNUM],
-		 NULL, bb, insn, DF_REF_REG_USE, DF_REF_CALL_STACK_USAGE | flags, -1, -1);
+		 NULL, bb, insn, DF_REF_REG_USE, DF_REF_CALL_STACK_USAGE | flags, 
+		 -1, -1, 0);
 
   /* Calls may also reference any of the global registers,
      so they are recorded as used.  */
@@ -3217,9 +3251,9 @@ df_get_call_refs (struct df_collection_r
     if (global_regs[i])
       {
 	df_ref_record (collection_rec, regno_reg_rtx[i],
-		       NULL, bb, insn, DF_REF_REG_USE, flags, -1, -1);
+		       NULL, bb, insn, DF_REF_REG_USE, flags, -1, -1, 0);
 	df_ref_record (collection_rec, regno_reg_rtx[i],
-		       NULL, bb, insn, DF_REF_REG_DEF, flags, -1, -1);
+		       NULL, bb, insn, DF_REF_REG_DEF, flags, -1, -1, 0);
       }
 
   is_sibling_call = SIBLING_CALL_P (insn);
@@ -3232,7 +3266,8 @@ df_get_call_refs (struct df_collection_r
 	      || refers_to_regno_p (ui, ui+1, 
 				    current_function_return_rtx, NULL)))
         df_ref_record (collection_rec, regno_reg_rtx[ui], 
-		       NULL, bb, insn, DF_REF_REG_DEF, DF_REF_MAY_CLOBBER | flags, -1, -1);
+		       NULL, bb, insn, DF_REF_REG_DEF, DF_REF_MAY_CLOBBER | flags, 
+		       -1, -1, 0);
     }
 
   BITMAP_FREE (defs_generated);
@@ -3270,7 +3305,7 @@ df_insn_refs_collect (struct df_collecti
         case REG_EQUAL:
           df_uses_record (collection_rec,
                           &XEXP (note, 0), DF_REF_REG_USE,
-                          bb, insn, DF_REF_IN_NOTE, -1, -1);
+                          bb, insn, DF_REF_IN_NOTE, -1, -1, 0);
           break;
         case REG_NON_LOCAL_GOTO:
           /* The frame ptr is used by a non-local goto.  */
@@ -3278,13 +3313,13 @@ df_insn_refs_collect (struct df_collecti
                          regno_reg_rtx[FRAME_POINTER_REGNUM],
                          NULL,
                          bb, insn, 
-                         DF_REF_REG_USE, 0, -1, -1);
+                         DF_REF_REG_USE, 0, -1, -1, 0);
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
           df_ref_record (collection_rec,
                          regno_reg_rtx[HARD_FRAME_POINTER_REGNUM],
                          NULL,
                          bb, insn, 
-                         DF_REF_REG_USE, 0, -1, -1);
+                         DF_REF_REG_USE, 0, -1, -1, 0);
 #endif
           break;
         default:
@@ -3298,7 +3333,8 @@ df_insn_refs_collect (struct df_collecti
 
   /* Record the register uses.  */
   df_uses_record (collection_rec,
-		  &PATTERN (insn), DF_REF_REG_USE, bb, insn, 0, -1, -1);
+		  &PATTERN (insn), DF_REF_REG_USE, bb, insn, 0, 
+		  -1, -1, 0);
 
   /* DF_REF_CONDITIONAL needs corresponding USES. */
   if (is_cond_exec)
@@ -3381,7 +3417,7 @@ df_bb_refs_collect (struct df_collection
 	  if (regno == INVALID_REGNUM)
 	    break;
 	  df_ref_record (collection_rec, regno_reg_rtx[regno], NULL,
-			 bb, NULL, DF_REF_REG_DEF, DF_REF_AT_TOP, -1, -1);
+			 bb, NULL, DF_REF_REG_DEF, DF_REF_AT_TOP, -1, -1, 0);
 	}
     }
 #endif
@@ -3405,7 +3441,7 @@ df_bb_refs_collect (struct df_collection
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	if (EH_USES (i))
 	  df_ref_record (collection_rec, regno_reg_rtx[i], NULL,
-			 bb, NULL, DF_REF_REG_USE, DF_REF_AT_TOP, -1, -1);
+			 bb, NULL, DF_REF_REG_USE, DF_REF_AT_TOP, -1, -1, 0);
     }
 #endif
 
@@ -3413,7 +3449,7 @@ df_bb_refs_collect (struct df_collection
      non-local goto.  */
   if (bb->flags & BB_NON_LOCAL_GOTO_TARGET)
     df_ref_record (collection_rec, hard_frame_pointer_rtx, NULL,
-		   bb, NULL, DF_REF_REG_DEF, DF_REF_AT_TOP, -1, -1);
+		   bb, NULL, DF_REF_REG_DEF, DF_REF_AT_TOP, -1, -1, 0);
  
   /* Add the artificial uses.  */
   if (bb->index >= NUM_FIXED_BLOCKS)
@@ -3427,7 +3463,7 @@ df_bb_refs_collect (struct df_collection
       EXECUTE_IF_SET_IN_BITMAP (au, 0, regno, bi)
 	{
 	  df_ref_record (collection_rec, regno_reg_rtx[regno], NULL,
-			 bb, NULL, DF_REF_REG_USE, 0, -1, -1);
+			 bb, NULL, DF_REF_REG_USE, 0, -1, -1, 0);
 	}
     }
 
@@ -3720,7 +3756,7 @@ df_entry_block_defs_collect (struct df_c
   EXECUTE_IF_SET_IN_BITMAP (entry_block_defs, 0, i, bi)
     {
       df_ref_record (collection_rec, regno_reg_rtx[i], NULL, 
-		     ENTRY_BLOCK_PTR, NULL, DF_REF_REG_DEF, 0, -1, -1);
+		     ENTRY_BLOCK_PTR, NULL, DF_REF_REG_DEF, 0, -1, -1, 0);
     }
 
   df_canonize_collection_rec (collection_rec);
@@ -3881,7 +3917,7 @@ df_exit_block_uses_collect (struct df_co
 
   EXECUTE_IF_SET_IN_BITMAP (exit_block_uses, 0, i, bi)
     df_ref_record (collection_rec, regno_reg_rtx[i], NULL,
-		   EXIT_BLOCK_PTR, NULL, DF_REF_REG_USE, 0, -1, -1);
+		   EXIT_BLOCK_PTR, NULL, DF_REF_REG_USE, 0, -1, -1, 0);
 
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
   /* It is deliberate that this is not put in the exit block uses but
@@ -3891,7 +3927,7 @@ df_exit_block_uses_collect (struct df_co
       && bb_has_eh_pred (EXIT_BLOCK_PTR)
       && fixed_regs[ARG_POINTER_REGNUM])
     df_ref_record (collection_rec, regno_reg_rtx[ARG_POINTER_REGNUM], NULL,
-		   EXIT_BLOCK_PTR, NULL, DF_REF_REG_USE, 0, -1, -1);
+		   EXIT_BLOCK_PTR, NULL, DF_REF_REG_USE, 0, -1, -1, 0);
 #endif
 
   df_canonize_collection_rec (collection_rec);
Index: global.c
===================================================================
--- global.c	(revision 133475)
+++ global.c	(working copy)
@@ -90,7 +90,9 @@ along with GCC; see the file COPYING3.  
    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.
+   pseudo-registers versus hardware registers. 
+
+   Steps 2 and 3 are done in ra-conflict.c.
 
    4. For each basic block, walk backward through the block, recording
    the preferred hardware registers for each pseudo-register.
@@ -531,7 +533,7 @@ global_alloc (void)
       /* Scan all the insns and compute the conflicts among allocnos
 	 and between allocnos and hard regs.  */
 
-      global_conflicts ();
+      ra_global_conflicts ();
 
       /* There is just too much going on in the register allocators to
 	 keep things up to date.  At the end we have to rescan anyway
@@ -540,7 +542,7 @@ global_alloc (void)
 
 	 However, we needed to do the rescanning before this point to
 	 get the new insns scanned inserted by local_alloc scanned for
-	 global_conflicts.  */
+	 ra_global_conflicts.  */
       df_set_flags (DF_NO_INSN_RESCAN);
 
       /* Eliminate conflicts between pseudos and eliminable registers.  If
@@ -637,6 +639,7 @@ global_alloc (void)
   free (num_allocnos_per_blk);
   free (partial_bitnum);
   free (allocno);
+  ra_free_aligned_mw_pseudos ();
   if (adjacency != NULL)
     {
       free_alloc_pool (adjacency_pool);
@@ -723,7 +726,7 @@ expand_preferences (void)
 	if (REG_NOTE_KIND (link) == REG_DEAD
 	    && REG_P (XEXP (link, 0))
 	    && reg_allocno[REGNO (XEXP (link, 0))] >= 0
-	    && ! conflict_p (reg_allocno[REGNO (SET_DEST (set))],
+	    && ! ra_conflict_p (reg_allocno[REGNO (SET_DEST (set))],
 			     reg_allocno[REGNO (XEXP (link, 0))]))
 	  {
 	    int a1 = reg_allocno[REGNO (SET_DEST (set))];
@@ -1418,7 +1421,7 @@ build_insn_chain (void)
      live_subregs_used is number of bytes that the pseudo can
      occupy.  */
   sbitmap *live_subregs = XCNEWVEC (sbitmap, max_regno);
-  int *live_subregs_used = XNEWVEC (int, max_regno);
+  bitmap live_subregs_used = BITMAP_ALLOC (NULL);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (TEST_HARD_REG_BIT (eliminable_regset, i))
@@ -1430,7 +1433,6 @@ build_insn_chain (void)
       rtx insn;
       
       CLEAR_REG_SET (live_relevant_regs);
-      memset (live_subregs_used, 0, max_regno * sizeof (int));
       
       EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), 0, i, bi)
 	{
@@ -1492,6 +1494,7 @@ build_insn_chain (void)
 			if (GET_CODE (reg) == SUBREG
 			    && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
 			  {
+			    unsigned int regsize = GET_MODE_SIZE (GET_MODE (regno_reg_rtx[regno]));
 			    unsigned int start = SUBREG_BYTE (reg);
 			    unsigned int last = start 
 			      + GET_MODE_SIZE (GET_MODE (reg));
@@ -1513,8 +1516,8 @@ build_insn_chain (void)
 			      }
 
 			    /* Ignore the paradoxical bits.  */
-			    if ((int)last > live_subregs_used[regno])
-			      last = live_subregs_used[regno];
+			    if (last > regsize)
+			      last = regsize;
 
 			    while (start < last)
 			      {
@@ -1524,7 +1527,7 @@ build_insn_chain (void)
 			    
 			    if (sbitmap_empty_p (live_subregs[regno]))
 			      {
-				live_subregs_used[regno] = 0;
+				bitmap_clear_bit (live_subregs_used, regno);
 				bitmap_clear_bit (live_relevant_regs, regno);
 			      }
 			    else
@@ -1543,7 +1546,7 @@ build_insn_chain (void)
 			    if (!DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL))
 			      {
 				bitmap_clear_bit (live_relevant_regs, regno);
-				live_subregs_used[regno] = 0;
+				bitmap_clear_bit (live_subregs_used, regno);
 			      }
 			  }
 		      }
@@ -1588,6 +1591,7 @@ build_insn_chain (void)
 			    && !DF_REF_FLAGS_IS_SET (use,
 						     DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT)) 
 			  {
+			    unsigned int regsize = GET_MODE_SIZE (GET_MODE (regno_reg_rtx[regno]));
 			    unsigned int start = SUBREG_BYTE (reg);
 			    unsigned int last = start 
 			      + GET_MODE_SIZE (GET_MODE (reg));
@@ -1599,8 +1603,8 @@ build_insn_chain (void)
 						  regno, reg);
 			    
 			    /* Ignore the paradoxical bits.  */
-			    if ((int)last > live_subregs_used[regno])
-			      last = live_subregs_used[regno];
+			    if (last > regsize)
+			      last = regsize;
 
 			    while (start < last)
 			      {
@@ -1613,7 +1617,7 @@ build_insn_chain (void)
 			     effectively saying do not use the subregs
 			     because we are reading the whole
 			     pseudo.  */
-			  live_subregs_used[regno] = 0;
+			  bitmap_clear_bit (live_subregs_used, regno);
 			bitmap_set_bit (live_relevant_regs, regno);
 		      }
 		  }
@@ -1664,7 +1668,7 @@ build_insn_chain (void)
   *p = NULL;
 
   free (live_subregs);
-  free (live_subregs_used);
+  BITMAP_FREE (live_subregs_used);
   BITMAP_FREE (live_relevant_regs);
   BITMAP_FREE (elim_regset);
 
@@ -1735,6 +1739,8 @@ dump_conflicts (FILE *file)
 	    fprintf (file, " %d", j);
 	fprintf (file, "\n");
       }
+
+  ra_dump_mw_reg_pairs (file);
   fprintf (file, "\n");
 }
 
Index: dbgcnt.c
===================================================================
--- dbgcnt.c	(revision 133475)
+++ dbgcnt.c	(working copy)
@@ -23,6 +23,9 @@ See dbgcnt.def for usage information.  *
 #include "system.h"
 #include "coretypes.h"
 #include "errors.h"
+#include "tm.h"
+#include "rtl.h"
+#include "output.h"
 
 #include "dbgcnt.h"
 
@@ -58,6 +61,10 @@ bool
 dbg_cnt (enum debug_counter index)
 {
   count[index]++;
+  if (dump_file && count[index] == limit[index])
+    fprintf (dump_file, "***dbgcnt: limit reached for %s.***\n", 
+	     map[index].name);
+
   return dbg_cnt_is_enabled (index);
 }
 
@@ -132,7 +139,8 @@ dbg_cnt_process_opt (const char *arg)
 
 /* Print name, limit and count of all counters.   */
 
-void dbg_cnt_list_all_counters (void)
+void 
+dbg_cnt_list_all_counters (void)
 {
   int i;
   printf ("  %-30s %-5s %-5s\n", "counter name",  "limit", "value");
Index: df.h
===================================================================
--- df.h	(revision 133475)
+++ df.h	(working copy)
@@ -398,6 +398,7 @@ struct df_ref_extract
   struct df_ref ref;
   int width;
   int offset;
+  enum machine_mode mode;
 };
 
 /* These links are used for two purposes:
@@ -619,8 +620,9 @@ struct df
 #define DF_REF_PREV_REG(REF) ((REF)->prev_reg)
 /* The following two macros may only be applied if one of 
    DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT is true. */ 
-#define DF_REF_WIDTH(REF) (((struct df_ref_extract *)(REF))->width)
-#define DF_REF_OFFSET(REF) (((struct df_ref_extract *)(REF))->offset)
+#define DF_REF_EXTRACT_WIDTH(REF) (((struct df_ref_extract *)(REF))->width)
+#define DF_REF_EXTRACT_OFFSET(REF) (((struct df_ref_extract *)(REF))->offset)
+#define DF_REF_EXTRACT_MODE(REF) (((struct df_ref_extract *)(REF))->mode)
 /* Macros to determine the reference type.  */
 
 #define DF_REF_REG_DEF_P(REF) (DF_REF_TYPE (REF) == DF_REF_REG_DEF)
@@ -885,7 +887,7 @@ extern void df_grow_insn_info (void);
 extern void df_scan_blocks (void);
 extern struct df_ref *df_ref_create (rtx, rtx *, rtx,basic_block, 
 				     enum df_ref_type, enum df_ref_flags,
-				     int, int);
+				     int, int, enum machine_mode);
 extern void df_ref_remove (struct df_ref *);
 extern struct df_insn_info * df_insn_create_insn_record (rtx);
 extern void df_insn_delete (basic_block, unsigned int);
@@ -911,6 +913,9 @@ extern void df_compute_regs_ever_live (b
 extern bool df_read_modify_subreg_p (rtx);
 extern void df_scan_verify (void);
 
+/* Functions defined in df-byte-scan.c.  */
+extern bool df_compute_accessed_bytes (struct df_ref *, unsigned int *, unsigned int *);
+
 
 /* Get basic block info.  */
 
Index: ra.h
===================================================================
--- ra.h	(revision 133475)
+++ ra.h	(working copy)
@@ -137,23 +137,6 @@ extern adjacency_t **adjacency;
    has already determined that NEIGHBOR is not already neighbor by
    checking the conflict bit matrix.  */
 
-static inline void
-add_neighbor (int alloc_no, int neighbor)
-{
-  adjacency_t *adjlist = adjacency[alloc_no];
-
-  if (adjlist == NULL || adjlist->index == ADJACENCY_VEC_LENGTH)
-    {
-      adjacency_t *new = pool_alloc (adjacency_pool);
-      new->index = 0;
-      new->next = adjlist;
-      adjlist = new;
-      adjacency[alloc_no] = adjlist;
-    }
-
-  adjlist->neighbors[adjlist->index++] = neighbor;
-}
-
 /* Iterator for adjacency lists.  */
 
 typedef struct adjacency_iterator_d
@@ -210,7 +193,14 @@ regno_basic_block (int regno)
   return block;
 }
 
-extern void global_conflicts (void);
+/* In ra-conflict.c  */
+extern void ra_global_conflicts (void);
+extern void ra_init_live_subregs (bool, sbitmap *, bitmap, int, rtx);
+extern bool ra_conflict_p (int, int);
+extern void ra_free_aligned_mw_pseudos (void);
+extern bool ra_aligned_mw_pseudos_p (int, int);
+extern void ra_dump_mw_reg_pairs (FILE *);
+
 
 /* In global.c  */
 
@@ -225,7 +215,4 @@ extern void global_conflicts (void);
 	 !adjacency_iter_done (&(ITER));				\
 	 (OUT_ALLOCNO) = adjacency_iter_next (&(ITER)))
 
-extern void ra_init_live_subregs (bool, sbitmap *, int *, int, rtx);
-extern bool conflict_p (int, int);
-
 #endif /* GCC_RA_H */
Index: df-byte-scan.c
===================================================================
--- df-byte-scan.c	(revision 0)
+++ df-byte-scan.c	(revision 0)
@@ -0,0 +1,269 @@
+/* Scanning of rtl byte level scanning for dataflow analysis.
+   Copyright (C) 2008  Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck (zadeck@naturalbridge.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "df.h"
+#include "output.h"
+#include "dbgcnt.h"
+
+/* The following suite of functions provides bytewise modeling of REFs
+   which are struct df_ref.  START_BYTE and LAST_BYTE are returned.
+   These can be used as indexes into bitmaps.  The indexes are
+   normalized so that 0 is the lowest numbered byte, of the inner
+   register according to the natural ordering of the machine.
+
+   It is important that if this code is called in a backwards scan
+   (which is, of course, the way all dataflow scanning should really
+   be done) that it not be called with the uses that set the
+   DF_REF_READ_WRITE flag except for DF_REF_PRE_POST_MODIFY uses
+   (because the fabricated uses really is necessary).  These uses are
+   there only to force the whole register alive if part of it is
+   written.  That will defeat the entire purpose of byte-wise modeling
+   of the insns.  */
+
+
+/* Helper for COMPUTE_ACCESSED_BYTES.  Ref is some sort of extract.
+   Return true if this effects the entire reg in REF. Return false if
+   otherwise and set START_BYTE and LAST_BYTE.  */ 
+
+static bool 
+df_compute_accessed_bytes_extract (struct df_ref *ref, 
+				   unsigned int *start_byte, 
+				   unsigned int *last_byte)
+{
+  int start;
+  int last;
+  rtx reg = DF_REF_REG (ref);
+  enum machine_mode m1;
+  int m1_size;
+  enum machine_mode m2;
+  int m2_size;
+
+  /* (*_extract:M1 (reg:M2 X) WIDTH POS)
+     (*_extract:M1 (subreg:M1 (reg:M2 X N) WIDTH POS)
+      
+     This is a bitfield extraction.  The assignment clobbers/extracts
+     exactly the bits named by WIDTH and POS and does not affect the
+     other bits in register X.  It is also technically possible that
+     the bits asked for are longer than units per word.  */
+  
+  int offset = DF_REF_EXTRACT_OFFSET (ref);
+  int width = DF_REF_EXTRACT_WIDTH (ref);
+
+  if (width == -1 || offset == -1)
+    return true;
+
+  m1 = DF_REF_EXTRACT_MODE (ref);
+  m1_size = GET_MODE_SIZE (m1);
+
+  gcc_assert (m1_size <= UNITS_PER_WORD);
+
+  /* There is nothing to do if this is a pure big or small endian
+     machine, but if the machine is a pastiche, we have to convert the
+     bit offsets into byte offsets.  This is only possible because we
+     do not care about individual bits because this conversion may
+     make the bits non-contiguous.  */
+  if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)
+    offset = GET_MODE_BITSIZE (m1_size) - (offset + width);
+
+  /* The offset is now in the same order as the subreg_byte.  */
+  if (GET_CODE (reg) == SUBREG)
+    {
+      m2 = GET_MODE (SUBREG_REG (reg));
+      m2_size = GET_MODE_SIZE (m2);
+      if (m1_size > m2_size)
+	/* If it is paradoxical, subreg_byte will be zero.  */
+	offset -= subreg_lowpart_offset (m2, m1) * BITS_PER_UNIT;
+      else
+	offset += SUBREG_BYTE (reg) * BITS_PER_UNIT;
+    }
+  else
+    {
+      m2 = GET_MODE (reg);
+      m2_size = GET_MODE_SIZE (m2);
+    }
+
+  start = offset / BITS_PER_UNIT;
+  last = (width + offset + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
+  
+  /* Paradoxical truncation.  */
+  if  (start < 0)
+    start = 0;
+  if (last > m2_size)
+    last = m2_size;
+
+  if (dump_file)
+    fprintf (dump_file, "    cpb extract start=%d last=%d\n", start, last);
+  
+  *start_byte = start;
+  *last_byte = last;
+  return false;
+}
+
+
+/* Helper for COMPUTE_ACCESSED_BYTES.  Ref is a strict_low_part.  Return
+   true if this effects the entire reg in REF. Return false if
+   otherwise and set START_BYTE and LAST_BYTE.  */ 
+
+static bool 
+df_compute_accessed_bytes_strict_low_part (struct df_ref *ref, 
+					   unsigned int *start_byte, 
+					   unsigned int *last_byte)
+{
+  int start;
+  int last;
+  rtx reg = DF_REF_REG (ref);
+  enum machine_mode m1 = GET_MODE (reg);
+  int m1_size = GET_MODE_SIZE (m1);
+  enum machine_mode m2 = GET_MODE (SUBREG_REG (reg));
+  int m2_size = GET_MODE_SIZE (m2);
+  int offset = SUBREG_BYTE (reg);
+
+  /* It does not seem to be meaningful to apply a strict_low_part of a
+     paradoxical register.  */
+  gcc_assert (m1_size <= m2_size);
+
+  /* (set (strict_low_part (subreg:M1 (reg:M2 X) N)) ...)
+      
+  This is a bitfield insertion.  The assignment clobbers exactly the
+  bits named by the subreg--the M1 bits at position N.  It is also
+  technically possible that the bits asked for are longer than units
+  per word.  */
+  
+  start = offset;
+  last = offset + m1_size;
+
+  if (dump_file)
+    fprintf (dump_file, "    cpb strict low part start=%d last=%d\n", 
+	     start, last);
+
+  *start_byte = start;
+  *last_byte = last;
+  return false;
+}
+
+/* Helper for COMPUTE_ACCESSED_BYTES.  Ref is a naked subreg.  Return
+   true if this effects the entire reg in REF. Return false if
+   otherwise and set START_BYTE and LAST_BYTE.  */ 
+
+static bool 
+df_compute_accessed_bytes_subreg (struct df_ref *ref, unsigned int *start_byte, 
+				  unsigned int *last_byte)
+
+{
+  /* (subreg:M1 (reg:M2 X) N) */
+  int start;
+  int last;
+  rtx reg = DF_REF_REG (ref);
+  enum machine_mode m1 = GET_MODE (reg);
+  int m1_size = GET_MODE_SIZE (m1);
+  enum machine_mode m2 = GET_MODE (SUBREG_REG (reg));
+  int m2_size = GET_MODE_SIZE (m2);
+
+  /* A simple paradoxical subreg just accesses the entire inner reg.  */
+  if (m1_size >= m2_size)
+    return true;
+
+  /* Defs and uses are different in the amount of the reg that touch.  */
+  if (DF_REF_TYPE (ref) == DF_REF_REG_DEF)
+    {
+      /* This is an lvalue.  */ 
+
+      if (m2_size > UNITS_PER_WORD)
+	{
+	  /* The assignment clobbers UNITS_PER_WORD segments of X.
+	     Look at the bytes named by the subreg, and expand it to
+	     cover a UNITS_PER_WORD part of register X.  That part of
+	     register X is clobbered, the rest is not.
+	     
+	     E.g., (subreg:SI (reg:DI X) 0), where UNITS_PER_WORD is the
+	     size of SImode, clobbers the first SImode part of X, and does
+	     not affect the second SImode part.
+	     
+	     E.g., (subreg:QI (reg:DI X) 0), where UNITS_PER_WORD is the
+	     size of SImode, clobbers the first SImode part of X, and does
+	     not affect the second SImode part.  Here the QImode byte is
+	     expanded to a UNITS_PER_WORD portion of the register for
+	     purposes of determining what is clobbered.
+	     
+	     If this is an rvalue, then it touches just the bytes that it
+	     talks about.  */
+	  int offset = SUBREG_BYTE (reg);
+	  
+	  start = offset & ~(UNITS_PER_WORD - 1);
+	  last = (offset + m1_size + UNITS_PER_WORD - 1) 
+	    & ~(UNITS_PER_WORD - 1);
+	}
+      else
+	/* Whole register size M2 equal to or smaller than
+	   UNITS_PER_WORD The assignment clobbers the entire register
+	   X.  */
+	return true;
+    }
+  else 
+    {
+      /* This is an rvalue. It touches just the bytes they explicitly
+	 mentioned.  */
+      int offset = SUBREG_BYTE (reg);
+      start = offset;
+      last = start + m1_size;
+    }
+  
+  if (dump_file)
+    fprintf (dump_file, "    cpb subreg start=%d last=%d\n", start, last);
+
+  *start_byte = start;
+  *last_byte = last;
+  return false;
+}
+
+
+/* Compute the set of affected bytes by a store to a psuedo to REF.
+   If the store is to the whole register, just return TRUE, if it is
+   to part of the register, return FALSE and set START_BYTE and
+   LAST_BYTE properly.  */
+
+bool 
+df_compute_accessed_bytes (struct df_ref *ref, unsigned int *start_byte, 
+			   unsigned int *last_byte)
+{
+  if (!dbg_cnt (df_byte_scan))
+    return true;
+
+  /* See the comment at the top.  */
+  if (DF_REF_TYPE (ref) != DF_REF_REG_DEF
+      && DF_REF_FLAGS_IS_SET (ref, DF_REF_READ_WRITE))
+    return true;
+
+  if (DF_REF_FLAGS_IS_SET (ref, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
+    return df_compute_accessed_bytes_extract (ref, start_byte, last_byte);
+  else if (DF_REF_FLAGS_IS_SET (ref, DF_REF_STRICT_LOW_PART))
+    return df_compute_accessed_bytes_strict_low_part (ref, 
+						      start_byte, last_byte);
+  else if (GET_CODE (DF_REF_REG (ref)) == SUBREG)
+    return df_compute_accessed_bytes_subreg (ref, start_byte, last_byte);
+  return true;
+}
+
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 133475)
+++ Makefile.in	(working copy)
@@ -807,7 +807,7 @@ IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CG
 IPA_REFERENCE_H = ipa-reference.h bitmap.h $(TREE_H)
 IPA_TYPE_ESCAPE_H = ipa-type-escape.h $(TREE_H)
 CGRAPH_H = cgraph.h $(TREE_H)
-DF_H = df.h bitmap.h $(BASIC_BLOCK_H) alloc-pool.h
+DF_H = df.h bitmap.h $(BASIC_BLOCK_H) alloc-pool.h 
 RESOURCE_H = resource.h hard-reg-set.h $(DF_H)
 DDG_H = ddg.h sbitmap.h $(DF_H)
 GCC_H = gcc.h version.h
@@ -1035,6 +1035,7 @@ OBJS-common = \
 	dce.o \
 	ddg.o \
 	debug.o \
+	df-byte-scan.o \
 	df-core.o \
 	df-problems.o \
 	df-scan.o \
@@ -2617,6 +2618,8 @@ df-scan.o : df-scan.c $(CONFIG_H) $(SYST
    insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \
    hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) bitmap.h sbitmap.h $(TM_P_H) \
    $(FLAGS_H) $(TARGET_H) $(TARGET_DEF_H) $(TREE_H) output.h tree-pass.h
+df-byte-scan.o : df-byte-scan.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
+   $(DF_H) output.h $(DBGCNT_H)
 regstat.o : regstat.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TM_P_H) $(FLAGS_H) $(REGS_H) output.h except.h hard-reg-set.h \
    $(BASIC_BLOCK_H) $(TIMEVAR_H) $(DF_H)
@@ -2729,7 +2732,7 @@ global.o : global.c $(CONFIG_H) $(SYSTEM
 ra-conflict.o : ra-conflict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(FLAGS_H) reload.h $(FUNCTION_H) $(RECOG_H) $(REGS_H) hard-reg-set.h \
    insn-config.h output.h toplev.h $(TM_P_H) $(MACHMODE_H) tree-pass.h \
-   $(TIMEVAR_H) vecprim.h $(DF_H) $(RA_H) sbitmap.h 
+   $(TIMEVAR_H) vecprim.h $(DF_H) $(RA_H) sbitmap.h
 varray.o : varray.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(GGC_H) \
    $(HASHTAB_H) $(BCONFIG_H) $(VARRAY_H) toplev.h
 vec.o : vec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h vec.h $(GGC_H) \
@@ -2882,7 +2885,8 @@ hooks.o: hooks.c $(CONFIG_H) $(SYSTEM_H)
 pretty-print.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h intl.h $(PRETTY_PRINT_H) \
    $(TREE_H)
 errors.o : errors.c $(CONFIG_H) $(SYSTEM_H) errors.h $(BCONFIG_H)
-dbgcnt.o: dbgcnt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(DBGCNT_H)
+dbgcnt.o: dbgcnt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(DBGCNT_H) $(TM_H) \
+   $(RTL_H) output.h
 lower-subreg.o : lower-subreg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(MACHMODE_H) $(TM_H) $(RTL_H) $(TM_P_H) $(TIMEVAR_H) $(FLAGS_H) \
    insn-config.h $(BASIC_BLOCK_H) $(RECOG_H) $(OBSTACK_H) bitmap.h \

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]