diff mbox

Patch 10/9: track subwords of DImode allocnos

Message ID 4C1F9B96.4030007@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt June 21, 2010, 5:04 p.m. UTC
So here's the scary part.  This adds ALLOCNO_NUM_OBJECTS and the
possibility that it may be larger than 1.  Currently, it only tries to
do anything for two-word (i.e. DImode) allocnos; it should be possible
(and even relatively easy) to extend, but I'm not sure it's worthwhile.
 Whether even this version is worthwhile is for others to decide.

I should explain what I've done with the conflict handling.  Given two
DImode allocnos A and B with halves Ah, Al, Bh and Bl, we can encounter
four different conflicts: AhxBl, AhxBh, AlxBh and AlxBl.  Of these, only
three are meaningful: AhxBh and AlxBl can be treated equivalently in
every place I found.  This reduces the number of ways two such allocnos
can conflict to 3, and I've implemented this (as "conflict
canonicalization") by recording an AlxBl conflict instead of a AhxBh
conflict if one is found.  This is meaningful for functions like
setup_allocno_left_conflicts_size: each of these three conflicts reduces
the number of registers available for allocation by 1.

There are some places in IRA that use conflict tests to determine
whether two allocnos can be given the same hard register; in these cases
it is sufficient to test the low-order objects for conflicts (given the
canonicalization described above).  Any other type of conflict would not
prevent the allocnos from being given the same hard register (assuming
that both will be assigned two hard regs).

There is one place in the code where this canonicalization has an ugly
effect: in setup_min_max_conflict_allocno_ids, we have to extend the
min/max value for object 0 of each multi-word allocno, since we may
later record conflicts for them that are due to AhxBh and not apparent
at this point in the code.

Another possibly slightly ugly case is the handling of
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM; it seemed easiest just to count
these points for each object separately, and then divide by
ALLOCNO_NUM_OBJECTS later on.

The test for conflicts in assign_hard_reg is quite complicated due to
the possibility Jeff mentioned: the value of hard_regno_nregs may differ
for some element regs of a cover class.  I believe this is handled
correctly, but it really is quite tricky.

Even after more than a week of digging through IRA, I can't claim to
understand all of it.  I've made sure that all the places I touched
looked sane afterwards, but - for example - I don't really know yet what
ira_emit is trying to do.  There may be bad interactions.

Still, successfully bootstrapped and regression tested on i686-linux.
Last week I've used earlier versions with an ARM compiler and seemed to
get small code size improvements on Crafty; it also fixes the remaining
issue with PR42502.  I'm also thinking of extending it further to do a
DCE of subreg stores which should help PR42575.


Bernd
* ira-build.c (ira_create_object): New arg SUBWORD; all callers changed.
	Initialize OBJECT_SUBWORD.
	(ira_create_allocno): Clear ALLOCNO_NUM_OBJECTS.
	(ira_create_allocno_objects): Renamed from ira_create_allocno_object;
	all callers changed.
	(merge_hard_reg_conflicts): Iterate over allocno subobjects.
	(finish_allocno): Likewise.
	(move_allocno_live_ranges, copy_allocno_live_ranges): Likewise.
	(remove_low_level_allocnos): Likewise.
	(update_bad_spill_attribute): Likewise.
	(setup_min_max_allocno_live_range_point): Likewise.
	(sort_conflict_id_map): Likewise.
	(ira_flattening): Likewise.  Use ior_hard_reg_conflicts.
	(ior_hard_reg_conflicts): New function.
	(ior_allocate_object_conflicts): Renamed first argument to OBJ.
	(compress_conflict_vecs): Iterate over objects, not allocnos.
	(ira_add_live_range_to_object): New function.
	(object_range_compare_func): Renamed from allocno_range_compare_func.
	All callers changed.
	(setup_min_max_conflict_allocno_ids): For allocnos with multiple
	subobjects, widen the min/max range of the lowest-order object to
	potentially include all other such low-order objects.
	* ira.c (ira_bad_reload_regno_1): Iterate over allocno subobjects.
	(check_allocation): Likewise.  Use more fine-grained tests for register
	conflicts.
	* ira-color.c (allocnos_have_intersected_live_ranges_p): Iterate over
	allocno subobjects.
	(assign_hard_reg): Keep multiple sets of conflicts.  Make finer-grained
	choices about which bits to set in each set.  Don't use
	ira_hard_reg_not_in_set_p, perform a more elaborate test for conflicts
	using the multiple sets we computed.
	(push_allocno_to_stack): Iterate over allocno subobjects.
	(all_conflicting_hard_regs_coalesced): New static function.
	(setup_allocno_available_regs_num): Use it.
	(setup_allocno_left_conflicts_size): Likewise.  Iterate over allocno
	subobjects.
	(coalesced_allocno_conflict): Test subobject 0 in each allocno.
	(setup_allocno_priorities): Divide ALLOCNO_EXCESS_PRESSURE_POINTS_NUM
	by ALLOCNO_NUM_OBJECTS.
	(calculate_spill_cost): Likewise.
	(color_pass): Express if statement in a more normal way.
	(ira_reassign_conflict_allocnos): Iterate over allocno subobjects.
	(slot_coalesced_allocno_live_ranges_intersect_p): Likewise.
	(setup_slot_coalesced_allocno_live_ranges): Likewise.
	(allocno_reload_assign): Likewise.
	(ira_reassign_pseudos): Likewise.
	(fast_allocation): Likewise.
	* ira-conflicts.c (build_conflict_bit_table): Likewise.
	(print_allocno_conflicts): Likewise.
	(ira_build_conflicts): Likewise.
	(allocnos_conflict_for_copy_p): Renamed from allocnos_conflict_p.  All
	callers changed.  Test subword 0 of each allocno for conflicts.
	(build_object_conflicts): Renamed from build_allocno_conflicts.  All
	callers changed.  Iterate over allocno subobjects.
	* ira-emit.c (modify_move_list): Iterate over allocno subobjects.
	* ira-int.h (struct ira_allocno): New member. num_objects.  Rename object
	to objects and change it into an array.
	(ALLOCNO_OBJECT): Add new argument N.
	(ALLOCNO_NUM_OBJECTS, OBJECT_SUBWORD): New macros.
	(ira_create_allocno_objects): Renamed from ira_create_allocno_object.
	(ior_hard_reg_conflicts): Declare.
	(ira_add_live_range_to_object): Declare.
	(ira_allocno_object_iterator): New.
	(ira_allocno_object_iter_init, ira_allocno_object_iter_cond): New.
	(FOR_EACH_ALLOCNO_OBJECT): New macro.
	* ira-lives.c (objects_live): Renamed from allocnos_live; all uses changed.
	(allocnos_processed): New sparseset.
	(make_object_born): Renamed from make_allocno_born; take an ira_object_t
	argument.  All callers changed.
	(make_object_dead): Renamed from make_allocno_dead; take an ira_object t
	argument.  All callers changed.
	(update_allocno_pressure_excess_length): Take an ira_obejct_t argument.
	All callers changed.
	(mark_pseudo_regno_live): Iterate over allocno subobjects.
	(mark_pseudo_regno_dead): Likewise.
	(mark_pseudo_regno_subword_live, mark_pseudo_regno_subword_dead): New
	functions.
	(mark_ref_live): Detect subword accesses and call
	mark_pseudo_regno_subword_live as appropriate.
	(mark_ref_dead): Likewise for mark_pseudo_regno_subword_dead.
	(process_bb_nodes_live): Deal with object-related updates first; set
	and test bits in allocnos_processed to avoid computing allocno
	statistics more than once.
	(create_start_finish_chains): Iterate over objects, not allocnos.
	(print_object_live_ranges): New function.
	(print_allocno_live_ranges): Use it.
	(ira_create_allocno_live_ranges): Allocate and free allocnos_processed
	and objects_live.

Comments

Bernd Schmidt July 6, 2010, 11:48 p.m. UTC | #1
Friendly ping for the IRA DImode changes.  I realize that this can take
some time to review.

  http://gcc.gnu.org/ml/gcc-patches/2010-06/msg02056.html



Bernd
Jeff Law July 13, 2010, 8:43 p.m. UTC | #2
On 06/21/10 11:04, Bernd Schmidt wrote:
> So here's the scary part.  This adds ALLOCNO_NUM_OBJECTS and the
> possibility that it may be larger than 1.  Currently, it only tries to
> do anything for two-word (i.e. DImode) allocnos; it should be possible
> (and even relatively easy) to extend, but I'm not sure it's worthwhile.
>   Whether even this version is worthwhile is for others to decide.
>
> I should explain what I've done with the conflict handling.  Given two
> DImode allocnos A and B with halves Ah, Al, Bh and Bl, we can encounter
> four different conflicts: AhxBl, AhxBh, AlxBh and AlxBl.  Of these, only
> three are meaningful: AhxBh and AlxBl can be treated equivalently in
> every place I found.  This reduces the number of ways two such allocnos
> can conflict to 3, and I've implemented this (as "conflict
> canonicalization") by recording an AlxBl conflict instead of a AhxBh
> conflict if one is found.  This is meaningful for functions like
> setup_allocno_left_conflicts_size: each of these three conflicts reduces
> the number of registers available for allocation by 1.
>
> There are some places in IRA that use conflict tests to determine
> whether two allocnos can be given the same hard register; in these cases
> it is sufficient to test the low-order objects for conflicts (given the
> canonicalization described above).  Any other type of conflict would not
> prevent the allocnos from being given the same hard register (assuming
> that both will be assigned two hard regs).
>
> There is one place in the code where this canonicalization has an ugly
> effect: in setup_min_max_conflict_allocno_ids, we have to extend the
> min/max value for object 0 of each multi-word allocno, since we may
> later record conflicts for them that are due to AhxBh and not apparent
> at this point in the code.
>
> Another possibly slightly ugly case is the handling of
> ALLOCNO_EXCESS_PRESSURE_POINTS_NUM; it seemed easiest just to count
> these points for each object separately, and then divide by
> ALLOCNO_NUM_OBJECTS later on.
>
> The test for conflicts in assign_hard_reg is quite complicated due to
> the possibility Jeff mentioned: the value of hard_regno_nregs may differ
> for some element regs of a cover class.  I believe this is handled
> correctly, but it really is quite tricky.
>
> Even after more than a week of digging through IRA, I can't claim to
> understand all of it.  I've made sure that all the places I touched
> looked sane afterwards, but - for example - I don't really know yet what
> ira_emit is trying to do.  There may be bad interactions.
>
> Still, successfully bootstrapped and regression tested on i686-linux.
> Last week I've used earlier versions with an ARM compiler and seemed to
> get small code size improvements on Crafty; it also fixes the remaining
> issue with PR42502.  I'm also thinking of extending it further to do a
> DCE of subreg stores which should help PR42575.
>
>
> Bernd
>    

Overall this was relatively straightforward.  You touched on most of the 
non-obvious stuff above.   Answers to most of my questions became clear 
as wrote out the questions.  Here's all that's left:


In assign_hard_reg, you moved this hunk:

+          if (allocno_coalesced_p)
+            {
+              if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
+                    ALLOCNO_NUM (conflict_allocno)))
+            continue;
+              bitmap_set_bit (processed_coalesced_allocno_bitmap,
+                      ALLOCNO_NUM (conflict_allocno));
+            }

Into the ! ALLOCNO_MAY_BE_SPILLED_P if-clause rather than leaving it to 
execute unconditionally for each conflict allocno.   I don't see the 
reasoning behind this change.


I'm happy to let you and Vlad work out the exact timing for when the 
bits get committed.

Jeff
Bernd Schmidt July 13, 2010, 9:09 p.m. UTC | #3
On 07/13/2010 10:43 PM, Jeff Law wrote:

> Overall this was relatively straightforward.  You touched on most of the
> non-obvious stuff above.   Answers to most of my questions became clear
> as wrote out the questions.  Here's all that's left:
> 
> 
> In assign_hard_reg, you moved this hunk:
> 
> +          if (allocno_coalesced_p)
> +            {
> +              if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
> +                    ALLOCNO_NUM (conflict_allocno)))
> +            continue;
> +              bitmap_set_bit (processed_coalesced_allocno_bitmap,
> +                      ALLOCNO_NUM (conflict_allocno));
> +            }
> 
> Into the ! ALLOCNO_MAY_BE_SPILLED_P if-clause rather than leaving it to
> execute unconditionally for each conflict allocno.   I don't see the
> reasoning behind this change.

We've found a conflicting object, and looked up the corresponding
allocno.  There are two cases here, either the conflicting allocno has a
hard register already, or it doesn't.  In the first case, we need to
track the conflicts by object, which means we can't ignore the conflict
if we've seen the allocno previously - we might have seen a different
subword.  In the second case, we're just doing some costs bookkeeping,
and here it's OK to skip the allocno if we've seen it before.

Does that make sense?

> I'm happy to let you and Vlad work out the exact timing for when the
> bits get committed.

Vlad, is it better for you if I check in the preliminary bits (6-9) now,
or should I wait until you've had a chance to look at things?


Bernd
Vladimir Makarov July 13, 2010, 10:02 p.m. UTC | #4
Bernd Schmidt wrote:
> On 07/13/2010 10:43 PM, Jeff Law wrote:
>
>   
>> Overall this was relatively straightforward.  You touched on most of the
>> non-obvious stuff above.   Answers to most of my questions became clear
>> as wrote out the questions.  Here's all that's left:
>>
>>
>> In assign_hard_reg, you moved this hunk:
>>
>> +          if (allocno_coalesced_p)
>> +            {
>> +              if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
>> +                    ALLOCNO_NUM (conflict_allocno)))
>> +            continue;
>> +              bitmap_set_bit (processed_coalesced_allocno_bitmap,
>> +                      ALLOCNO_NUM (conflict_allocno));
>> +            }
>>
>> Into the ! ALLOCNO_MAY_BE_SPILLED_P if-clause rather than leaving it to
>> execute unconditionally for each conflict allocno.   I don't see the
>> reasoning behind this change.
>>     
>
> We've found a conflicting object, and looked up the corresponding
> allocno.  There are two cases here, either the conflicting allocno has a
> hard register already, or it doesn't.  In the first case, we need to
> track the conflicts by object, which means we can't ignore the conflict
> if we've seen the allocno previously - we might have seen a different
> subword.  In the second case, we're just doing some costs bookkeeping,
> and here it's OK to skip the allocno if we've seen it before.
>
> Does that make sense?
>
>   
>> I'm happy to let you and Vlad work out the exact timing for when the
>> bits get committed.
>>     
>
> Vlad, is it better for you if I check in the preliminary bits (6-9) now,
> or should I wait until you've had a chance to look at things?
>
>   
It is ok for me if you commit it now.  The earlier you commit, the 
earlier I start conflict resolution on the branch and look at your patches.
Bernd Schmidt July 14, 2010, 2 a.m. UTC | #5
On 07/14/2010 12:02 AM, Vladimir Makarov wrote:
>> Vlad, is it better for you if I check in the preliminary bits (6-9) now,
>> or should I wait until you've had a chance to look at things?
>>
>>   
> It is ok for me if you commit it now.  The earlier you commit, the
> earlier I start conflict resolution on the branch and look at your patches.

Patches 7-9 now committed after another bootstrap & regression test on
i686-linux.  Still no observed changes in code generation.

It probably would make sense to remove -fira-coalesce at this point if
you want to merge that part now.  This should simplify the final piece
of my patchkit; I can adapt and resubmit it.  Or we could stick to the
original plan.


Bernd
Jeff Law July 14, 2010, 7:06 p.m. UTC | #6
On 07/13/10 15:09, Bernd Schmidt wrote:
> On 07/13/2010 10:43 PM, Jeff Law wrote:
>
>    
>> Overall this was relatively straightforward.  You touched on most of the
>> non-obvious stuff above.   Answers to most of my questions became clear
>> as wrote out the questions.  Here's all that's left:
>>
>>
>> In assign_hard_reg, you moved this hunk:
>>
>> +          if (allocno_coalesced_p)
>> +            {
>> +              if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
>> +                    ALLOCNO_NUM (conflict_allocno)))
>> +            continue;
>> +              bitmap_set_bit (processed_coalesced_allocno_bitmap,
>> +                      ALLOCNO_NUM (conflict_allocno));
>> +            }
>>
>> Into the ! ALLOCNO_MAY_BE_SPILLED_P if-clause rather than leaving it to
>> execute unconditionally for each conflict allocno.   I don't see the
>> reasoning behind this change.
>>      
> We've found a conflicting object, and looked up the corresponding
> allocno.  There are two cases here, either the conflicting allocno has a
> hard register already, or it doesn't.  In the first case, we need to
> track the conflicts by object, which means we can't ignore the conflict
> if we've seen the allocno previously - we might have seen a different
> subword.  In the second case, we're just doing some costs bookkeeping,
> and here it's OK to skip the allocno if we've seen it before.
>
> Does that make sense?
>    
Yes.  Makes perfect sense now.  I might have just been burned out when I 
stumbled across that somewhat odd hunk.

jeff
Bernd Schmidt July 20, 2010, 2:27 p.m. UTC | #7
On 07/14/2010 12:02 AM, Vladimir Makarov wrote:
> Bernd Schmidt wrote:

>> Vlad, is it better for you if I check in the preliminary bits (6-9) now,
>> or should I wait until you've had a chance to look at things?
>>
>>   
> It is ok for me if you commit it now.  The earlier you commit, the
> earlier I start conflict resolution on the branch and look at your patches.

Did you mean all of it, or just the preliminary bits?  I've been holding
off on the final piece to give you time to investigate whether it will
cause problems with the new code.


Bernd
Vladimir Makarov July 20, 2010, 2:45 p.m. UTC | #8
Bernd Schmidt wrote:
> On 07/14/2010 12:02 AM, Vladimir Makarov wrote:
>   
>> Bernd Schmidt wrote:
>>     
>
>   
>>> Vlad, is it better for you if I check in the preliminary bits (6-9) now,
>>> or should I wait until you've had a chance to look at things?
>>>
>>>   
>>>       
>> It is ok for me if you commit it now.  The earlier you commit, the
>> earlier I start conflict resolution on the branch and look at your patches.
>>     
>
> Did you mean all of it, or just the preliminary bits?  I've been holding
> off on the final piece to give you time to investigate whether it will
> cause problems with the new code.
>
>   
I meant all of it.  I'll resolve the conflicts on my branch and submit 
my patches again.
Bernd Schmidt July 22, 2010, 3:47 p.m. UTC | #9
On 07/20/2010 04:45 PM, Vladimir Makarov wrote:
> I meant all of it.  I'll resolve the conflicts on my branch and submit
> my patches again.

All committed now after bootstrapping and regression testing again on
i686 and x86_64-linux.


Bernd
Nathan Froyd July 22, 2010, 6 p.m. UTC | #10
On Wed, Jul 14, 2010 at 04:00:23AM +0200, Bernd Schmidt wrote:
> On 07/14/2010 12:02 AM, Vladimir Makarov wrote:
> >> Vlad, is it better for you if I check in the preliminary bits (6-9) now,
> >> or should I wait until you've had a chance to look at things?
> >>
> >>   
> > It is ok for me if you commit it now.  The earlier you commit, the
> > earlier I start conflict resolution on the branch and look at your patches.
> 
> Patches 7-9 now committed after another bootstrap & regression test on
> i686-linux.  Still no observed changes in code generation.

At least this patch:

http://gcc.gnu.org/ml/gcc-patches/2010-06/msg02056.html

causes ICEs with powerpc-eabispe when compiling -msoft-float's libgcc:

../../.././gcc/dp-bit.c: In function '_fpadd_parts':
../../.././gcc/dp-bit.c:731:1: internal compiler error: in check_allocation, at ira.c:1629
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.

I am way out of my depth debugging this code; I tried loading everything
into gdb to provide a little more useful information, but of course the
compilation succeeds when cc1 is being run under gdb. :(

-Nathan
diff mbox

Patch

Index: gcc/ira-build.c
===================================================================
--- gcc.orig/ira-build.c
+++ gcc/ira-build.c
@@ -421,12 +421,13 @@  initiate_allocnos (void)
 
 /* Create and return an object corresponding to a new allocno A.  */
 static ira_object_t
-ira_create_object (ira_allocno_t a)
+ira_create_object (ira_allocno_t a, int subword)
 {
   enum reg_class cover_class = ALLOCNO_COVER_CLASS (a);
   ira_object_t obj = (ira_object_t) pool_alloc (object_pool);
 
   OBJECT_ALLOCNO (obj) = a;
+  OBJECT_SUBWORD (obj) = subword;
   OBJECT_CONFLICT_ID (obj) = ira_objects_num;
   OBJECT_CONFLICT_VEC_P (obj) = false;
   OBJECT_CONFLICT_ARRAY (obj) = NULL;
@@ -445,6 +446,7 @@  ira_create_object (ira_allocno_t a)
   ira_object_id_map
     = VEC_address (ira_object_t, ira_object_id_map_vec);
   ira_objects_num = VEC_length (ira_object_t, ira_object_id_map_vec);
+
   return obj;
 }
 
@@ -509,10 +511,12 @@  ira_create_allocno (int regno, bool cap_
   ALLOCNO_PREV_BUCKET_ALLOCNO (a) = NULL;
   ALLOCNO_FIRST_COALESCED_ALLOCNO (a) = a;
   ALLOCNO_NEXT_COALESCED_ALLOCNO (a) = a;
+  ALLOCNO_NUM_OBJECTS (a) = 0;
 
   VEC_safe_push (ira_allocno_t, heap, allocno_vec, a);
   ira_allocnos = VEC_address (ira_allocno_t, allocno_vec);
   ira_allocnos_num = VEC_length (ira_allocno_t, allocno_vec);
+
   return a;
 }
 
@@ -523,14 +527,27 @@  ira_set_allocno_cover_class (ira_allocno
   ALLOCNO_COVER_CLASS (a) = cover_class;
 }
 
-/* Allocate an object for allocno A and set ALLOCNO_OBJECT.  */
+/* Determine the number of objects we should associate with allocno A
+   and allocate them.  */
 void
-ira_create_allocno_object (ira_allocno_t a)
+ira_create_allocno_objects (ira_allocno_t a)
 {
-  ALLOCNO_OBJECT (a) = ira_create_object (a);
+  enum machine_mode mode = ALLOCNO_MODE (a);
+  enum reg_class cover_class = ALLOCNO_COVER_CLASS (a);
+  int n = ira_reg_class_nregs[cover_class][mode];
+  int i;
+
+  if (GET_MODE_SIZE (mode) != 2 * UNITS_PER_WORD || n != 2)
+    n = 1;
+
+  ALLOCNO_NUM_OBJECTS (a) = n;
+  for (i = 0; i < n; i++)
+    ALLOCNO_OBJECT (a, i) = ira_create_object (a, i);
 }
 
-/* For each allocno, create the corresponding ALLOCNO_OBJECT structure.  */
+/* For each allocno, set ALLOCNO_NUM_OBJECTS and create the
+   ALLOCNO_OBJECT structures.  This must be called after the cover
+   classes are known.  */
 static void
 create_allocno_objects (void)
 {
@@ -538,22 +555,28 @@  create_allocno_objects (void)
   ira_allocno_iterator ai;
 
   FOR_EACH_ALLOCNO (a, ai)
-    ira_create_allocno_object (a);
+    ira_create_allocno_objects (a);
 }
 
-/* Merge hard register conflicts from allocno FROM into allocno TO.  If
-   TOTAL_ONLY is true, we ignore ALLOCNO_CONFLICT_HARD_REGS.  */
+/* Merge hard register conflict information for all objects associated with
+   allocno TO into the corresponding objects associated with FROM.
+   If TOTAL_ONLY is true, we only merge OBJECT_TOTAL_CONFLICT_HARD_REGS.  */
 static void
 merge_hard_reg_conflicts (ira_allocno_t from, ira_allocno_t to,
 			  bool total_only)
 {
-  ira_object_t from_obj = ALLOCNO_OBJECT (from);
-  ira_object_t to_obj = ALLOCNO_OBJECT (to);
-  if (!total_only)
-    IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (to_obj),
-		      OBJECT_CONFLICT_HARD_REGS (from_obj));
-  IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (to_obj),
-		    OBJECT_TOTAL_CONFLICT_HARD_REGS (from_obj));
+  int i;
+  gcc_assert (ALLOCNO_NUM_OBJECTS (to) == ALLOCNO_NUM_OBJECTS (from));
+  for (i = 0; i < ALLOCNO_NUM_OBJECTS (to); i++)
+    {
+      ira_object_t from_obj = ALLOCNO_OBJECT (from, i);
+      ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
+      if (!total_only)
+	IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (to_obj),
+			  OBJECT_CONFLICT_HARD_REGS (from_obj));
+      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (to_obj),
+			OBJECT_TOTAL_CONFLICT_HARD_REGS (from_obj));
+    }
 #ifdef STACK_REGS
   if (!total_only && ALLOCNO_NO_STACK_REG_P (from))
     ALLOCNO_NO_STACK_REG_P (to) = true;
@@ -562,6 +585,20 @@  merge_hard_reg_conflicts (ira_allocno_t 
 #endif
 }
 
+/* Update hard register conflict information for all objects associated with
+   A to include the regs in SET.  */
+void
+ior_hard_reg_conflicts (ira_allocno_t a, HARD_REG_SET *set)
+{
+  ira_allocno_object_iterator i;
+  ira_object_t obj;
+  FOR_EACH_ALLOCNO_OBJECT (a, obj, i)
+    {
+      IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), *set);
+      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), *set);
+    }
+}
+
 /* Return TRUE if a conflict vector with NUM elements is more
    profitable than a conflict bit vector for OBJ.  */
 bool
@@ -616,14 +653,14 @@  allocate_conflict_bit_vec (ira_object_t 
 }
 
 /* Allocate and initialize the conflict vector or conflict bit vector
-   of A for NUM conflicting allocnos whatever is more profitable.  */
+   of OBJ for NUM conflicting allocnos whatever is more profitable.  */
 void
-ira_allocate_object_conflicts (ira_object_t a, int num)
+ira_allocate_object_conflicts (ira_object_t obj, int num)
 {
-  if (ira_conflict_vector_profitable_p (a, num))
-    ira_allocate_conflict_vec (a, num);
+  if (ira_conflict_vector_profitable_p (obj, num))
+    ira_allocate_conflict_vec (obj, num);
   else
-    allocate_conflict_bit_vec (a);
+    allocate_conflict_bit_vec (obj);
 }
 
 /* Add OBJ2 to the conflicts of OBJ1.  */
@@ -771,15 +808,14 @@  compress_conflict_vec (ira_object_t obj)
 static void
 compress_conflict_vecs (void)
 {
-  ira_allocno_t a;
-  ira_allocno_iterator ai;
+  ira_object_t obj;
+  ira_object_iterator oi;
 
   conflict_check = (int *) ira_allocate (sizeof (int) * ira_objects_num);
   memset (conflict_check, 0, sizeof (int) * ira_objects_num);
   curr_conflict_check_tick = 0;
-  FOR_EACH_ALLOCNO (a, ai)
+  FOR_EACH_OBJECT (obj, oi)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
       if (OBJECT_CONFLICT_VEC_P (obj))
 	compress_conflict_vec (obj);
     }
@@ -822,7 +858,7 @@  create_cap_allocno (ira_allocno_t a)
   ALLOCNO_MODE (cap) = ALLOCNO_MODE (a);
   cover_class = ALLOCNO_COVER_CLASS (a);
   ira_set_allocno_cover_class (cap, cover_class);
-  ira_create_allocno_object (cap);
+  ira_create_allocno_objects (cap);
   ALLOCNO_AVAILABLE_REGS_NUM (cap) = ALLOCNO_AVAILABLE_REGS_NUM (a);
   ALLOCNO_CAP_MEMBER (cap) = a;
   ALLOCNO_CAP (a) = cap;
@@ -837,7 +873,9 @@  create_cap_allocno (ira_allocno_t a)
   ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a);
   ALLOCNO_FREQ (cap) = ALLOCNO_FREQ (a);
   ALLOCNO_CALL_FREQ (cap) = ALLOCNO_CALL_FREQ (a);
+
   merge_hard_reg_conflicts (a, cap, false);
+
   ALLOCNO_CALLS_CROSSED_NUM (cap) = ALLOCNO_CALLS_CROSSED_NUM (a);
   if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
     {
@@ -848,7 +886,7 @@  create_cap_allocno (ira_allocno_t a)
   return cap;
 }
 
-/* Create and return allocno live range with given attributes.  */
+/* Create and return a live range for OBJECT with given attributes.  */
 live_range_t
 ira_create_live_range (ira_object_t obj, int start, int finish,
 		       live_range_t next)
@@ -863,6 +901,17 @@  ira_create_live_range (ira_object_t obj,
   return p;
 }
 
+/* Create a new live range for OBJECT and queue it at the head of its
+   live range list.  */
+void
+ira_add_live_range_to_object (ira_object_t object, int start, int finish)
+{
+  live_range_t p;
+  p = ira_create_live_range (object, start, finish,
+			     OBJECT_LIVE_RANGES (object));
+  OBJECT_LIVE_RANGES (object) = p;
+}
+
 /* Copy allocno live range R and return the result.  */
 static live_range_t
 copy_live_range (live_range_t r)
@@ -1031,13 +1080,17 @@  static void
 finish_allocno (ira_allocno_t a)
 {
   enum reg_class cover_class = ALLOCNO_COVER_CLASS (a);
-  ira_object_t obj = ALLOCNO_OBJECT (a);
+  ira_object_t obj;
+  ira_allocno_object_iterator oi;
 
-  ira_finish_live_range_list (OBJECT_LIVE_RANGES (obj));
-  ira_object_id_map[OBJECT_CONFLICT_ID (obj)] = NULL;
-  if (OBJECT_CONFLICT_ARRAY (obj) != NULL)
-    ira_free (OBJECT_CONFLICT_ARRAY (obj));
-  pool_free (object_pool, obj);
+  FOR_EACH_ALLOCNO_OBJECT (a, obj, oi)
+    {
+      ira_finish_live_range_list (OBJECT_LIVE_RANGES (obj));
+      ira_object_id_map[OBJECT_CONFLICT_ID (obj)] = NULL;
+      if (OBJECT_CONFLICT_ARRAY (obj) != NULL)
+	ira_free (OBJECT_CONFLICT_ARRAY (obj));
+      pool_free (object_pool, obj);
+    }
 
   ira_allocnos[ALLOCNO_NUM (a)] = NULL;
   if (ALLOCNO_HARD_REG_COSTS (a) != NULL)
@@ -1703,48 +1756,62 @@  change_object_in_range_list (live_range_
     r->object = obj;
 }
 
-/* Move all live ranges associated with allocno A to allocno OTHER_A.  */
+/* Move all live ranges associated with allocno FROM to allocno TO.  */
 static void
 move_allocno_live_ranges (ira_allocno_t from, ira_allocno_t to)
 {
-  ira_object_t from_obj = ALLOCNO_OBJECT (from);
-  ira_object_t to_obj = ALLOCNO_OBJECT (to);
-  live_range_t lr = OBJECT_LIVE_RANGES (from_obj);
+  int i;
+  int n = ALLOCNO_NUM_OBJECTS (from);
+
+  gcc_assert (n == ALLOCNO_NUM_OBJECTS (to));
 
-  if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL)
+  for (i = 0; i < n; i++)
     {
-      fprintf (ira_dump_file,
-	       "      Moving ranges of a%dr%d to a%dr%d: ",
-	       ALLOCNO_NUM (from), ALLOCNO_REGNO (from),
-	       ALLOCNO_NUM (to), ALLOCNO_REGNO (to));
-      ira_print_live_range_list (ira_dump_file, lr);
-    }
-  change_object_in_range_list (lr, to_obj);
-  OBJECT_LIVE_RANGES (to_obj)
-    = ira_merge_live_ranges (lr, OBJECT_LIVE_RANGES (to_obj));
-  OBJECT_LIVE_RANGES (from_obj) = NULL;
+      ira_object_t from_obj = ALLOCNO_OBJECT (from, i);
+      ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
+      live_range_t lr = OBJECT_LIVE_RANGES (from_obj);
+
+      if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL)
+	{
+	  fprintf (ira_dump_file,
+		   "      Moving ranges of a%dr%d to a%dr%d: ",
+		   ALLOCNO_NUM (from), ALLOCNO_REGNO (from),
+		   ALLOCNO_NUM (to), ALLOCNO_REGNO (to));
+	  ira_print_live_range_list (ira_dump_file, lr);
+	}
+      change_object_in_range_list (lr, to_obj);
+      OBJECT_LIVE_RANGES (to_obj)
+	= ira_merge_live_ranges (lr, OBJECT_LIVE_RANGES (to_obj));
+      OBJECT_LIVE_RANGES (from_obj) = NULL;
+    }
 }
 
-/* Copy all live ranges associated with allocno A to allocno OTHER_A.  */
 static void
 copy_allocno_live_ranges (ira_allocno_t from, ira_allocno_t to)
 {
-  ira_object_t from_obj = ALLOCNO_OBJECT (from);
-  ira_object_t to_obj = ALLOCNO_OBJECT (to);
-  live_range_t lr = OBJECT_LIVE_RANGES (from_obj);
+  int i;
+  int n = ALLOCNO_NUM_OBJECTS (from);
 
-  if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL)
+  gcc_assert (n == ALLOCNO_NUM_OBJECTS (to));
+
+  for (i = 0; i < n; i++)
     {
-      fprintf (ira_dump_file,
-	       "      Copying ranges of a%dr%d to a%dr%d: ",
-	       ALLOCNO_NUM (from), ALLOCNO_REGNO (from),
-	       ALLOCNO_NUM (to), ALLOCNO_REGNO (to));
-      ira_print_live_range_list (ira_dump_file, lr);
-    }
-  lr = ira_copy_live_range_list (lr);
-  change_object_in_range_list (lr, to_obj);
-  OBJECT_LIVE_RANGES (to_obj)
-    = ira_merge_live_ranges (lr, OBJECT_LIVE_RANGES (to_obj));
+      ira_object_t from_obj = ALLOCNO_OBJECT (from, i);
+      ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
+      live_range_t lr = OBJECT_LIVE_RANGES (from_obj);
+
+      if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL)
+	{
+	  fprintf (ira_dump_file, "      Copying ranges of a%dr%d to a%dr%d: ",
+		   ALLOCNO_NUM (from), ALLOCNO_REGNO (from),
+		   ALLOCNO_NUM (to), ALLOCNO_REGNO (to));
+	  ira_print_live_range_list (ira_dump_file, lr);
+	}
+      lr = ira_copy_live_range_list (lr);
+      change_object_in_range_list (lr, to_obj);
+      OBJECT_LIVE_RANGES (to_obj)
+	= ira_merge_live_ranges (lr, OBJECT_LIVE_RANGES (to_obj));
+    }
 }
 
 /* Return TRUE if NODE represents a loop with low register
@@ -2124,13 +2191,15 @@  remove_low_level_allocnos (void)
       regno = ALLOCNO_REGNO (a);
       if (ira_loop_tree_root->regno_allocno_map[regno] == a)
 	{
-	  ira_object_t obj = ALLOCNO_OBJECT (a);
+	  ira_object_t obj;
+	  ira_allocno_object_iterator oi;
 
 	  ira_regno_allocno_map[regno] = a;
 	  ALLOCNO_NEXT_REGNO_ALLOCNO (a) = NULL;
 	  ALLOCNO_CAP_MEMBER (a) = NULL;
-	  COPY_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
-			     OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+	  FOR_EACH_ALLOCNO_OBJECT (a, obj, oi)
+	    COPY_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
+			       OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
 #ifdef STACK_REGS
 	  if (ALLOCNO_TOTAL_NO_STACK_REG_P (a))
 	    ALLOCNO_NO_STACK_REG_P (a) = true;
@@ -2193,6 +2262,8 @@  update_bad_spill_attribute (void)
   int i;
   ira_allocno_t a;
   ira_allocno_iterator ai;
+  ira_allocno_object_iterator aoi;
+  ira_object_t obj;
   live_range_t r;
   enum reg_class cover_class;
   bitmap_head dead_points[N_REG_CLASSES];
@@ -2204,31 +2275,36 @@  update_bad_spill_attribute (void)
     }
   FOR_EACH_ALLOCNO (a, ai)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
       cover_class = ALLOCNO_COVER_CLASS (a);
       if (cover_class == NO_REGS)
 	continue;
-      for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
-	bitmap_set_bit (&dead_points[cover_class], r->finish);
+      FOR_EACH_ALLOCNO_OBJECT (a, obj, aoi)
+	for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+	  bitmap_set_bit (&dead_points[cover_class], r->finish);
     }
   FOR_EACH_ALLOCNO (a, ai)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
       cover_class = ALLOCNO_COVER_CLASS (a);
       if (cover_class == NO_REGS)
 	continue;
       if (! ALLOCNO_BAD_SPILL_P (a))
 	continue;
-      for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+      FOR_EACH_ALLOCNO_OBJECT (a, obj, aoi)
 	{
-	  for (i = r->start + 1; i < r->finish; i++)
-	    if (bitmap_bit_p (&dead_points[cover_class], i))
+	  for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+	    {
+	      for (i = r->start + 1; i < r->finish; i++)
+		if (bitmap_bit_p (&dead_points[cover_class], i))
+		  break;
+	      if (i < r->finish)
+		break;
+	    }
+	  if (r != NULL)
+	    {
+	      ALLOCNO_BAD_SPILL_P (a) = false;
 	      break;
-	  if (i < r->finish)
-	    break;
+	    }
 	}
-      if (r != NULL)
-	ALLOCNO_BAD_SPILL_P (a) = false;
     }
   for (i = 0; i < ira_reg_class_cover_size; i++)
     {
@@ -2246,57 +2322,69 @@  setup_min_max_allocno_live_range_point (
   int i;
   ira_allocno_t a, parent_a, cap;
   ira_allocno_iterator ai;
+#ifdef ENABLE_IRA_CHECKING
+  ira_object_iterator oi;
+  ira_object_t obj;
+#endif
   live_range_t r;
   ira_loop_tree_node_t parent;
 
   FOR_EACH_ALLOCNO (a, ai)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      r = OBJECT_LIVE_RANGES (obj);
-      if (r == NULL)
-	continue;
-      OBJECT_MAX (obj) = r->finish;
-      for (; r->next != NULL; r = r->next)
-	;
-      OBJECT_MIN (obj) = r->start;
+      int n = ALLOCNO_NUM_OBJECTS (a);
+      for (i = 0; i < n; i++)
+	{
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  r = OBJECT_LIVE_RANGES (obj);
+	  if (r == NULL)
+	    continue;
+	  OBJECT_MAX (obj) = r->finish;
+	  for (; r->next != NULL; r = r->next)
+	    ;
+	  OBJECT_MIN (obj) = r->start;
+	}
     }
   for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
     for (a = ira_regno_allocno_map[i];
 	 a != NULL;
 	 a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
       {
-	ira_object_t obj = ALLOCNO_OBJECT (a);
-	ira_object_t parent_obj;
-
-	if (OBJECT_MAX (obj) < 0)
-	  continue;
-	ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
-	/* Accumulation of range info.  */
-	if (ALLOCNO_CAP (a) != NULL)
+	int j;
+	int n = ALLOCNO_NUM_OBJECTS (a);
+	for (j = 0; j < n; j++)
 	  {
-	    for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
+	    ira_object_t obj = ALLOCNO_OBJECT (a, j);
+	    ira_object_t parent_obj;
+
+	    if (OBJECT_MAX (obj) < 0)
+	      continue;
+	    ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
+	    /* Accumulation of range info.  */
+	    if (ALLOCNO_CAP (a) != NULL)
 	      {
-		ira_object_t cap_obj = ALLOCNO_OBJECT (cap);
-		if (OBJECT_MAX (cap_obj) < OBJECT_MAX (obj))
-		  OBJECT_MAX (cap_obj) = OBJECT_MAX (obj);
-		if (OBJECT_MIN (cap_obj) > OBJECT_MIN (obj))
-		  OBJECT_MIN (cap_obj) = OBJECT_MIN (obj);
+		for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
+		  {
+		    ira_object_t cap_obj = ALLOCNO_OBJECT (cap, j);
+		    if (OBJECT_MAX (cap_obj) < OBJECT_MAX (obj))
+		      OBJECT_MAX (cap_obj) = OBJECT_MAX (obj);
+		    if (OBJECT_MIN (cap_obj) > OBJECT_MIN (obj))
+		      OBJECT_MIN (cap_obj) = OBJECT_MIN (obj);
+		  }
+		continue;
 	      }
-	    continue;
+	    if ((parent = ALLOCNO_LOOP_TREE_NODE (a)->parent) == NULL)
+	      continue;
+	    parent_a = parent->regno_allocno_map[i];
+	    parent_obj = ALLOCNO_OBJECT (parent_a, j);
+	    if (OBJECT_MAX (parent_obj) < OBJECT_MAX (obj))
+	      OBJECT_MAX (parent_obj) = OBJECT_MAX (obj);
+	    if (OBJECT_MIN (parent_obj) > OBJECT_MIN (obj))
+	      OBJECT_MIN (parent_obj) = OBJECT_MIN (obj);
 	  }
-	if ((parent = ALLOCNO_LOOP_TREE_NODE (a)->parent) == NULL)
-	  continue;
-	parent_a = parent->regno_allocno_map[i];
-	parent_obj = ALLOCNO_OBJECT (parent_a);
-	if (OBJECT_MAX (parent_obj) < OBJECT_MAX (obj))
-	  OBJECT_MAX (parent_obj) = OBJECT_MAX (obj);
-	if (OBJECT_MIN (parent_obj) > OBJECT_MIN (obj))
-	  OBJECT_MIN (parent_obj) = OBJECT_MIN (obj);
       }
 #ifdef ENABLE_IRA_CHECKING
-  FOR_EACH_ALLOCNO (a, ai)
+  FOR_EACH_OBJECT (obj, oi)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
       if ((0 <= OBJECT_MIN (obj) && OBJECT_MIN (obj) <= ira_max_point)
 	  && (0 <= OBJECT_MAX (obj) && OBJECT_MAX (obj) <= ira_max_point))
 	continue;
@@ -2311,7 +2399,7 @@  setup_min_max_allocno_live_range_point (
    (min).  Allocnos with the same start are ordered according their
    finish (max).  */
 static int
-allocno_range_compare_func (const void *v1p, const void *v2p)
+object_range_compare_func (const void *v1p, const void *v2p)
 {
   int diff;
   ira_object_t obj1 = *(const ira_object_t *) v1p;
@@ -2339,9 +2427,15 @@  sort_conflict_id_map (void)
 
   num = 0;
   FOR_EACH_ALLOCNO (a, ai)
-    ira_object_id_map[num++] = ALLOCNO_OBJECT (a);
+    {
+      ira_allocno_object_iterator oi;
+      ira_object_t obj;
+
+      FOR_EACH_ALLOCNO_OBJECT (a, obj, oi)
+	ira_object_id_map[num++] = obj;
+    }
   qsort (ira_object_id_map, num, sizeof (ira_object_t),
-	 allocno_range_compare_func);
+	 object_range_compare_func);
   for (i = 0; i < num; i++)
     {
       ira_object_t obj = ira_object_id_map[i];
@@ -2360,7 +2454,9 @@  setup_min_max_conflict_allocno_ids (void
   int cover_class;
   int i, j, min, max, start, finish, first_not_finished, filled_area_start;
   int *live_range_min, *last_lived;
+  int word0_min, word0_max;
   ira_allocno_t a;
+  ira_allocno_iterator ai;
 
   live_range_min = (int *) ira_allocate (sizeof (int) * ira_objects_num);
   cover_class = -1;
@@ -2387,10 +2483,10 @@  setup_min_max_conflict_allocno_ids (void
 	  /* If we skip an allocno, the allocno with smaller ids will
 	     be also skipped because of the secondary sorting the
 	     range finishes (see function
-	     allocno_range_compare_func).  */
+	     object_range_compare_func).  */
 	  while (first_not_finished < i
 		 && start > OBJECT_MAX (ira_object_id_map
-					 [first_not_finished]))
+					[first_not_finished]))
 	    first_not_finished++;
 	  min = first_not_finished;
 	}
@@ -2441,6 +2537,38 @@  setup_min_max_conflict_allocno_ids (void
     }
   ira_free (last_lived);
   ira_free (live_range_min);
+
+  /* For allocnos with more than one object, we may later record extra conflicts in
+     subobject 0 that we cannot really know about here.
+     For now, simply widen the min/max range of these subobjects.  */
+
+  word0_min = INT_MAX;
+  word0_max = INT_MIN;
+
+  FOR_EACH_ALLOCNO (a, ai)
+    {
+      int n = ALLOCNO_NUM_OBJECTS (a);
+      ira_object_t obj0;
+      if (n < 2)
+	continue;
+      obj0 = ALLOCNO_OBJECT (a, 0);
+      if (OBJECT_CONFLICT_ID (obj0) < word0_min)
+	word0_min = OBJECT_CONFLICT_ID (obj0);
+      if (OBJECT_CONFLICT_ID (obj0) > word0_max)
+	word0_max = OBJECT_CONFLICT_ID (obj0);
+    }
+  FOR_EACH_ALLOCNO (a, ai)
+    {
+      int n = ALLOCNO_NUM_OBJECTS (a);
+      ira_object_t obj0;
+      if (n < 2)
+	continue;
+      obj0 = ALLOCNO_OBJECT (a, 0);
+      if (OBJECT_MIN (obj0) > word0_min)
+	OBJECT_MIN (obj0) = word0_min;
+      if (OBJECT_MAX (obj0) < word0_max)
+	OBJECT_MAX (obj0) = word0_max;
+    }
 }
 
 
@@ -2528,6 +2656,7 @@  copy_info_to_removed_store_destinations 
       if (a != regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))])
 	/* This allocno will be removed.  */
 	continue;
+
       /* Caps will be removed.  */
       ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
       for (parent = ALLOCNO_LOOP_TREE_NODE (a)->parent;
@@ -2540,8 +2669,10 @@  copy_info_to_removed_store_destinations 
 	  break;
       if (parent == NULL || parent_a == NULL)
 	continue;
+
       copy_allocno_live_ranges (a, parent_a);
       merge_hard_reg_conflicts (a, parent_a, true);
+
       ALLOCNO_CALL_FREQ (parent_a) += ALLOCNO_CALL_FREQ (a);
       ALLOCNO_CALLS_CROSSED_NUM (parent_a)
 	+= ALLOCNO_CALLS_CROSSED_NUM (a);
@@ -2581,14 +2712,16 @@  ira_flattening (int max_regno_before_emi
   new_pseudos_p = merged_p = false;
   FOR_EACH_ALLOCNO (a, ai)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
+      ira_allocno_object_iterator oi;
+      ira_object_t obj;
       if (ALLOCNO_CAP_MEMBER (a) != NULL)
 	/* Caps are not in the regno allocno maps and they are never
 	   will be transformed into allocnos existing after IR
 	   flattening.  */
 	continue;
-      COPY_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
-			 OBJECT_CONFLICT_HARD_REGS (obj));
+      FOR_EACH_ALLOCNO_OBJECT (a, obj, oi)
+	COPY_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+			   OBJECT_CONFLICT_HARD_REGS (obj));
 #ifdef STACK_REGS
       ALLOCNO_TOTAL_NO_STACK_REG_P (a) = ALLOCNO_NO_STACK_REG_P (a);
 #endif
@@ -2673,13 +2806,17 @@  ira_flattening (int max_regno_before_emi
       /* Rebuild conflicts.  */
       FOR_EACH_ALLOCNO (a, ai)
 	{
-	  ira_object_t obj = ALLOCNO_OBJECT (a);
+	  ira_allocno_object_iterator oi;
+	  ira_object_t obj;
 	  if (a != regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))]
 	      || ALLOCNO_CAP_MEMBER (a) != NULL)
 	    continue;
-	  for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
-	    ira_assert (r->object == obj);
-	  clear_conflicts (obj);
+	  FOR_EACH_ALLOCNO_OBJECT (a, obj, oi)
+	    {
+	      for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+		ira_assert (r->object == obj);
+	      clear_conflicts (obj);
+	    }
 	}
       objects_live = sparseset_alloc (ira_objects_num);
       for (i = 0; i < ira_max_point; i++)
@@ -2691,6 +2828,7 @@  ira_flattening (int max_regno_before_emi
 	      if (a != regno_top_level_allocno_map[REGNO (ALLOCNO_REG (a))]
 		  || ALLOCNO_CAP_MEMBER (a) != NULL)
 		continue;
+
 	      cover_class = ALLOCNO_COVER_CLASS (a);
 	      sparseset_set_bit (objects_live, OBJECT_CONFLICT_ID (obj));
 	      EXECUTE_IF_SET_IN_SPARSESET (objects_live, n)
@@ -2698,7 +2836,6 @@  ira_flattening (int max_regno_before_emi
 		  ira_object_t live_obj = ira_object_id_map[n];
 		  ira_allocno_t live_a = OBJECT_ALLOCNO (live_obj);
 		  enum reg_class live_cover = ALLOCNO_COVER_CLASS (live_a);
-
 		  if (ira_reg_classes_intersect_p[cover_class][live_cover]
 		      /* Don't set up conflict for the allocno with itself.  */
 		      && live_a != a)
@@ -2930,40 +3067,39 @@  ira_build (bool loops_p)
 	 allocno crossing calls.  */
       FOR_EACH_ALLOCNO (a, ai)
 	if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
-	  {
-	    ira_object_t obj = ALLOCNO_OBJECT (a);
-	    IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
-			      call_used_reg_set);
-	    IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
-			      call_used_reg_set);
-	  }
+	  ior_hard_reg_conflicts (a, &call_used_reg_set);
     }
   if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
     print_copies (ira_dump_file);
   if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
     {
-      int n, nr;
+      int n, nr, nr_big;
       ira_allocno_t a;
       live_range_t r;
       ira_allocno_iterator ai;
 
       n = 0;
+      nr = 0;
+      nr_big = 0;
       FOR_EACH_ALLOCNO (a, ai)
 	{
-	  ira_object_t obj = ALLOCNO_OBJECT (a);
-	  n += OBJECT_NUM_CONFLICTS (obj);
+	  int j, nobj = ALLOCNO_NUM_OBJECTS (a);
+	  if (nobj > 1)
+	    nr_big++;
+	  for (j = 0; j < nobj; j++)
+	    {
+	      ira_object_t obj = ALLOCNO_OBJECT (a, j);
+	      n += OBJECT_NUM_CONFLICTS (obj);
+	      for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+		nr++;
+	    }
 	}
-      nr = 0;
-      FOR_EACH_ALLOCNO (a, ai)
-	for (r = OBJECT_LIVE_RANGES (ALLOCNO_OBJECT (a)); r != NULL;
-	     r = r->next)
-	  nr++;
       fprintf (ira_dump_file, "  regions=%d, blocks=%d, points=%d\n",
 	       VEC_length (loop_p, ira_loops.larray), n_basic_blocks,
 	       ira_max_point);
       fprintf (ira_dump_file,
-	       "    allocnos=%d, copies=%d, conflicts=%d, ranges=%d\n",
-	       ira_allocnos_num, ira_copies_num, n, nr);
+	       "    allocnos=%d (big %d), copies=%d, conflicts=%d, ranges=%d\n",
+	       ira_allocnos_num, nr_big, ira_copies_num, n, nr);
     }
   return loops_p;
 }
Index: gcc/ira.c
===================================================================
--- gcc.orig/ira.c
+++ gcc/ira.c
@@ -1376,9 +1376,8 @@  setup_prohibited_mode_move_regs (void)
 static bool
 ira_bad_reload_regno_1 (int regno, rtx x)
 {
-  int x_regno;
+  int x_regno, n, i;
   ira_allocno_t a;
-  ira_object_t obj;
   enum reg_class pref;
 
   /* We only deal with pseudo regs.  */
@@ -1398,10 +1397,13 @@  ira_bad_reload_regno_1 (int regno, rtx x
   /* If the pseudo conflicts with REGNO, then we consider REGNO a
      poor choice for a reload regno.  */
   a = ira_regno_allocno_map[x_regno];
-  obj = ALLOCNO_OBJECT (a);
-  if (TEST_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno))
-    return true;
-
+  n = ALLOCNO_NUM_OBJECTS (a);
+  for (i = 0; i < n; i++)
+    {
+      ira_object_t obj = ALLOCNO_OBJECT (a, i);
+      if (TEST_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno))
+	return true;
+    }
   return false;
 }
 
@@ -1749,32 +1751,60 @@  static void
 check_allocation (void)
 {
   ira_allocno_t a;
-  int hard_regno, nregs;
+  int hard_regno, nregs, conflict_nregs;
   ira_allocno_iterator ai;
 
   FOR_EACH_ALLOCNO (a, ai)
     {
-      ira_object_t obj, conflict_obj;
-      ira_object_conflict_iterator oci;
+      int n = ALLOCNO_NUM_OBJECTS (a);
+      int i;
 
       if (ALLOCNO_CAP_MEMBER (a) != NULL
 	  || (hard_regno = ALLOCNO_HARD_REGNO (a)) < 0)
 	continue;
       nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (a)];
-      obj = ALLOCNO_OBJECT (a);
-      FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+      if (n > 1)
+	{
+	  gcc_assert (n == nregs);
+	  nregs = 1;
+	}
+      for (i = 0; i < n; i++)
 	{
-	  ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
-	  int conflict_hard_regno = ALLOCNO_HARD_REGNO (conflict_a);
-	  if (conflict_hard_regno >= 0)
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  ira_object_t conflict_obj;
+	  ira_object_conflict_iterator oci;
+	  int this_regno = hard_regno;
+	  if (n > 1)
 	    {
-	      int conflict_nregs
-		= (hard_regno_nregs
-		   [conflict_hard_regno][ALLOCNO_MODE (conflict_a)]);
-	      if ((conflict_hard_regno <= hard_regno
-		   && hard_regno < conflict_hard_regno + conflict_nregs)
-		  || (hard_regno <= conflict_hard_regno
-		      && conflict_hard_regno < hard_regno + nregs))
+	      if (WORDS_BIG_ENDIAN)
+		this_regno += n - i - 1;
+	      else
+		this_regno += i;
+	    }
+	  FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+	    {
+	      ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
+	      int conflict_hard_regno = ALLOCNO_HARD_REGNO (conflict_a);
+	      if (conflict_hard_regno < 0)
+		continue;
+	      if (ALLOCNO_NUM_OBJECTS (conflict_a) > 1)
+		{
+		  if (WORDS_BIG_ENDIAN)
+		    conflict_hard_regno += (ALLOCNO_NUM_OBJECTS (conflict_a)
+					    - OBJECT_SUBWORD (conflict_obj) - 1);
+		  else
+		    conflict_hard_regno += OBJECT_SUBWORD (conflict_obj);
+		  conflict_nregs = 1;
+		}
+	      else
+		conflict_nregs
+		  = (hard_regno_nregs
+		     [conflict_hard_regno][ALLOCNO_MODE (conflict_a)]);
+
+	      if ((conflict_hard_regno <= this_regno
+		 && this_regno < conflict_hard_regno + conflict_nregs)
+		|| (this_regno <= conflict_hard_regno
+		    && conflict_hard_regno < this_regno + nregs))
 		{
 		  fprintf (stderr, "bad allocation for %d and %d\n",
 			   ALLOCNO_REGNO (a), ALLOCNO_REGNO (conflict_a));
Index: gcc/ira-color.c
===================================================================
--- gcc.orig/ira-color.c
+++ gcc/ira-color.c
@@ -93,16 +93,29 @@  static VEC(ira_allocno_t,heap) *removed_
 static bool
 allocnos_have_intersected_live_ranges_p (ira_allocno_t a1, ira_allocno_t a2)
 {
-  ira_object_t obj1 = ALLOCNO_OBJECT (a1);
-  ira_object_t obj2 = ALLOCNO_OBJECT (a2);
+  int i, j;
+  int n1 = ALLOCNO_NUM_OBJECTS (a1);
+  int n2 = ALLOCNO_NUM_OBJECTS (a2);
+
   if (a1 == a2)
     return false;
   if (ALLOCNO_REG (a1) != NULL && ALLOCNO_REG (a2) != NULL
       && (ORIGINAL_REGNO (ALLOCNO_REG (a1))
 	  == ORIGINAL_REGNO (ALLOCNO_REG (a2))))
     return false;
-  return ira_live_ranges_intersect_p (OBJECT_LIVE_RANGES (obj1),
-				      OBJECT_LIVE_RANGES (obj2));
+
+  for (i = 0; i < n1; i++)
+    {
+      ira_object_t c1 = ALLOCNO_OBJECT (a1, i);
+      for (j = 0; j < n2; j++)
+	{
+	  ira_object_t c2 = ALLOCNO_OBJECT (a2, j);
+	  if (ira_live_ranges_intersect_p (OBJECT_LIVE_RANGES (c1),
+					   OBJECT_LIVE_RANGES (c2)))
+	    return true;
+	}
+    }
+  return false;
 }
 
 #ifdef ENABLE_IRA_CHECKING
@@ -441,12 +454,11 @@  print_coalesced_allocno (ira_allocno_t a
 static bool
 assign_hard_reg (ira_allocno_t allocno, bool retry_p)
 {
-  HARD_REG_SET conflicting_regs;
-  int i, j, k, hard_regno, best_hard_regno, class_size;
-  int cost, mem_cost, min_cost, full_cost, min_full_cost;
+  HARD_REG_SET conflicting_regs[2];
+  int i, j, hard_regno, nregs, best_hard_regno, class_size;
+  int cost, mem_cost, min_cost, full_cost, min_full_cost, nwords;
   int *a_costs;
-  int *conflict_costs;
-  enum reg_class cover_class, conflict_cover_class;
+  enum reg_class cover_class;
   enum machine_mode mode;
   ira_allocno_t a;
   static int costs[FIRST_PSEUDO_REGISTER], full_costs[FIRST_PSEUDO_REGISTER];
@@ -458,11 +470,13 @@  assign_hard_reg (ira_allocno_t allocno, 
   bool no_stack_reg_p;
 #endif
 
+  nwords = ALLOCNO_NUM_OBJECTS (allocno);
   ira_assert (! ALLOCNO_ASSIGNED_P (allocno));
   cover_class = ALLOCNO_COVER_CLASS (allocno);
   class_size = ira_class_hard_regs_num[cover_class];
   mode = ALLOCNO_MODE (allocno);
-  CLEAR_HARD_REG_SET (conflicting_regs);
+  for (i = 0; i < nwords; i++)
+    CLEAR_HARD_REG_SET (conflicting_regs[i]);
   best_hard_regno = -1;
   memset (full_costs, 0, sizeof (int) * class_size);
   mem_cost = 0;
@@ -477,13 +491,9 @@  assign_hard_reg (ira_allocno_t allocno, 
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      ira_object_t conflict_obj;
-      ira_object_conflict_iterator oci;
-
+      int word;
       mem_cost += ALLOCNO_UPDATED_MEMORY_COST (a);
-      IOR_HARD_REG_SET (conflicting_regs,
-			OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+
       ira_allocate_and_copy_costs (&ALLOCNO_UPDATED_HARD_REG_COSTS (a),
 				   cover_class, ALLOCNO_HARD_REG_COSTS (a));
       a_costs = ALLOCNO_UPDATED_HARD_REG_COSTS (a);
@@ -502,44 +512,68 @@  assign_hard_reg (ira_allocno_t allocno, 
 	    costs[i] += cost;
 	    full_costs[i] += cost;
 	  }
-      /* Take preferences of conflicting allocnos into account.  */
-      FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+      for (word = 0; word < nwords; word++)
 	{
-	  ira_allocno_t conflict_allocno = OBJECT_ALLOCNO (conflict_obj);
+	  ira_object_t conflict_obj;
+	  ira_object_t obj = ALLOCNO_OBJECT (allocno, word);
+	  ira_object_conflict_iterator oci;
 
-	  /* Reload can give another class so we need to check all
-	     allocnos.  */
-	  if (retry_p || bitmap_bit_p (consideration_allocno_bitmap,
-				       ALLOCNO_NUM (conflict_allocno)))
+	  IOR_HARD_REG_SET (conflicting_regs[word],
+			    OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+	  /* Take preferences of conflicting allocnos into account.  */
+	  FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
 	    {
+	      ira_allocno_t conflict_allocno = OBJECT_ALLOCNO (conflict_obj);
+	      enum reg_class conflict_cover_class;
+	      /* Reload can give another class so we need to check all
+		 allocnos.  */
+	      if (!retry_p && !bitmap_bit_p (consideration_allocno_bitmap,
+					     ALLOCNO_NUM (conflict_allocno)))
+		continue;
 	      conflict_cover_class = ALLOCNO_COVER_CLASS (conflict_allocno);
 	      ira_assert (ira_reg_classes_intersect_p
 			  [cover_class][conflict_cover_class]);
-	      if (allocno_coalesced_p)
-		{
-		  if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
-				    ALLOCNO_NUM (conflict_allocno)))
-		    continue;
-		  bitmap_set_bit (processed_coalesced_allocno_bitmap,
-				  ALLOCNO_NUM (conflict_allocno));
-		}
 	      if (ALLOCNO_ASSIGNED_P (conflict_allocno))
 		{
-		  if ((hard_regno = ALLOCNO_HARD_REGNO (conflict_allocno)) >= 0
+		  hard_regno = ALLOCNO_HARD_REGNO (conflict_allocno);
+		  if (hard_regno >= 0
 		      && ira_class_hard_reg_index[cover_class][hard_regno] >= 0)
 		    {
-		      IOR_HARD_REG_SET
-			(conflicting_regs,
-			 ira_reg_mode_hard_regset
-			 [hard_regno][ALLOCNO_MODE (conflict_allocno)]);
+		      enum machine_mode mode = ALLOCNO_MODE (conflict_allocno);
+		      int conflict_nregs = hard_regno_nregs[hard_regno][mode];
+		      int n_objects = ALLOCNO_NUM_OBJECTS (conflict_allocno);
+		      if (conflict_nregs == n_objects && conflict_nregs > 1)
+			{
+			  int num = OBJECT_SUBWORD (conflict_obj);
+			  if (WORDS_BIG_ENDIAN)
+			    SET_HARD_REG_BIT (conflicting_regs[word],
+					      hard_regno + n_objects - num - 1);
+			  else
+			    SET_HARD_REG_BIT (conflicting_regs[word],
+					      hard_regno + num);
+			}
+		      else
+			IOR_HARD_REG_SET (conflicting_regs[word],
+					  ira_reg_mode_hard_regset[hard_regno][mode]);
 		      if (hard_reg_set_subset_p (reg_class_contents[cover_class],
-						 conflicting_regs))
+						 conflicting_regs[word]))
 			goto fail;
 		    }
 		}
 	      else if (! ALLOCNO_MAY_BE_SPILLED_P (ALLOCNO_FIRST_COALESCED_ALLOCNO
 						   (conflict_allocno)))
 		{
+		  int k, *conflict_costs;
+
+		  if (allocno_coalesced_p)
+		    {
+		      if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
+					ALLOCNO_NUM (conflict_allocno)))
+			continue;
+		      bitmap_set_bit (processed_coalesced_allocno_bitmap,
+				      ALLOCNO_NUM (conflict_allocno));
+		    }
+
 		  ira_allocate_and_copy_costs
 		    (&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (conflict_allocno),
 		     conflict_cover_class,
@@ -580,6 +614,7 @@  assign_hard_reg (ira_allocno_t allocno, 
     }
   update_conflict_hard_regno_costs (full_costs, cover_class, false);
   min_cost = min_full_cost = INT_MAX;
+
   /* We don't care about giving callee saved registers to allocnos no
      living through calls because call clobbered registers are
      allocated first (it is usual practice to put them first in
@@ -587,14 +622,34 @@  assign_hard_reg (ira_allocno_t allocno, 
   for (i = 0; i < class_size; i++)
     {
       hard_regno = ira_class_hard_regs[cover_class][i];
+      nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (allocno)];
 #ifdef STACK_REGS
       if (no_stack_reg_p
 	  && FIRST_STACK_REG <= hard_regno && hard_regno <= LAST_STACK_REG)
 	continue;
 #endif
-      if (! ira_hard_reg_not_in_set_p (hard_regno, mode, conflicting_regs)
-	  || TEST_HARD_REG_BIT (prohibited_class_mode_regs[cover_class][mode],
-				hard_regno))
+      if (TEST_HARD_REG_BIT (prohibited_class_mode_regs[cover_class][mode],
+			     hard_regno))
+	continue;
+      for (j = 0; j < nregs; j++)
+	{
+	  int k;
+	  int set_to_test_start = 0, set_to_test_end = nwords;
+	  if (nregs == nwords)
+	    {
+	      if (WORDS_BIG_ENDIAN)
+		set_to_test_start = nwords - j - 1;
+	      else
+		set_to_test_start = j;
+	      set_to_test_end = set_to_test_start + 1;
+	    }
+	  for (k = set_to_test_start; k < set_to_test_end; k++)
+	    if (TEST_HARD_REG_BIT (conflicting_regs[k], hard_regno + j))
+	      break;
+	  if (k != set_to_test_end)
+	    break;
+	}
+      if (j != nregs)
 	continue;
       cost = costs[i];
       full_cost = full_costs[i];
@@ -875,7 +930,7 @@  static splay_tree uncolorable_allocnos_s
 static void
 push_allocno_to_stack (ira_allocno_t allocno)
 {
-  int left_conflicts_size, conflict_size, size;
+  int size;
   ira_allocno_t a;
   enum reg_class cover_class;
 
@@ -885,77 +940,90 @@  push_allocno_to_stack (ira_allocno_t all
   if (cover_class == NO_REGS)
     return;
   size = ira_reg_class_nregs[cover_class][ALLOCNO_MODE (allocno)];
+  if (ALLOCNO_NUM_OBJECTS (allocno) > 1)
+    {
+      /* We will deal with the subwords individually.  */
+      gcc_assert (size == ALLOCNO_NUM_OBJECTS (allocno));
+      size = 1;
+    }
   if (allocno_coalesced_p)
     bitmap_clear (processed_coalesced_allocno_bitmap);
+
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      ira_object_t conflict_obj;
-      ira_object_conflict_iterator oci;
-
-      FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+      int i, n = ALLOCNO_NUM_OBJECTS (a);
+      for (i = 0; i < n; i++)
 	{
-	  ira_allocno_t conflict_allocno = OBJECT_ALLOCNO (conflict_obj);
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  int conflict_size;
+	  ira_object_t conflict_obj;
+	  ira_object_conflict_iterator oci;
 
-	  conflict_allocno = ALLOCNO_FIRST_COALESCED_ALLOCNO (conflict_allocno);
-	  if (bitmap_bit_p (coloring_allocno_bitmap,
-			    ALLOCNO_NUM (conflict_allocno)))
+	  FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
 	    {
+	      ira_allocno_t conflict_allocno = OBJECT_ALLOCNO (conflict_obj);
+	      int left_conflicts_size;
+
+	      conflict_allocno = ALLOCNO_FIRST_COALESCED_ALLOCNO (conflict_allocno);
+	      if (!bitmap_bit_p (coloring_allocno_bitmap,
+				 ALLOCNO_NUM (conflict_allocno)))
+		continue;
+
 	      ira_assert (cover_class
 			  == ALLOCNO_COVER_CLASS (conflict_allocno));
 	      if (allocno_coalesced_p)
 		{
+		  conflict_obj = ALLOCNO_OBJECT (conflict_allocno,
+						 OBJECT_SUBWORD (conflict_obj));
 		  if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
-				    ALLOCNO_NUM (conflict_allocno)))
+				    OBJECT_CONFLICT_ID (conflict_obj)))
 		    continue;
 		  bitmap_set_bit (processed_coalesced_allocno_bitmap,
-				  ALLOCNO_NUM (conflict_allocno));
+				  OBJECT_CONFLICT_ID (conflict_obj));
 		}
-	      if (ALLOCNO_IN_GRAPH_P (conflict_allocno)
-		  && ! ALLOCNO_ASSIGNED_P (conflict_allocno))
+
+	      if (!ALLOCNO_IN_GRAPH_P (conflict_allocno)
+		  || ALLOCNO_ASSIGNED_P (conflict_allocno))
+		continue;
+
+	      left_conflicts_size = ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_allocno);
+	      conflict_size
+		= (ira_reg_class_nregs
+		   [cover_class][ALLOCNO_MODE (conflict_allocno)]);
+	      ira_assert (left_conflicts_size >= size);
+	      if (left_conflicts_size + conflict_size
+		  <= ALLOCNO_AVAILABLE_REGS_NUM (conflict_allocno))
+		{
+		  ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_allocno) -= size;
+		  continue;
+		}
+	      left_conflicts_size -= size;
+	      if (uncolorable_allocnos_splay_tree[cover_class] != NULL
+		  && !ALLOCNO_SPLAY_REMOVED_P (conflict_allocno)
+		  && USE_SPLAY_P (cover_class))
 		{
-		  left_conflicts_size
-		    = ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_allocno);
-		  conflict_size
-		    = (ira_reg_class_nregs
-		       [cover_class][ALLOCNO_MODE (conflict_allocno)]);
 		  ira_assert
-		    (ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_allocno) >= size);
-		  if (left_conflicts_size + conflict_size
-		      <= ALLOCNO_AVAILABLE_REGS_NUM (conflict_allocno))
-		    {
-		      ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_allocno) -= size;
-		      continue;
-		    }
-		  left_conflicts_size
-		    = ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_allocno) - size;
-		  if (uncolorable_allocnos_splay_tree[cover_class] != NULL
-		      && !ALLOCNO_SPLAY_REMOVED_P (conflict_allocno)
-		      && USE_SPLAY_P (cover_class))
-		    {
-		      ira_assert
-		      (splay_tree_lookup
-		       (uncolorable_allocnos_splay_tree[cover_class],
-			(splay_tree_key) conflict_allocno) != NULL);
-		      splay_tree_remove
-			(uncolorable_allocnos_splay_tree[cover_class],
-			 (splay_tree_key) conflict_allocno);
-		      ALLOCNO_SPLAY_REMOVED_P (conflict_allocno) = true;
-		      VEC_safe_push (ira_allocno_t, heap,
-				     removed_splay_allocno_vec,
-				     conflict_allocno);
-		    }
-		  ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_allocno)
-		    = left_conflicts_size;
-		  if (left_conflicts_size + conflict_size
-		      <= ALLOCNO_AVAILABLE_REGS_NUM (conflict_allocno))
-		    {
-		      delete_allocno_from_bucket
-			(conflict_allocno, &uncolorable_allocno_bucket);
-		      add_allocno_to_ordered_bucket
-			(conflict_allocno, &colorable_allocno_bucket);
-		    }
+		    (splay_tree_lookup
+		     (uncolorable_allocnos_splay_tree[cover_class],
+		      (splay_tree_key) conflict_allocno) != NULL);
+		  splay_tree_remove
+		    (uncolorable_allocnos_splay_tree[cover_class],
+		     (splay_tree_key) conflict_allocno);
+		  ALLOCNO_SPLAY_REMOVED_P (conflict_allocno) = true;
+		  VEC_safe_push (ira_allocno_t, heap,
+				 removed_splay_allocno_vec,
+				 conflict_allocno);
+		}
+	      ALLOCNO_LEFT_CONFLICTS_SIZE (conflict_allocno)
+		= left_conflicts_size;
+	      if (left_conflicts_size + conflict_size
+		  <= ALLOCNO_AVAILABLE_REGS_NUM (conflict_allocno))
+		{
+		  delete_allocno_from_bucket
+		    (conflict_allocno, &uncolorable_allocno_bucket);
+		  add_allocno_to_ordered_bucket
+		    (conflict_allocno, &colorable_allocno_bucket);
 		}
 	    }
 	}
@@ -1369,6 +1437,28 @@  pop_allocnos_from_stack (void)
     }
 }
 
+/* Loop over all coalesced allocnos of ALLOCNO and their subobjects, collecting
+   total hard register conflicts in PSET (which the caller must initialize).  */
+static void
+all_conflicting_hard_regs_coalesced (ira_allocno_t allocno, HARD_REG_SET *pset)
+{
+  ira_allocno_t a;
+
+  for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
+       a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
+    {
+      int i;
+      int n = ALLOCNO_NUM_OBJECTS (a);
+      for (i = 0; i < n; i++)
+	{
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  IOR_HARD_REG_SET (*pset, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+	}
+      if (a == allocno)
+	break;
+    }
+}
+
 /* Set up number of available hard registers for ALLOCNO.  */
 static void
 setup_allocno_available_regs_num (ira_allocno_t allocno)
@@ -1376,7 +1466,6 @@  setup_allocno_available_regs_num (ira_al
   int i, n, hard_regs_num, hard_regno;
   enum machine_mode mode;
   enum reg_class cover_class;
-  ira_allocno_t a;
   HARD_REG_SET temp_set;
 
   cover_class = ALLOCNO_COVER_CLASS (allocno);
@@ -1386,14 +1475,8 @@  setup_allocno_available_regs_num (ira_al
   CLEAR_HARD_REG_SET (temp_set);
   ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (allocno) == allocno);
   hard_regs_num = ira_class_hard_regs_num[cover_class];
-  for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
-       a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
-    {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      IOR_HARD_REG_SET (temp_set, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
-      if (a == allocno)
-	break;
-    }
+  all_conflicting_hard_regs_coalesced (allocno, &temp_set);
+
   mode = ALLOCNO_MODE (allocno);
   for (n = 0, i = hard_regs_num - 1; i >= 0; i--)
     {
@@ -1422,16 +1505,11 @@  setup_allocno_left_conflicts_size (ira_a
   hard_regs_num = ira_class_hard_regs_num[cover_class];
   CLEAR_HARD_REG_SET (temp_set);
   ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (allocno) == allocno);
-  for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
-       a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
-    {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      IOR_HARD_REG_SET (temp_set, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
-      if (a == allocno)
-	break;
-    }
+  all_conflicting_hard_regs_coalesced (allocno, &temp_set);
+
   AND_HARD_REG_SET (temp_set, reg_class_contents[cover_class]);
   AND_COMPL_HARD_REG_SET (temp_set, ira_no_alloc_regs);
+
   conflict_allocnos_size = 0;
   if (! hard_reg_set_empty_p (temp_set))
     for (i = 0; i < (int) hard_regs_num; i++)
@@ -1452,19 +1530,23 @@  setup_allocno_left_conflicts_size (ira_a
     for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
 	 a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
       {
-	ira_object_t obj = ALLOCNO_OBJECT (a);
-	ira_object_t conflict_obj;
-	ira_object_conflict_iterator oci;
-
-	FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+	int n = ALLOCNO_NUM_OBJECTS (a);
+	for (i = 0; i < n; i++)
 	  {
-	    ira_allocno_t conflict_allocno = OBJECT_ALLOCNO (conflict_obj);
+	    ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	    ira_object_t conflict_obj;
+	    ira_object_conflict_iterator oci;
 
-	    conflict_allocno
-	      = ALLOCNO_FIRST_COALESCED_ALLOCNO (conflict_allocno);
-	    if (bitmap_bit_p (consideration_allocno_bitmap,
-			      ALLOCNO_NUM (conflict_allocno)))
+	    FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
 	      {
+		ira_allocno_t conflict_allocno = OBJECT_ALLOCNO (conflict_obj);
+
+		conflict_allocno
+		  = ALLOCNO_FIRST_COALESCED_ALLOCNO (conflict_allocno);
+		if (!bitmap_bit_p (consideration_allocno_bitmap,
+				   ALLOCNO_NUM (conflict_allocno)))
+		  continue;
+
 		ira_assert (cover_class
 			    == ALLOCNO_COVER_CLASS (conflict_allocno));
 		if (allocno_coalesced_p)
@@ -1475,6 +1557,7 @@  setup_allocno_left_conflicts_size (ira_a
 		    bitmap_set_bit (processed_coalesced_allocno_bitmap,
 				    ALLOCNO_NUM (conflict_allocno));
 		  }
+
 		if (! ALLOCNO_ASSIGNED_P (conflict_allocno))
 		  conflict_allocnos_size
 		    += (ira_reg_class_nregs
@@ -1484,7 +1567,7 @@  setup_allocno_left_conflicts_size (ira_a
 		  {
 		    int last = (hard_regno
 				+ hard_regno_nregs
-			        [hard_regno][ALLOCNO_MODE (conflict_allocno)]);
+				[hard_regno][ALLOCNO_MODE (conflict_allocno)]);
 
 		    while (hard_regno < last)
 		      {
@@ -1567,9 +1650,9 @@  merge_allocnos (ira_allocno_t a1, ira_al
   ALLOCNO_NEXT_COALESCED_ALLOCNO (last) = next;
 }
 
-/* Return TRUE if there are conflicting allocnos from two sets of
-   coalesced allocnos given correspondingly by allocnos A1 and A2.  If
-   RELOAD_P is TRUE, we use live ranges to find conflicts because
+/* Given two sets of coalesced sets of allocnos, A1 and A2, this
+   function determines if any conflicts exist between the two sets.
+   If RELOAD_P is TRUE, we use live ranges to find conflicts because
    conflicts are represented only for allocnos of the same cover class
    and during the reload pass we coalesce allocnos for sharing stack
    memory slots.  */
@@ -1577,15 +1660,20 @@  static bool
 coalesced_allocno_conflict_p (ira_allocno_t a1, ira_allocno_t a2,
 			      bool reload_p)
 {
-  ira_allocno_t a;
+  ira_allocno_t a, conflict_allocno;
+
+  /* When testing for conflicts, it is sufficient to examine only the
+     subobjects of order 0, due to the canonicalization of conflicts
+     we do in record_object_conflict.  */
 
+  bitmap_clear (processed_coalesced_allocno_bitmap);
   if (allocno_coalesced_p)
     {
-      bitmap_clear (processed_coalesced_allocno_bitmap);
       for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a1);;
 	   a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
 	{
-	  bitmap_set_bit (processed_coalesced_allocno_bitmap, ALLOCNO_NUM (a));
+	  bitmap_set_bit (processed_coalesced_allocno_bitmap,
+			  OBJECT_CONFLICT_ID (ALLOCNO_OBJECT (a, 0)));
 	  if (a == a1)
 	    break;
 	}
@@ -1595,7 +1683,6 @@  coalesced_allocno_conflict_p (ira_allocn
     {
       if (reload_p)
 	{
-	  ira_allocno_t conflict_allocno;
 	  for (conflict_allocno = ALLOCNO_NEXT_COALESCED_ALLOCNO (a1);;
 	       conflict_allocno
 		 = ALLOCNO_NEXT_COALESCED_ALLOCNO (conflict_allocno))
@@ -1609,20 +1696,17 @@  coalesced_allocno_conflict_p (ira_allocn
 	}
       else
 	{
-	  ira_object_t obj = ALLOCNO_OBJECT (a);
+	  ira_object_t a_obj = ALLOCNO_OBJECT (a, 0);
 	  ira_object_t conflict_obj;
 	  ira_object_conflict_iterator oci;
-
-	  FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
-	    {
-	      ira_allocno_t conflict_allocno = OBJECT_ALLOCNO (conflict_obj);
-	      if (conflict_allocno == a1
-		  || (allocno_coalesced_p
-		      && bitmap_bit_p (processed_coalesced_allocno_bitmap,
-				       ALLOCNO_NUM (conflict_allocno))))
-		return true;
-	    }
+	  FOR_EACH_OBJECT_CONFLICT (a_obj, conflict_obj, oci)
+	    if (conflict_obj == ALLOCNO_OBJECT (a1, 0)
+		|| (allocno_coalesced_p
+		    && bitmap_bit_p (processed_coalesced_allocno_bitmap,
+				     OBJECT_CONFLICT_ID (conflict_obj))))
+	      return true;
 	}
+
       if (a == a2)
 	break;
     }
@@ -1759,6 +1843,8 @@  setup_allocno_priorities (ira_allocno_t 
     {
       a = consideration_allocnos[i];
       length = ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a);
+      if (ALLOCNO_NUM_OBJECTS (a) > 1)
+	length /= ALLOCNO_NUM_OBJECTS (a);
       if (length <= 0)
 	length = 1;
       allocno_priorities[ALLOCNO_NUM (a)]
@@ -1968,9 +2054,8 @@  color_pass (ira_loop_tree_node_t loop_tr
   EXECUTE_IF_SET_IN_BITMAP (consideration_allocno_bitmap, 0, j, bi)
     {
       a = ira_allocnos[j];
-      if (! ALLOCNO_ASSIGNED_P (a))
-	continue;
-      bitmap_clear_bit (coloring_allocno_bitmap, ALLOCNO_NUM (a));
+      if (ALLOCNO_ASSIGNED_P (a))
+	bitmap_clear_bit (coloring_allocno_bitmap, ALLOCNO_NUM (a));
     }
   /* Color all mentioned allocnos including transparent ones.  */
   color_allocnos ();
@@ -2321,9 +2406,7 @@  ira_reassign_conflict_allocnos (int star
   allocnos_to_color_num = 0;
   FOR_EACH_ALLOCNO (a, ai)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      ira_object_t conflict_obj;
-      ira_object_conflict_iterator oci;
+      int n = ALLOCNO_NUM_OBJECTS (a);
 
       if (! ALLOCNO_ASSIGNED_P (a)
 	  && ! bitmap_bit_p (allocnos_to_color, ALLOCNO_NUM (a)))
@@ -2342,15 +2425,21 @@  ira_reassign_conflict_allocnos (int star
       if (ALLOCNO_REGNO (a) < start_regno
 	  || (cover_class = ALLOCNO_COVER_CLASS (a)) == NO_REGS)
 	continue;
-      FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+      for (i = 0; i < n; i++)
 	{
-	  ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
-	  ira_assert (ira_reg_classes_intersect_p
-		      [cover_class][ALLOCNO_COVER_CLASS (conflict_a)]);
-	  if (bitmap_bit_p (allocnos_to_color, ALLOCNO_NUM (conflict_a)))
-	    continue;
-	  bitmap_set_bit (allocnos_to_color, ALLOCNO_NUM (conflict_a));
-	  sorted_allocnos[allocnos_to_color_num++] = conflict_a;
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  ira_object_t conflict_obj;
+	  ira_object_conflict_iterator oci;
+	  FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+	    {
+	      ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
+	      ira_assert (ira_reg_classes_intersect_p
+			  [cover_class][ALLOCNO_COVER_CLASS (conflict_a)]);
+	      if (bitmap_bit_p (allocnos_to_color, ALLOCNO_NUM (conflict_a)))
+		continue;
+	      bitmap_set_bit (allocnos_to_color, ALLOCNO_NUM (conflict_a));
+	      sorted_allocnos[allocnos_to_color_num++] = conflict_a;
+	    }
 	}
     }
   ira_free_bitmap (allocnos_to_color);
@@ -2538,10 +2627,15 @@  slot_coalesced_allocno_live_ranges_inter
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      if (ira_live_ranges_intersect_p
-	  (slot_coalesced_allocnos_live_ranges[n], OBJECT_LIVE_RANGES (obj)))
-	return true;
+      int i;
+      int nr = ALLOCNO_NUM_OBJECTS (a);
+      for (i = 0; i < nr; i++)
+	{
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  if (ira_live_ranges_intersect_p (slot_coalesced_allocnos_live_ranges[n],
+					   OBJECT_LIVE_RANGES (obj)))
+	    return true;
+	}
       if (a == allocno)
 	break;
     }
@@ -2553,7 +2647,7 @@  slot_coalesced_allocno_live_ranges_inter
 static void
 setup_slot_coalesced_allocno_live_ranges (ira_allocno_t allocno)
 {
-  int n;
+  int i, n;
   ira_allocno_t a;
   live_range_t r;
 
@@ -2561,11 +2655,15 @@  setup_slot_coalesced_allocno_live_ranges
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      r = ira_copy_live_range_list (OBJECT_LIVE_RANGES (obj));
-      slot_coalesced_allocnos_live_ranges[n]
-	= ira_merge_live_ranges
-	  (slot_coalesced_allocnos_live_ranges[n], r);
+      int nr = ALLOCNO_NUM_OBJECTS (a);
+      for (i = 0; i < nr; i++)
+	{
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  r = ira_copy_live_range_list (OBJECT_LIVE_RANGES (obj));
+	  slot_coalesced_allocnos_live_ranges[n]
+	    = ira_merge_live_ranges
+	    (slot_coalesced_allocnos_live_ranges[n], r);
+	}
       if (a == allocno)
 	break;
     }
@@ -2822,13 +2920,19 @@  allocno_reload_assign (ira_allocno_t a, 
   int hard_regno;
   enum reg_class cover_class;
   int regno = ALLOCNO_REGNO (a);
-  HARD_REG_SET saved;
-  ira_object_t obj = ALLOCNO_OBJECT (a);
+  HARD_REG_SET saved[2];
+  int i, n;
 
-  COPY_HARD_REG_SET (saved, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
-  IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), forbidden_regs);
-  if (! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
-    IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), call_used_reg_set);
+  n = ALLOCNO_NUM_OBJECTS (a);
+  for (i = 0; i < n; i++)
+    {
+      ira_object_t obj = ALLOCNO_OBJECT (a, i);
+      COPY_HARD_REG_SET (saved[i], OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), forbidden_regs);
+      if (! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+	IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+			  call_used_reg_set);
+    }
   ALLOCNO_ASSIGNED_P (a) = false;
   cover_class = ALLOCNO_COVER_CLASS (a);
   update_curr_costs (a);
@@ -2867,7 +2971,11 @@  allocno_reload_assign (ira_allocno_t a, 
     }
   else if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
     fprintf (ira_dump_file, "\n");
-  COPY_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), saved);
+  for (i = 0; i < n; i++)
+    {
+      ira_object_t obj = ALLOCNO_OBJECT (a, i);
+      COPY_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), saved[i]);
+    }
   return reg_renumber[regno] >= 0;
 }
 
@@ -2915,25 +3023,31 @@  ira_reassign_pseudos (int *spilled_pseud
 
   for (i = 0, n = num; i < n; i++)
     {
-      ira_object_t obj, conflict_obj;
-      ira_object_conflict_iterator oci;
+      int nr, j;
       int regno = spilled_pseudo_regs[i];
       bitmap_set_bit (temp, regno);
 
       a = ira_regno_allocno_map[regno];
-      obj = ALLOCNO_OBJECT (a);
-      FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+      nr = ALLOCNO_NUM_OBJECTS (a);
+      for (j = 0; j < nr; j++)
 	{
-	  ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
-	  if (ALLOCNO_HARD_REGNO (conflict_a) < 0
-	      && ! ALLOCNO_DONT_REASSIGN_P (conflict_a)
-	      && ! bitmap_bit_p (temp, ALLOCNO_REGNO (conflict_a)))
-	    {
-	      spilled_pseudo_regs[num++] = ALLOCNO_REGNO (conflict_a);
-	      bitmap_set_bit (temp, ALLOCNO_REGNO (conflict_a));
-	      /* ?!? This seems wrong.  */
-	      bitmap_set_bit (consideration_allocno_bitmap,
-			      ALLOCNO_NUM (conflict_a));
+	  ira_object_t conflict_obj;
+	  ira_object_t obj = ALLOCNO_OBJECT (a, j);
+	  ira_object_conflict_iterator oci;
+
+	  FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+	    {
+	      ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
+	      if (ALLOCNO_HARD_REGNO (conflict_a) < 0
+		  && ! ALLOCNO_DONT_REASSIGN_P (conflict_a)
+		  && ! bitmap_bit_p (temp, ALLOCNO_REGNO (conflict_a)))
+		{
+		  spilled_pseudo_regs[num++] = ALLOCNO_REGNO (conflict_a);
+		  bitmap_set_bit (temp, ALLOCNO_REGNO (conflict_a));
+		  /* ?!? This seems wrong.  */
+		  bitmap_set_bit (consideration_allocno_bitmap,
+				  ALLOCNO_NUM (conflict_a));
+		}
 	    }
 	}
     }
@@ -3146,7 +3260,7 @@  calculate_spill_cost (int *regnos, rtx i
       hard_regno = reg_renumber[regno];
       ira_assert (hard_regno >= 0);
       a = ira_regno_allocno_map[regno];
-      length += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a);
+      length += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) / ALLOCNO_NUM_OBJECTS (a);
       cost += ALLOCNO_MEMORY_COST (a) - ALLOCNO_COVER_CLASS_COST (a);
       nregs = hard_regno_nregs[hard_regno][ALLOCNO_MODE (a)];
       for (j = 0; j < nregs; j++)
@@ -3300,13 +3414,20 @@  fast_allocation (void)
 	 allocno_priority_compare_func);
   for (i = 0; i < num; i++)
     {
-      ira_object_t obj;
+      int nr, l;
+
       a = sorted_allocnos[i];
-      obj = ALLOCNO_OBJECT (a);
-      COPY_HARD_REG_SET (conflict_hard_regs, OBJECT_CONFLICT_HARD_REGS (obj));
-      for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
-	for (j =  r->start; j <= r->finish; j++)
-	  IOR_HARD_REG_SET (conflict_hard_regs, used_hard_regs[j]);
+      nr = ALLOCNO_NUM_OBJECTS (a);
+      CLEAR_HARD_REG_SET (conflict_hard_regs);
+      for (l = 0; l < nr; l++)
+	{
+	  ira_object_t obj = ALLOCNO_OBJECT (a, l);
+	  IOR_HARD_REG_SET (conflict_hard_regs,
+			    OBJECT_CONFLICT_HARD_REGS (obj));
+	  for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+	    for (j = r->start; j <= r->finish; j++)
+	      IOR_HARD_REG_SET (conflict_hard_regs, used_hard_regs[j]);
+	}
       cover_class = ALLOCNO_COVER_CLASS (a);
       ALLOCNO_ASSIGNED_P (a) = true;
       ALLOCNO_HARD_REGNO (a) = -1;
@@ -3331,10 +3452,14 @@  fast_allocation (void)
 		  (prohibited_class_mode_regs[cover_class][mode], hard_regno)))
 	    continue;
 	  ALLOCNO_HARD_REGNO (a) = hard_regno;
-	  for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
-	    for (k = r->start; k <= r->finish; k++)
-	      IOR_HARD_REG_SET (used_hard_regs[k],
-				ira_reg_mode_hard_regset[hard_regno][mode]);
+	  for (l = 0; l < nr; l++)
+	    {
+	      ira_object_t obj = ALLOCNO_OBJECT (a, l);
+	      for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+		for (k = r->start; k <= r->finish; k++)
+		  IOR_HARD_REG_SET (used_hard_regs[k],
+				    ira_reg_mode_hard_regset[hard_regno][mode]);
+	    }
 	  break;
 	}
     }
Index: gcc/ira-conflicts.c
===================================================================
--- gcc.orig/ira-conflicts.c
+++ gcc/ira-conflicts.c
@@ -47,11 +47,11 @@  along with GCC; see the file COPYING3.  
    allocno's conflict (can't go in the same hardware register).
 
    Some arrays will be used as conflict bit vector of the
-   corresponding allocnos see function build_allocno_conflicts.  */
+   corresponding allocnos see function build_object_conflicts.  */
 static IRA_INT_TYPE **conflicts;
 
 /* Macro to test a conflict of C1 and C2 in `conflicts'.  */
-#define OBJECTS_CONFLICT_P(C1, C2)				\
+#define OBJECTS_CONFLICT_P(C1, C2)					\
   (OBJECT_MIN (C1) <= OBJECT_CONFLICT_ID (C2)				\
    && OBJECT_CONFLICT_ID (C2) <= OBJECT_MAX (C1)			\
    && TEST_MINMAX_SET_BIT (conflicts[OBJECT_CONFLICT_ID (C1)],		\
@@ -59,6 +59,36 @@  static IRA_INT_TYPE **conflicts;
 			   OBJECT_MIN (C1), OBJECT_MAX (C1)))
 
 
+/* Record a conflict between objects OBJ1 and OBJ2.  If necessary,
+   canonicalize the conflict by recording it for lower-order subobjects
+   of the corresponding allocnos. */
+static void
+record_object_conflict (ira_object_t obj1, ira_object_t obj2)
+{
+  ira_allocno_t a1 = OBJECT_ALLOCNO (obj1);
+  ira_allocno_t a2 = OBJECT_ALLOCNO (obj2);
+  int w1 = OBJECT_SUBWORD (obj1);
+  int w2 = OBJECT_SUBWORD (obj2);
+  int id1, id2;
+
+  /* Canonicalize the conflict.  If two identically-numbered words
+     conflict, always record this as a conflict between words 0.  That
+     is the only information we need, and it is easier to test for if
+     it is collected in each allocno's lowest-order object.  */
+  if (w1 == w2 && w1 > 0)
+    {
+      obj1 = ALLOCNO_OBJECT (a1, 0);
+      obj2 = ALLOCNO_OBJECT (a2, 0);
+    }
+  id1 = OBJECT_CONFLICT_ID (obj1);
+  id2 = OBJECT_CONFLICT_ID (obj2);
+
+  SET_MINMAX_SET_BIT (conflicts[id1], id2, OBJECT_MIN (obj1),
+		      OBJECT_MAX (obj1));
+  SET_MINMAX_SET_BIT (conflicts[id2], id1, OBJECT_MIN (obj2),
+		      OBJECT_MAX (obj2));
+}
+
 /* Build allocno conflict table by processing allocno live ranges.
    Return true if the table was built.  The table is not built if it
    is too big.  */
@@ -73,51 +103,53 @@  build_conflict_bit_table (void)
   ira_allocno_t allocno;
   ira_allocno_iterator ai;
   sparseset objects_live;
+  ira_object_t obj;
+  ira_allocno_object_iterator aoi;
 
   allocated_words_num = 0;
   FOR_EACH_ALLOCNO (allocno, ai)
-    {
-      ira_object_t obj = ALLOCNO_OBJECT (allocno);
-      if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
+    FOR_EACH_ALLOCNO_OBJECT (allocno, obj, aoi)
+      {
+	if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
 	  continue;
-      conflict_bit_vec_words_num
-	= ((OBJECT_MAX (obj) - OBJECT_MIN (obj) + IRA_INT_BITS)
-	   / IRA_INT_BITS);
-      allocated_words_num += conflict_bit_vec_words_num;
-      if ((unsigned long long) allocated_words_num * sizeof (IRA_INT_TYPE)
-	  > (unsigned long long) IRA_MAX_CONFLICT_TABLE_SIZE * 1024 * 1024)
-	{
-	  if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
-	    fprintf
-	      (ira_dump_file,
-	       "+++Conflict table will be too big(>%dMB) -- don't use it\n",
-	       IRA_MAX_CONFLICT_TABLE_SIZE);
-	  return false;
-	}
-    }
+	conflict_bit_vec_words_num
+	  = ((OBJECT_MAX (obj) - OBJECT_MIN (obj) + IRA_INT_BITS)
+	     / IRA_INT_BITS);
+	allocated_words_num += conflict_bit_vec_words_num;
+	if ((unsigned long long) allocated_words_num * sizeof (IRA_INT_TYPE)
+	    > (unsigned long long) IRA_MAX_CONFLICT_TABLE_SIZE * 1024 * 1024)
+	  {
+	    if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
+	      fprintf
+		(ira_dump_file,
+		 "+++Conflict table will be too big(>%dMB) -- don't use it\n",
+		 IRA_MAX_CONFLICT_TABLE_SIZE);
+	    return false;
+	  }
+      }
 
   conflicts = (IRA_INT_TYPE **) ira_allocate (sizeof (IRA_INT_TYPE *)
 					      * ira_objects_num);
   allocated_words_num = 0;
   FOR_EACH_ALLOCNO (allocno, ai)
-    {
-      ira_object_t obj = ALLOCNO_OBJECT (allocno);
-      int id = OBJECT_CONFLICT_ID (obj);
-      if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
-	{
-	  conflicts[id] = NULL;
-	  continue;
-	}
-      conflict_bit_vec_words_num
-	= ((OBJECT_MAX (obj) - OBJECT_MIN (obj) + IRA_INT_BITS)
-	   / IRA_INT_BITS);
-      allocated_words_num += conflict_bit_vec_words_num;
-      conflicts[id]
-	= (IRA_INT_TYPE *) ira_allocate (sizeof (IRA_INT_TYPE)
-					 * conflict_bit_vec_words_num);
-      memset (conflicts[id], 0,
-	      sizeof (IRA_INT_TYPE) * conflict_bit_vec_words_num);
-    }
+    FOR_EACH_ALLOCNO_OBJECT (allocno, obj, aoi)
+      {
+	int id = OBJECT_CONFLICT_ID (obj);
+	if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
+	  {
+	    conflicts[id] = NULL;
+	    continue;
+	  }
+	conflict_bit_vec_words_num
+	  = ((OBJECT_MAX (obj) - OBJECT_MIN (obj) + IRA_INT_BITS)
+	     / IRA_INT_BITS);
+	allocated_words_num += conflict_bit_vec_words_num;
+	conflicts[id]
+	  = (IRA_INT_TYPE *) ira_allocate (sizeof (IRA_INT_TYPE)
+					   * conflict_bit_vec_words_num);
+	memset (conflicts[id], 0,
+		sizeof (IRA_INT_TYPE) * conflict_bit_vec_words_num);
+      }
 
   object_set_words = (ira_objects_num + IRA_INT_BITS - 1) / IRA_INT_BITS;
   if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
@@ -136,33 +168,27 @@  build_conflict_bit_table (void)
 	  ira_allocno_t allocno = OBJECT_ALLOCNO (obj);
 	  int id = OBJECT_CONFLICT_ID (obj);
 
+	  gcc_assert (id < ira_objects_num);
+
 	  cover_class = ALLOCNO_COVER_CLASS (allocno);
 	  sparseset_set_bit (objects_live, id);
 	  EXECUTE_IF_SET_IN_SPARSESET (objects_live, j)
 	    {
-	      ira_object_t live_cr = ira_object_id_map[j];
-	      ira_allocno_t live_a = OBJECT_ALLOCNO (live_cr);
+	      ira_object_t live_obj = ira_object_id_map[j];
+	      ira_allocno_t live_a = OBJECT_ALLOCNO (live_obj);
 	      enum reg_class live_cover_class = ALLOCNO_COVER_CLASS (live_a);
 
 	      if (ira_reg_classes_intersect_p[cover_class][live_cover_class]
 		  /* Don't set up conflict for the allocno with itself.  */
-		  && id != (int) j)
+		  && live_a != allocno)
 		{
-		  SET_MINMAX_SET_BIT (conflicts[id], j,
-				      OBJECT_MIN (obj),
-				      OBJECT_MAX (obj));
-		  SET_MINMAX_SET_BIT (conflicts[j], id,
-				      OBJECT_MIN (live_cr),
-				      OBJECT_MAX (live_cr));
+		  record_object_conflict (obj, live_obj);
 		}
 	    }
 	}
 
       for (r = ira_finish_point_ranges[i]; r != NULL; r = r->finish_next)
-	{
-	  ira_object_t obj = r->object;
-	  sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (obj));
-	}
+	sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (r->object));
     }
   sparseset_free (objects_live);
   return true;
@@ -172,10 +198,13 @@  build_conflict_bit_table (void)
    register due to conflicts.  */
 
 static bool
-allocnos_conflict_p (ira_allocno_t a1, ira_allocno_t a2)
+allocnos_conflict_for_copy_p (ira_allocno_t a1, ira_allocno_t a2)
 {
-  ira_object_t obj1 = ALLOCNO_OBJECT (a1);
-  ira_object_t obj2 = ALLOCNO_OBJECT (a2);
+  /* Due to the fact that we canonicalize conflicts (see
+     record_object_conflict), we only need to test for conflicts of
+     the lowest order words.  */
+  ira_object_t obj1 = ALLOCNO_OBJECT (a1, 0);
+  ira_object_t obj2 = ALLOCNO_OBJECT (a2, 0);
   return OBJECTS_CONFLICT_P (obj1, obj2);
 }
 
@@ -386,7 +415,7 @@  process_regs_for_copy (rtx reg1, rtx reg
     {
       ira_allocno_t a1 = ira_curr_regno_allocno_map[REGNO (reg1)];
       ira_allocno_t a2 = ira_curr_regno_allocno_map[REGNO (reg2)];
-      if (!allocnos_conflict_p (a1, a2) && offset1 == offset2)
+      if (!allocnos_conflict_for_copy_p (a1, a2) && offset1 == offset2)
 	{
 	  cp = ira_add_allocno_copy (a1, a2, freq, constraint_p, insn,
 				     ira_curr_loop_tree_node);
@@ -559,7 +588,7 @@  propagate_copies (void)
       parent_a1 = ira_parent_or_cap_allocno (a1);
       parent_a2 = ira_parent_or_cap_allocno (a2);
       ira_assert (parent_a1 != NULL && parent_a2 != NULL);
-      if (! allocnos_conflict_p (parent_a1, parent_a2))
+      if (! allocnos_conflict_for_copy_p (parent_a1, parent_a2))
 	ira_add_allocno_copy (parent_a1, parent_a2, cp->freq,
 			      cp->constraint_p, cp->insn, cp->loop_tree_node);
     }
@@ -569,23 +598,20 @@  propagate_copies (void)
 static ira_object_t *collected_conflict_objects;
 
 /* Build conflict vectors or bit conflict vectors (whatever is more
-   profitable) for allocno A from the conflict table and propagate the
-   conflicts to upper level allocno.  */
+   profitable) for object OBJ from the conflict table.  */
 static void
-build_allocno_conflicts (ira_allocno_t a)
+build_object_conflicts (ira_object_t obj)
 {
   int i, px, parent_num;
-  int conflict_bit_vec_words_num;
   ira_allocno_t parent_a, another_parent_a;
-  ira_object_t *vec;
-  IRA_INT_TYPE *allocno_conflicts;
-  ira_object_t obj, parent_obj;
+  ira_object_t parent_obj;
+  ira_allocno_t a = OBJECT_ALLOCNO (obj);
+  IRA_INT_TYPE *object_conflicts;
   minmax_set_iterator asi;
 
-  obj = ALLOCNO_OBJECT (a);
-  allocno_conflicts = conflicts[OBJECT_CONFLICT_ID (obj)];
+  object_conflicts = conflicts[OBJECT_CONFLICT_ID (obj)];
   px = 0;
-  FOR_EACH_BIT_IN_MINMAX_SET (allocno_conflicts,
+  FOR_EACH_BIT_IN_MINMAX_SET (object_conflicts,
 			      OBJECT_MIN (obj), OBJECT_MAX (obj), i, asi)
     {
       ira_object_t another_obj = ira_object_id_map[i];
@@ -596,6 +622,7 @@  build_allocno_conflicts (ira_allocno_t a
     }
   if (ira_conflict_vector_profitable_p (obj, px))
     {
+      ira_object_t *vec;
       ira_allocate_conflict_vec (obj, px);
       vec = OBJECT_CONFLICT_VEC (obj);
       memcpy (vec, collected_conflict_objects, sizeof (ira_object_t) * px);
@@ -604,7 +631,8 @@  build_allocno_conflicts (ira_allocno_t a
     }
   else
     {
-      OBJECT_CONFLICT_ARRAY (obj) = allocno_conflicts;
+      int conflict_bit_vec_words_num;
+      OBJECT_CONFLICT_ARRAY (obj) = object_conflicts;
       if (OBJECT_MAX (obj) < OBJECT_MIN (obj))
 	conflict_bit_vec_words_num = 0;
       else
@@ -614,28 +642,35 @@  build_allocno_conflicts (ira_allocno_t a
       OBJECT_CONFLICT_ARRAY_SIZE (obj)
 	= conflict_bit_vec_words_num * sizeof (IRA_INT_TYPE);
     }
+
   parent_a = ira_parent_or_cap_allocno (a);
   if (parent_a == NULL)
     return;
   ira_assert (ALLOCNO_COVER_CLASS (a) == ALLOCNO_COVER_CLASS (parent_a));
-  parent_obj = ALLOCNO_OBJECT (parent_a);
+  ira_assert (ALLOCNO_NUM_OBJECTS (a) == ALLOCNO_NUM_OBJECTS (parent_a));
+  parent_obj = ALLOCNO_OBJECT (parent_a, OBJECT_SUBWORD (obj));
   parent_num = OBJECT_CONFLICT_ID (parent_obj);
-  FOR_EACH_BIT_IN_MINMAX_SET (allocno_conflicts,
+  FOR_EACH_BIT_IN_MINMAX_SET (object_conflicts,
 			      OBJECT_MIN (obj), OBJECT_MAX (obj), i, asi)
     {
       ira_object_t another_obj = ira_object_id_map[i];
       ira_allocno_t another_a = OBJECT_ALLOCNO (another_obj);
+      int another_word = OBJECT_SUBWORD (another_obj);
 
       ira_assert (ira_reg_classes_intersect_p
 		  [ALLOCNO_COVER_CLASS (a)][ALLOCNO_COVER_CLASS (another_a)]);
+
       another_parent_a = ira_parent_or_cap_allocno (another_a);
       if (another_parent_a == NULL)
 	continue;
       ira_assert (ALLOCNO_NUM (another_parent_a) >= 0);
       ira_assert (ALLOCNO_COVER_CLASS (another_a)
 		  == ALLOCNO_COVER_CLASS (another_parent_a));
+      ira_assert (ALLOCNO_NUM_OBJECTS (another_a)
+		  == ALLOCNO_NUM_OBJECTS (another_parent_a));
       SET_MINMAX_SET_BIT (conflicts[parent_num],
-			  OBJECT_CONFLICT_ID (ALLOCNO_OBJECT (another_parent_a)),
+			  OBJECT_CONFLICT_ID (ALLOCNO_OBJECT (another_parent_a,
+						     another_word)),
 			  OBJECT_MIN (parent_obj),
 			  OBJECT_MAX (parent_obj));
     }
@@ -657,9 +692,18 @@  build_conflicts (void)
 	 a != NULL;
 	 a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
       {
-	build_allocno_conflicts (a);
-	for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
-	  build_allocno_conflicts (cap);
+	int j, nregs = ALLOCNO_NUM_OBJECTS (a);
+	for (j = 0; j < nregs; j++)
+	  {
+	    ira_object_t obj = ALLOCNO_OBJECT (a, j);
+	    build_object_conflicts (obj);
+	    for (cap = ALLOCNO_CAP (a); cap != NULL; cap = ALLOCNO_CAP (cap))
+	      {
+		ira_object_t cap_obj = ALLOCNO_OBJECT (cap, j);
+		gcc_assert (ALLOCNO_NUM_OBJECTS (cap) == ALLOCNO_NUM_OBJECTS (a));
+		build_object_conflicts (cap_obj);
+	      }
+	  }
       }
   ira_free (collected_conflict_objects);
 }
@@ -699,9 +743,8 @@  static void
 print_allocno_conflicts (FILE * file, bool reg_p, ira_allocno_t a)
 {
   HARD_REG_SET conflicting_hard_regs;
-  ira_object_t obj, conflict_obj;
-  ira_object_conflict_iterator oci;
   basic_block bb;
+  int n, i;
 
   if (reg_p)
     fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
@@ -716,39 +759,52 @@  print_allocno_conflicts (FILE * file, bo
     }
 
   fputs (" conflicts:", file);
-  obj = ALLOCNO_OBJECT (a);
-  if (OBJECT_CONFLICT_ARRAY (obj) != NULL)
-    FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
-      {
-	ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
-        if (reg_p)
-          fprintf (file, " r%d,", ALLOCNO_REGNO (conflict_a));
-        else
-          {
-	    fprintf (file, " a%d(r%d,", ALLOCNO_NUM (conflict_a),
-		     ALLOCNO_REGNO (conflict_a));
-	    if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
-	      fprintf (file, "b%d)", bb->index);
-	    else
-	      fprintf (file, "l%d)",
-		       ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
-	  }
-      }
+  n = ALLOCNO_NUM_OBJECTS (a);
+  for (i = 0; i < n; i++)
+    {
+      ira_object_t obj = ALLOCNO_OBJECT (a, i);
+      ira_object_t conflict_obj;
+      ira_object_conflict_iterator oci;
+
+      if (OBJECT_CONFLICT_ARRAY (obj) == NULL)
+	continue;
+      if (n > 1)
+	fprintf (file, "\n;;   subobject %d:", i);
+      FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
+	{
+	  ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
+	  if (reg_p)
+	    fprintf (file, " r%d,", ALLOCNO_REGNO (conflict_a));
+	  else
+	    {
+	      fprintf (file, " a%d(r%d", ALLOCNO_NUM (conflict_a),
+		       ALLOCNO_REGNO (conflict_a));
+	      if (ALLOCNO_NUM_OBJECTS (conflict_a) > 1)
+		fprintf (file, ",w%d", OBJECT_SUBWORD (conflict_obj));
+	      if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
+		fprintf (file, ",b%d", bb->index);
+	      else
+		fprintf (file, ",l%d",
+			 ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
+	      putc (')', file);
+	    }
+	}
+      COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
+      AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
+      AND_HARD_REG_SET (conflicting_hard_regs,
+			reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
+      print_hard_reg_set (file, "\n;;     total conflict hard regs:",
+			  conflicting_hard_regs);
+
+      COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_CONFLICT_HARD_REGS (obj));
+      AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
+      AND_HARD_REG_SET (conflicting_hard_regs,
+			reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
+      print_hard_reg_set (file, ";;     conflict hard regs:",
+			  conflicting_hard_regs);
+      putc ('\n', file);
+    }
 
-  COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
-  AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
-  AND_HARD_REG_SET (conflicting_hard_regs,
-		    reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
-  print_hard_reg_set (file, "\n;;     total conflict hard regs:",
-		      conflicting_hard_regs);
-
-  COPY_HARD_REG_SET (conflicting_hard_regs, OBJECT_CONFLICT_HARD_REGS (obj));
-  AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
-  AND_HARD_REG_SET (conflicting_hard_regs,
-		    reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
-  print_hard_reg_set (file, ";;     conflict hard regs:",
-		      conflicting_hard_regs);
-  putc ('\n', file);
 }
 
 /* Print information about allocno or only regno (if REG_P) conflicts
@@ -798,7 +854,7 @@  ira_build_conflicts (void)
 	    propagate_copies ();
 
 	  /* Now we can free memory for the conflict table (see function
-	     build_allocno_conflicts for details).  */
+	     build_object_conflicts for details).  */
 	  FOR_EACH_OBJECT (obj, oi)
 	    {
 	      if (OBJECT_CONFLICT_ARRAY (obj) != conflicts[OBJECT_CONFLICT_ID (obj)])
@@ -818,29 +874,38 @@  ira_build_conflicts (void)
     }
   FOR_EACH_ALLOCNO (a, ai)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      reg_attrs *attrs;
-      tree decl;
-
-      if ((! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
-	  /* For debugging purposes don't put user defined variables in
-	     callee-clobbered registers.  */
-	  || (optimize == 0
-	      && (attrs = REG_ATTRS (regno_reg_rtx [ALLOCNO_REGNO (a)])) != NULL
-	      && (decl = attrs->decl) != NULL
-	      && VAR_OR_FUNCTION_DECL_P (decl)
-	      && ! DECL_ARTIFICIAL (decl)))
+      int i, n = ALLOCNO_NUM_OBJECTS (a);
+      for (i = 0; i < n; i++)
 	{
-	  IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), call_used_reg_set);
-	  IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), call_used_reg_set);
-	}
-      else if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
-	{
-	  IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
-			    no_caller_save_reg_set);
-	  IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), temp_hard_reg_set);
-	  IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), no_caller_save_reg_set);
-	  IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), temp_hard_reg_set);
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  reg_attrs *attrs = REG_ATTRS (regno_reg_rtx [ALLOCNO_REGNO (a)]);
+	  tree decl;
+
+	  if ((! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+	      /* For debugging purposes don't put user defined variables in
+		 callee-clobbered registers.  */
+	      || (optimize == 0
+		  && attrs != NULL
+		  && (decl = attrs->decl) != NULL
+		  && VAR_OR_FUNCTION_DECL_P (decl)
+		  && ! DECL_ARTIFICIAL (decl)))
+	    {
+	      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+				call_used_reg_set);
+	      IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
+				call_used_reg_set);
+	    }
+	  else if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+	    {
+	      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+				no_caller_save_reg_set);
+	      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+				temp_hard_reg_set);
+	      IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
+				no_caller_save_reg_set);
+	      IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
+				temp_hard_reg_set);
+	    }
 	}
     }
   if (optimize && ira_conflicts_p
Index: gcc/ira-emit.c
===================================================================
--- gcc.orig/ira-emit.c
+++ gcc/ira-emit.c
@@ -715,8 +715,8 @@  modify_move_list (move_t list)
 		&& ALLOCNO_HARD_REGNO
 		   (hard_regno_last_set[hard_regno + i]->to) >= 0)
 	      {
+		int n, j;
 		ira_allocno_t new_allocno;
-		ira_object_t new_obj;
 
 		set_move = hard_regno_last_set[hard_regno + i];
 		/* It does not matter what loop_tree_node (of TO or
@@ -729,19 +729,25 @@  modify_move_list (move_t list)
 		ALLOCNO_MODE (new_allocno) = ALLOCNO_MODE (set_move->to);
 		ira_set_allocno_cover_class
 		  (new_allocno, ALLOCNO_COVER_CLASS (set_move->to));
-		ira_create_allocno_object (new_allocno);
+		ira_create_allocno_objects (new_allocno);
 		ALLOCNO_ASSIGNED_P (new_allocno) = true;
 		ALLOCNO_HARD_REGNO (new_allocno) = -1;
 		ALLOCNO_REG (new_allocno)
 		  = create_new_reg (ALLOCNO_REG (set_move->to));
 
-		new_obj = ALLOCNO_OBJECT (new_allocno);
-
 		/* Make it possibly conflicting with all earlier
 		   created allocnos.  Cases where temporary allocnos
 		   created to remove the cycles are quite rare.  */
-		OBJECT_MIN (new_obj) = 0;
-		OBJECT_MAX (new_obj) = ira_objects_num - 1;
+		n = ALLOCNO_NUM_OBJECTS (new_allocno);
+		gcc_assert (n == ALLOCNO_NUM_OBJECTS (set_move->to));
+		for (j = 0; j < n; j++)
+		  {
+		    ira_object_t new_obj = ALLOCNO_OBJECT (new_allocno, j);
+
+		    OBJECT_MIN (new_obj) = 0;
+		    OBJECT_MAX (new_obj) = ira_objects_num - 1;
+		  }
+
 		new_move = create_move (set_move->to, new_allocno);
 		set_move->to = new_allocno;
 		VEC_safe_push (move_t, heap, move_vec, new_move);
@@ -937,21 +943,26 @@  add_range_and_copies_from_move_list (mov
     {
       ira_allocno_t from = move->from;
       ira_allocno_t to = move->to;
-      ira_object_t from_obj = ALLOCNO_OBJECT (from);
-      ira_object_t to_obj = ALLOCNO_OBJECT (to);
-      if (OBJECT_CONFLICT_ARRAY (to_obj) == NULL)
-	{
-	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
-	    fprintf (ira_dump_file, "    Allocate conflicts for a%dr%d\n",
-		     ALLOCNO_NUM (to), REGNO (ALLOCNO_REG (to)));
-	  ira_allocate_object_conflicts (to_obj, n);
-	}
+      int nr, i;
+
       bitmap_clear_bit (live_through, ALLOCNO_REGNO (from));
       bitmap_clear_bit (live_through, ALLOCNO_REGNO (to));
-      IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (from_obj), hard_regs_live);
-      IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (to_obj), hard_regs_live);
-      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (from_obj), hard_regs_live);
-      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (to_obj), hard_regs_live);
+
+      nr = ALLOCNO_NUM_OBJECTS (to);
+      for (i = 0; i < nr; i++)
+	{
+	  ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
+	  if (OBJECT_CONFLICT_ARRAY (to_obj) == NULL)
+	    {
+	      if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+		fprintf (ira_dump_file, "    Allocate conflicts for a%dr%d\n",
+			 ALLOCNO_NUM (to), REGNO (ALLOCNO_REG (to)));
+	      ira_allocate_object_conflicts (to_obj, n);
+	    }
+	}
+      ior_hard_reg_conflicts (from, &hard_regs_live);
+      ior_hard_reg_conflicts (to, &hard_regs_live);
+
       update_costs (from, true, freq);
       update_costs (to, false, freq);
       cp = ira_add_allocno_copy (from, to, freq, false, move->insn, NULL);
@@ -960,58 +971,73 @@  add_range_and_copies_from_move_list (mov
 		 cp->num, ALLOCNO_NUM (cp->first),
 		 REGNO (ALLOCNO_REG (cp->first)), ALLOCNO_NUM (cp->second),
 		 REGNO (ALLOCNO_REG (cp->second)));
-      r = OBJECT_LIVE_RANGES (from_obj);
-      if (r == NULL || r->finish >= 0)
+
+      nr = ALLOCNO_NUM_OBJECTS (from);
+      for (i = 0; i < nr; i++)
 	{
-	  OBJECT_LIVE_RANGES (from_obj)
-	    = ira_create_live_range (from_obj, start, ira_max_point, r);
-	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
-	    fprintf (ira_dump_file,
-		     "    Adding range [%d..%d] to allocno a%dr%d\n",
-		     start, ira_max_point, ALLOCNO_NUM (from),
-		     REGNO (ALLOCNO_REG (from)));
+	  ira_object_t from_obj = ALLOCNO_OBJECT (from, i);
+	  r = OBJECT_LIVE_RANGES (from_obj);
+	  if (r == NULL || r->finish >= 0)
+	    {
+	      ira_add_live_range_to_object (from_obj, start, ira_max_point);
+	      if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+		fprintf (ira_dump_file,
+			 "    Adding range [%d..%d] to allocno a%dr%d\n",
+			 start, ira_max_point, ALLOCNO_NUM (from),
+			 REGNO (ALLOCNO_REG (from)));
+	    }
+	  else
+	    {
+	      r->finish = ira_max_point;
+	      if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+		fprintf (ira_dump_file,
+			 "    Adding range [%d..%d] to allocno a%dr%d\n",
+			 r->start, ira_max_point, ALLOCNO_NUM (from),
+			 REGNO (ALLOCNO_REG (from)));
+	    }
 	}
-      else
+      ira_max_point++;
+      nr = ALLOCNO_NUM_OBJECTS (to);
+      for (i = 0; i < nr; i++)
 	{
-	  r->finish = ira_max_point;
-	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
-	    fprintf (ira_dump_file,
-		     "    Adding range [%d..%d] to allocno a%dr%d\n",
-		     r->start, ira_max_point, ALLOCNO_NUM (from),
-		     REGNO (ALLOCNO_REG (from)));
+	  ira_object_t to_obj = ALLOCNO_OBJECT (to, i);
+	  ira_add_live_range_to_object (to_obj, ira_max_point, -1);
 	}
       ira_max_point++;
-      OBJECT_LIVE_RANGES (to_obj)
-	= ira_create_live_range (to_obj, ira_max_point, -1,
-				 OBJECT_LIVE_RANGES (to_obj));
-      ira_max_point++;
     }
   for (move = list; move != NULL; move = move->next)
     {
-      ira_object_t to_obj = ALLOCNO_OBJECT (move->to);
-      r = OBJECT_LIVE_RANGES (to_obj);
-      if (r->finish < 0)
-	{
-	  r->finish = ira_max_point - 1;
-	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
-	    fprintf (ira_dump_file,
-		     "    Adding range [%d..%d] to allocno a%dr%d\n",
-		     r->start, r->finish, ALLOCNO_NUM (move->to),
-		     REGNO (ALLOCNO_REG (move->to)));
+      int nr, i;
+      nr = ALLOCNO_NUM_OBJECTS (move->to);
+      for (i = 0; i < nr; i++)
+	{
+	  ira_object_t to_obj = ALLOCNO_OBJECT (move->to, i);
+	  r = OBJECT_LIVE_RANGES (to_obj);
+	  if (r->finish < 0)
+	    {
+	      r->finish = ira_max_point - 1;
+	      if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+		fprintf (ira_dump_file,
+			 "    Adding range [%d..%d] to allocno a%dr%d\n",
+			 r->start, r->finish, ALLOCNO_NUM (move->to),
+			 REGNO (ALLOCNO_REG (move->to)));
+	    }
 	}
     }
   EXECUTE_IF_SET_IN_BITMAP (live_through, FIRST_PSEUDO_REGISTER, regno, bi)
     {
       ira_allocno_t to;
-      ira_object_t obj;
+      int nr, i;
+
       a = node->regno_allocno_map[regno];
-      to = ALLOCNO_MEM_OPTIMIZED_DEST (a);
-      if (to != NULL)
+      if ((to = ALLOCNO_MEM_OPTIMIZED_DEST (a)) != NULL)
 	a = to;
-      obj = ALLOCNO_OBJECT (a);
-      OBJECT_LIVE_RANGES (obj)
-	= ira_create_live_range (obj, start, ira_max_point - 1,
-				 OBJECT_LIVE_RANGES (obj));
+      nr = ALLOCNO_NUM_OBJECTS (a);
+      for (i = 0; i < nr; i++)
+	{
+	  ira_object_t obj = ALLOCNO_OBJECT (a, i);
+	  ira_add_live_range_to_object (obj, start, ira_max_point - 1);
+	}
       if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
 	fprintf
 	  (ira_dump_file,
Index: gcc/ira-int.h
===================================================================
--- gcc.orig/ira-int.h
+++ gcc/ira-int.h
@@ -192,7 +192,6 @@  extern ira_loop_tree_node_t ira_loop_nod
 #define IRA_LOOP_NODE(loop) IRA_LOOP_NODE_BY_INDEX ((loop)->num)
 
 
-
 /* The structure describes program points where a given allocno lives.
    To save memory we store allocno conflicts only for the same cover
    class allocnos which is enough to assign hard registers.  To find
@@ -201,7 +200,7 @@  extern ira_loop_tree_node_t ira_loop_nod
    intersected, the allocnos are in conflict.  */
 struct live_range
 {
-  /* Allocno whose live range is described by given structure.  */
+  /* Object whose live range is described by given structure.  */
   ira_object_t object;
   /* Program point range.  */
   int start, finish;
@@ -233,7 +232,7 @@  struct ira_object
   ira_allocno_t allocno;
   /* Vector of accumulated conflicting conflict_redords with NULL end
      marker (if OBJECT_CONFLICT_VEC_P is true) or conflict bit vector
-     otherwise.  Only objects belonging to allocnos with the
+     otherwise.  Only ira_objects belonging to allocnos with the
      same cover class are in the vector or in the bit vector.  */
   void *conflicts_array;
   /* Pointer to structures describing at what program point the
@@ -241,25 +240,27 @@  struct ira_object
      ranges in the list are not intersected and ordered by decreasing
      their program points*.  */
   live_range_t live_ranges;
+  /* The subword within ALLOCNO which is represented by this object.
+     Zero means the lowest-order subword (or the entire allocno in case
+     it is not being tracked in subwords).  */
+  int subword;
   /* Allocated size of the conflicts array.  */
   unsigned int conflicts_array_size;
-  /* A unique number for every instance of this structure which is used
+  /* A unique number for every instance of this structure, which is used
      to represent it in conflict bit vectors.  */
   int id;
   /* Before building conflicts, MIN and MAX are initialized to
      correspondingly minimal and maximal points of the accumulated
-     allocno live ranges.  Afterwards, they hold the minimal and
-     maximal ids of other objects that this one can conflict
-     with.  */
+     live ranges.  Afterwards, they hold the minimal and maximal ids
+     of other ira_objects that this one can conflict with.  */
   int min, max;
   /* Initial and accumulated hard registers conflicting with this
-     conflict record and as a consequences can not be assigned to the
-     allocno.  All non-allocatable hard regs and hard regs of cover
-     classes different from given allocno one are included in the
-     sets.  */
+     object and as a consequences can not be assigned to the allocno.
+     All non-allocatable hard regs and hard regs of cover classes
+     different from given allocno one are included in the sets.  */
   HARD_REG_SET conflict_hard_regs, total_conflict_hard_regs;
   /* Number of accumulated conflicts in the vector of conflicting
-     conflict records.  */
+     objects.  */
   int num_accumulated_conflicts;
   /* TRUE if conflicts are represented by a vector of pointers to
      ira_object structures.  Otherwise, we use a bit vector indexed
@@ -346,9 +347,13 @@  struct ira_allocno
      list is chained by NEXT_COALESCED_ALLOCNO.  */
   ira_allocno_t first_coalesced_allocno;
   ira_allocno_t next_coalesced_allocno;
-  /* Pointer to a structure describing conflict information about this
-     allocno.  */
-  ira_object_t object;
+  /* The number of objects tracked in the following array.  */
+  int num_objects;
+  /* An array of structures describing conflict information and live
+     ranges for each object associated with the allocno.  There may be
+     more than one such object in cases where the allocno represents a
+     multi-word register.  */
+  ira_object_t objects[2];
   /* Accumulated frequency of calls which given allocno
      intersects.  */
   int call_freq;
@@ -483,9 +488,11 @@  struct ira_allocno
 #define ALLOCNO_TEMP(A) ((A)->temp)
 #define ALLOCNO_FIRST_COALESCED_ALLOCNO(A) ((A)->first_coalesced_allocno)
 #define ALLOCNO_NEXT_COALESCED_ALLOCNO(A) ((A)->next_coalesced_allocno)
-#define ALLOCNO_OBJECT(A) ((A)->object)
+#define ALLOCNO_OBJECT(A,N) ((A)->objects[N])
+#define ALLOCNO_NUM_OBJECTS(A) ((A)->num_objects)
 
 #define OBJECT_ALLOCNO(C) ((C)->allocno)
+#define OBJECT_SUBWORD(C) ((C)->subword)
 #define OBJECT_CONFLICT_ARRAY(C) ((C)->conflicts_array)
 #define OBJECT_CONFLICT_VEC(C) ((ira_object_t *)(C)->conflicts_array)
 #define OBJECT_CONFLICT_BITVEC(C) ((IRA_INT_TYPE *)(C)->conflicts_array)
@@ -497,7 +504,7 @@  struct ira_allocno
 #define OBJECT_MIN(C) ((C)->min)
 #define OBJECT_MAX(C) ((C)->max)
 #define OBJECT_CONFLICT_ID(C) ((C)->id)
-#define OBJECT_LIVE_RANGES(C) ((C)->live_ranges)
+#define OBJECT_LIVE_RANGES(A) ((A)->live_ranges)
 
 /* Map regno -> allocnos with given regno (see comments for
    allocno member `next_regno_allocno').  */
@@ -596,6 +603,7 @@  extern int ira_max_nregs;
 
 /* The type used as elements in the array, and the number of bits in
    this type.  */
+
 #define IRA_INT_BITS HOST_BITS_PER_WIDE_INT
 #define IRA_INT_TYPE HOST_WIDE_INT
 
@@ -693,7 +701,7 @@  minmax_set_iter_init (minmax_set_iterato
   i->word = i->nel == 0 ? 0 : vec[0];
 }
 
-/* Return TRUE if we have more elements to visit, in which case *N is
+/* Return TRUE if we have more allocnos to visit, in which case *N is
    set to the number of the element to be visited.  Otherwise, return
    FALSE.  */
 static inline bool
@@ -735,7 +743,7 @@  minmax_set_iter_next (minmax_set_iterato
   for (minmax_set_iter_init (&(ITER), (VEC), (MIN), (MAX));	\
        minmax_set_iter_cond (&(ITER), &(N));			\
        minmax_set_iter_next (&(ITER)))
-
+
 /* ira.c: */
 
 /* Map: hard regs X modes -> set of hard registers for storing value
@@ -865,12 +873,14 @@  extern void ira_traverse_loop_tree (bool
 extern ira_allocno_t ira_parent_allocno (ira_allocno_t);
 extern ira_allocno_t ira_parent_or_cap_allocno (ira_allocno_t);
 extern ira_allocno_t ira_create_allocno (int, bool, ira_loop_tree_node_t);
-extern void ira_create_allocno_object (ira_allocno_t);
+extern void ira_create_allocno_objects (ira_allocno_t);
 extern void ira_set_allocno_cover_class (ira_allocno_t, enum reg_class);
 extern bool ira_conflict_vector_profitable_p (ira_object_t, int);
 extern void ira_allocate_conflict_vec (ira_object_t, int);
 extern void ira_allocate_object_conflicts (ira_object_t, int);
+extern void ior_hard_reg_conflicts (ira_allocno_t, HARD_REG_SET *);
 extern void ira_print_expanded_allocno (ira_allocno_t);
+extern void ira_add_live_range_to_object (ira_object_t, int, int);
 extern live_range_t ira_create_live_range (ira_object_t, int, int,
 					   live_range_t);
 extern live_range_t ira_copy_live_range_list (live_range_t);
@@ -995,7 +1005,7 @@  ira_allocno_iter_cond (ira_allocno_itera
 
 /* The iterator for all objects.  */
 typedef struct {
-  /* The number of the current element in IRA_OBJECT_ID_MAP.  */
+  /* The number of the current element in ira_object_id_map.  */
   int n;
 } ira_object_iterator;
 
@@ -1023,13 +1033,44 @@  ira_object_iter_cond (ira_object_iterato
   return false;
 }
 
-/* Loop over all objects.  In each iteration, A is set to the next
-   conflict.  ITER is an instance of ira_object_iterator used to iterate
+/* Loop over all objects.  In each iteration, OBJ is set to the next
+   object.  ITER is an instance of ira_object_iterator used to iterate
    the objects.  */
 #define FOR_EACH_OBJECT(OBJ, ITER)			\
   for (ira_object_iter_init (&(ITER));			\
        ira_object_iter_cond (&(ITER), &(OBJ));)
 
+/* The iterator for objects associated with an allocno.  */
+typedef struct {
+  /* The number of the element the allocno's object array.  */
+  int n;
+} ira_allocno_object_iterator;
+
+/* Initialize the iterator I.  */
+static inline void
+ira_allocno_object_iter_init (ira_allocno_object_iterator *i)
+{
+  i->n = 0;
+}
+
+/* Return TRUE if we have more objects to visit in allocno A, in which
+   case *O is set to the object to be visited.  Otherwise, return
+   FALSE.  */
+static inline bool
+ira_allocno_object_iter_cond (ira_allocno_object_iterator *i, ira_allocno_t a,
+			      ira_object_t *o)
+{
+  *o = ALLOCNO_OBJECT (a, i->n);
+  return i->n++ < ALLOCNO_NUM_OBJECTS (a);
+}
+
+/* Loop over all objects associated with allocno A.  In each
+   iteration, O is set to the next object.  ITER is an instance of
+   ira_allocno_object_iterator used to iterate the conflicts.  */
+#define FOR_EACH_ALLOCNO_OBJECT(A, O, ITER)			\
+  for (ira_allocno_object_iter_init (&(ITER));			\
+       ira_allocno_object_iter_cond (&(ITER), (A), &(O));)
+
 
 /* The iterator for copies.  */
 typedef struct {
@@ -1068,9 +1109,10 @@  ira_copy_iter_cond (ira_copy_iterator *i
   for (ira_copy_iter_init (&(ITER));			\
        ira_copy_iter_cond (&(ITER), &(C));)
 
-/* The iterator for allocno conflicts.  */
+/* The iterator for object conflicts.  */
 typedef struct {
-  /* TRUE if the conflicts are represented by vector of objects.  */
+
+  /* TRUE if the conflicts are represented by vector of allocnos.  */
   bool conflict_vec_p;
 
   /* The conflict vector or conflict bit vector.  */
Index: gcc/ira-lives.c
===================================================================
--- gcc.orig/ira-lives.c
+++ gcc/ira-lives.c
@@ -67,8 +67,12 @@  static int curr_point;
    classes.  */
 static int high_pressure_start_point[N_REG_CLASSES];
 
-/* Allocnos live at current point in the scan.  */
-static sparseset allocnos_live;
+/* Objects live at current point in the scan.  */
+static sparseset objects_live;
+
+/* A temporary bitmap used in functions that wish to avoid visiting an allocno
+   multiple times.  */
+static sparseset allocnos_processed;
 
 /* Set of hard regs (except eliminable ones) currently live.  */
 static HARD_REG_SET hard_regs_live;
@@ -81,18 +85,17 @@  static int last_call_num;
 /* The number of last call at which given allocno was saved.  */
 static int *allocno_saved_at_call;
 
-/* Record the birth of hard register REGNO, updating hard_regs_live
-   and hard reg conflict information for living allocno.  */
+/* Record the birth of hard register REGNO, updating hard_regs_live and
+   hard reg conflict information for living allocnos.  */
 static void
 make_hard_regno_born (int regno)
 {
   unsigned int i;
 
   SET_HARD_REG_BIT (hard_regs_live, regno);
-  EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
+  EXECUTE_IF_SET_IN_SPARSESET (objects_live, i)
     {
-      ira_allocno_t allocno = ira_allocnos[i];
-      ira_object_t obj = ALLOCNO_OBJECT (allocno);
+      ira_object_t obj = ira_object_id_map[i];
       SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
       SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno);
     }
@@ -106,29 +109,29 @@  make_hard_regno_dead (int regno)
   CLEAR_HARD_REG_BIT (hard_regs_live, regno);
 }
 
-/* Record the birth of allocno A, starting a new live range for
-   it if necessary, and updating hard reg conflict information.  We also
-   record it in allocnos_live.  */
+/* Record the birth of object OBJ.  Set a bit for it in objects_live,
+   start a new live range for it if necessary and update hard register
+   conflicts.  */
 static void
-make_allocno_born (ira_allocno_t a)
+make_object_born (ira_object_t obj)
 {
-  ira_object_t obj = ALLOCNO_OBJECT (a);
-  live_range_t p = OBJECT_LIVE_RANGES (obj);
+  live_range_t lr = OBJECT_LIVE_RANGES (obj);
 
-  sparseset_set_bit (allocnos_live, ALLOCNO_NUM (a));
+  sparseset_set_bit (objects_live, OBJECT_CONFLICT_ID (obj));
   IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), hard_regs_live);
   IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), hard_regs_live);
 
-  if (p == NULL
-      || (p->finish != curr_point && p->finish + 1 != curr_point))
-    OBJECT_LIVE_RANGES (obj)
-      = ira_create_live_range (obj, curr_point, -1, p);
+  if (lr == NULL
+      || (lr->finish != curr_point && lr->finish + 1 != curr_point))
+    ira_add_live_range_to_object (obj, curr_point, -1);
 }
 
-/* Update ALLOCNO_EXCESS_PRESSURE_POINTS_NUM for allocno A.  */
+/* Update ALLOCNO_EXCESS_PRESSURE_POINTS_NUM for the allocno
+   associated with object OBJ.  */
 static void
-update_allocno_pressure_excess_length (ira_allocno_t a)
+update_allocno_pressure_excess_length (ira_object_t obj)
 {
+  ira_allocno_t a = OBJECT_ALLOCNO (obj);
   int start, i;
   enum reg_class cover_class, cl;
   live_range_t p;
@@ -138,7 +141,6 @@  update_allocno_pressure_excess_length (i
        (cl = ira_reg_class_super_classes[cover_class][i]) != LIM_REG_CLASSES;
        i++)
     {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
       if (high_pressure_start_point[cl] < 0)
 	continue;
       p = OBJECT_LIVE_RANGES (obj);
@@ -149,18 +151,18 @@  update_allocno_pressure_excess_length (i
     }
 }
 
-/* Process the death of allocno A.  This finishes the current live
-   range for it.  */
+/* Process the death of object OBJ, which is associated with allocno
+   A.  This finishes the current live range for it.  */
 static void
-make_allocno_dead (ira_allocno_t a)
+make_object_dead (ira_object_t obj)
 {
-  ira_object_t obj = ALLOCNO_OBJECT (a);
-  live_range_t p = OBJECT_LIVE_RANGES (obj);
+  live_range_t lr;
 
-  ira_assert (p != NULL);
-  p->finish = curr_point;
-  update_allocno_pressure_excess_length (a);
-  sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (a));
+  sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (obj));
+  lr = OBJECT_LIVE_RANGES (obj);
+  ira_assert (lr != NULL);
+  lr->finish = curr_point;
+  update_allocno_pressure_excess_length (obj);
 }
 
 /* The current register pressures for each cover class for the current
@@ -215,8 +217,8 @@  dec_register_pressure (enum reg_class co
     }
   if (set_p)
     {
-      EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, j)
-	update_allocno_pressure_excess_length (ira_allocnos[j]);
+      EXECUTE_IF_SET_IN_SPARSESET (objects_live, j)
+	update_allocno_pressure_excess_length (ira_object_id_map[j]);
       for (i = 0;
 	   (cl = ira_reg_class_super_classes[cover_class][i])
 	     != LIM_REG_CLASSES;
@@ -233,8 +235,8 @@  static void
 mark_pseudo_regno_live (int regno)
 {
   ira_allocno_t a = ira_curr_regno_allocno_map[regno];
+  int i, n, nregs;
   enum reg_class cl;
-  int nregs;
 
   if (a == NULL)
     return;
@@ -242,18 +244,66 @@  mark_pseudo_regno_live (int regno)
   /* Invalidate because it is referenced.  */
   allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
 
-  if (sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
+  n = ALLOCNO_NUM_OBJECTS (a);
+  cl = ALLOCNO_COVER_CLASS (a);
+  nregs = ira_reg_class_nregs[cl][ALLOCNO_MODE (a)];
+  if (n > 1)
+    {
+      /* We track every subobject separately.  */
+      gcc_assert (nregs == n);
+      nregs = 1;
+    }
+
+  for (i = 0; i < n; i++)
+    {
+      ira_object_t obj = ALLOCNO_OBJECT (a, i);
+      if (sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj)))
+	continue;
+
+      inc_register_pressure (cl, nregs);
+      make_object_born (obj);
+    }
+}
+
+/* Like mark_pseudo_regno_live, but try to only mark one subword of
+   the pseudo as live.  SUBWORD indicates which; a value of 0
+   indicates the low part.  */
+static void
+mark_pseudo_regno_subword_live (int regno, int subword)
+{
+  ira_allocno_t a = ira_curr_regno_allocno_map[regno];
+  int n, nregs;
+  enum reg_class cl;
+  ira_object_t obj;
+
+  if (a == NULL)
     return;
 
+  /* Invalidate because it is referenced.  */
+  allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
+
+  n = ALLOCNO_NUM_OBJECTS (a);
+  if (n == 1)
+    {
+      mark_pseudo_regno_live (regno);
+      return;
+    }
+
   cl = ALLOCNO_COVER_CLASS (a);
   nregs = ira_reg_class_nregs[cl][ALLOCNO_MODE (a)];
+  gcc_assert (nregs == n);
+  obj = ALLOCNO_OBJECT (a, subword);
+
+  if (sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj)))
+    return;
+
   inc_register_pressure (cl, nregs);
-  make_allocno_born (a);
+  make_object_born (obj);
 }
 
-/* Mark the hard register REG as live.  Store a 1 in hard_regs_live
-   for this register, record how many consecutive hardware registers
-   it actually needs.  */
+/* Mark the register REG as live.  Store a 1 in hard_regs_live for
+   this register, record how many consecutive hardware registers it
+   actually needs.  */
 static void
 mark_hard_reg_live (rtx reg)
 {
@@ -281,13 +331,22 @@  mark_hard_reg_live (rtx reg)
 static void
 mark_ref_live (df_ref ref)
 {
-  rtx reg;
+  rtx reg = DF_REF_REG (ref);
+  rtx orig_reg = reg;
 
-  reg = DF_REF_REG (ref);
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
+
   if (REGNO (reg) >= FIRST_PSEUDO_REGISTER)
-    mark_pseudo_regno_live (REGNO (reg));
+    {
+      if (df_read_modify_subreg_p (orig_reg))
+	{
+	  mark_pseudo_regno_subword_live (REGNO (reg),
+					  subreg_lowpart_p (orig_reg) ? 0 : 1);
+	}
+      else
+	mark_pseudo_regno_live (REGNO (reg));
+    }
   else
     mark_hard_reg_live (reg);
 }
@@ -298,8 +357,8 @@  static void
 mark_pseudo_regno_dead (int regno)
 {
   ira_allocno_t a = ira_curr_regno_allocno_map[regno];
+  int n, i, nregs;
   enum reg_class cl;
-  int nregs;
 
   if (a == NULL)
     return;
@@ -307,18 +366,61 @@  mark_pseudo_regno_dead (int regno)
   /* Invalidate because it is referenced.  */
   allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
 
-  if (! sparseset_bit_p (allocnos_live, ALLOCNO_NUM (a)))
+  n = ALLOCNO_NUM_OBJECTS (a);
+  cl = ALLOCNO_COVER_CLASS (a);
+  nregs = ira_reg_class_nregs[cl][ALLOCNO_MODE (a)];
+  if (n > 1)
+    {
+      /* We track every subobject separately.  */
+      gcc_assert (nregs == n);
+      nregs = 1;
+    }
+  for (i = 0; i < n; i++)
+    {
+      ira_object_t obj = ALLOCNO_OBJECT (a, i);
+      if (!sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj)))
+	continue;
+
+      dec_register_pressure (cl, nregs);
+      make_object_dead (obj);
+    }
+}
+
+/* Like mark_pseudo_regno_dead, but called when we know that only part of the
+   register dies.  SUBWORD indicates which; a value of 0 indicates the low part.  */
+static void
+mark_pseudo_regno_subword_dead (int regno, int subword)
+{
+  ira_allocno_t a = ira_curr_regno_allocno_map[regno];
+  int n, nregs;
+  enum reg_class cl;
+  ira_object_t obj;
+
+  if (a == NULL)
+    return;
+
+  /* Invalidate because it is referenced.  */
+  allocno_saved_at_call[ALLOCNO_NUM (a)] = 0;
+
+  n = ALLOCNO_NUM_OBJECTS (a);
+  if (n == 1)
+    /* The allocno as a whole doesn't die in this case.  */
     return;
 
   cl = ALLOCNO_COVER_CLASS (a);
   nregs = ira_reg_class_nregs[cl][ALLOCNO_MODE (a)];
-  dec_register_pressure (cl, nregs);
+  gcc_assert (nregs == n);
+
+  obj = ALLOCNO_OBJECT (a, subword);
+  if (!sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj)))
+    return;
 
-  make_allocno_dead (a);
+  dec_register_pressure (cl, 1);
+  make_object_dead (obj);
 }
 
-/* Mark the hard register REG as dead.  Store a 0 in hard_regs_live
-   for the register.  */
+/* Mark the hard register REG as dead.  Store a 0 in hard_regs_live for the
+   register.  */
 static void
 mark_hard_reg_dead (rtx reg)
 {
@@ -346,17 +448,31 @@  mark_hard_reg_dead (rtx reg)
 static void
 mark_ref_dead (df_ref def)
 {
-  rtx reg;
+  rtx reg = DF_REF_REG (def);
+  rtx orig_reg = reg;
 
-  if (DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL)
-      || DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL))
+  if (DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL))
     return;
 
-  reg = DF_REF_REG (def);
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
+
+  if (DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL)
+      && (GET_CODE (orig_reg) != SUBREG
+	  || REGNO (reg) < FIRST_PSEUDO_REGISTER
+	  || !df_read_modify_subreg_p (orig_reg)))
+    return;
+
   if (REGNO (reg) >= FIRST_PSEUDO_REGISTER)
-    mark_pseudo_regno_dead (REGNO (reg));
+    {
+      if (df_read_modify_subreg_p (orig_reg))
+	{
+	  mark_pseudo_regno_subword_dead (REGNO (reg),
+					  subreg_lowpart_p (orig_reg) ? 0 : 1);
+	}
+      else
+	mark_pseudo_regno_dead (REGNO (reg));
+    }
   else
     mark_hard_reg_dead (reg);
 }
@@ -467,7 +583,7 @@  check_and_make_def_conflict (int alt, in
 
       /* If there's any alternative that allows USE to match DEF, do not
 	 record a conflict.  If that causes us to create an invalid
-	 instruction due to the earlyclobber, reload must fix it up.  */	 
+	 instruction due to the earlyclobber, reload must fix it up.  */
       for (alt1 = 0; alt1 < recog_data.n_alternatives; alt1++)
 	if (recog_op_alt[use][alt1].matches == def
 	    || (use < recog_data.n_operands - 1
@@ -835,13 +951,12 @@  process_single_reg_class_operands (bool 
 	    }
 	}
 
-      EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, px)
+      EXECUTE_IF_SET_IN_SPARSESET (objects_live, px)
         {
-	  a = ira_allocnos[px];
+	  ira_object_t obj = ira_object_id_map[px];
+	  a = OBJECT_ALLOCNO (obj);
 	  if (a != operand_a)
 	    {
-	      ira_object_t obj = ALLOCNO_OBJECT (a);
-
 	      /* We could increase costs of A instead of making it
 		 conflicting with the hard register.  But it works worse
 		 because it will be spilled in reload in anyway.  */
@@ -896,7 +1011,7 @@  process_bb_node_lives (ira_loop_tree_nod
 	}
       curr_bb_node = loop_tree_node;
       reg_live_out = DF_LR_OUT (bb);
-      sparseset_clear (allocnos_live);
+      sparseset_clear (objects_live);
       REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out);
       AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
       AND_COMPL_HARD_REG_SET (hard_regs_live, ira_no_alloc_regs);
@@ -1010,21 +1125,14 @@  process_bb_node_lives (ira_loop_tree_nod
 	  if (call_p)
 	    {
 	      last_call_num++;
+	      sparseset_clear (allocnos_processed);
 	      /* The current set of live allocnos are live across the call.  */
-	      EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
+	      EXECUTE_IF_SET_IN_SPARSESET (objects_live, i)
 	        {
-		  ira_allocno_t a = ira_allocnos[i];
+		  ira_object_t obj = ira_object_id_map[i];
+		  ira_allocno_t a = OBJECT_ALLOCNO (obj);
+		  int num = ALLOCNO_NUM (a);
 
-		  if (allocno_saved_at_call[i] != last_call_num)
-		    /* Here we are mimicking caller-save.c behaviour
-		       which does not save hard register at a call if
-		       it was saved on previous call in the same basic
-		       block and the hard register was not mentioned
-		       between the two calls.  */
-		    ALLOCNO_CALL_FREQ (a) += freq;
-		  /* Mark it as saved at the next call.  */
-		  allocno_saved_at_call[i] = last_call_num + 1;
-		  ALLOCNO_CALLS_CROSSED_NUM (a)++;
 		  /* Don't allocate allocnos that cross setjmps or any
 		     call, if this function receives a nonlocal
 		     goto.  */
@@ -1032,18 +1140,31 @@  process_bb_node_lives (ira_loop_tree_nod
 		      || find_reg_note (insn, REG_SETJMP,
 					NULL_RTX) != NULL_RTX)
 		    {
-		      ira_object_t obj = ALLOCNO_OBJECT (a);
 		      SET_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj));
 		      SET_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
 		    }
 		  if (can_throw_internal (insn))
 		    {
-		      ira_object_t obj = ALLOCNO_OBJECT (a);
-		      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
-					call_used_reg_set);
 		      IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj),
 					call_used_reg_set);
+		      IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj),
+					call_used_reg_set);
 		    }
+
+		  if (sparseset_bit_p (allocnos_processed, num))
+		    continue;
+		  sparseset_set_bit (allocnos_processed, num);
+
+		  if (allocno_saved_at_call[num] != last_call_num)
+		    /* Here we are mimicking caller-save.c behaviour
+		       which does not save hard register at a call if
+		       it was saved on previous call in the same basic
+		       block and the hard register was not mentioned
+		       between the two calls.  */
+		    ALLOCNO_CALL_FREQ (a) += freq;
+		  /* Mark it as saved at the next call.  */
+		  allocno_saved_at_call[num] = last_call_num + 1;
+		  ALLOCNO_CALLS_CROSSED_NUM (a)++;
 		}
 	    }
 
@@ -1101,10 +1222,11 @@  process_bb_node_lives (ira_loop_tree_nod
       if (bb_has_abnormal_pred (bb))
 	{
 #ifdef STACK_REGS
-	  EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, px)
+	  EXECUTE_IF_SET_IN_SPARSESET (objects_live, px)
 	    {
-	      ALLOCNO_NO_STACK_REG_P (ira_allocnos[px]) = true;
-	      ALLOCNO_TOTAL_NO_STACK_REG_P (ira_allocnos[px]) = true;
+	      ira_allocno_t a = OBJECT_ALLOCNO (ira_object_id_map[px]);
+	      ALLOCNO_NO_STACK_REG_P (a) = true;
+	      ALLOCNO_TOTAL_NO_STACK_REG_P (a) = true;
 	    }
 	  for (px = FIRST_STACK_REG; px <= LAST_STACK_REG; px++)
 	    make_hard_regno_born (px);
@@ -1118,8 +1240,8 @@  process_bb_node_lives (ira_loop_tree_nod
 		make_hard_regno_born (px);
 	}
 
-      EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
-	make_allocno_dead (ira_allocnos[i]);
+      EXECUTE_IF_SET_IN_SPARSESET (objects_live, i)
+	make_object_dead (ira_object_id_map[i]);
 
       curr_point++;
 
@@ -1143,31 +1265,24 @@  process_bb_node_lives (ira_loop_tree_nod
 static void
 create_start_finish_chains (void)
 {
-  ira_allocno_t a;
-  ira_allocno_iterator ai;
+  ira_object_t obj;
+  ira_object_iterator oi;
   live_range_t r;
 
   ira_start_point_ranges
-    = (live_range_t *) ira_allocate (ira_max_point
-					     * sizeof (live_range_t));
-  memset (ira_start_point_ranges, 0,
-	  ira_max_point * sizeof (live_range_t));
+    = (live_range_t *) ira_allocate (ira_max_point * sizeof (live_range_t));
+  memset (ira_start_point_ranges, 0, ira_max_point * sizeof (live_range_t));
   ira_finish_point_ranges
-    = (live_range_t *) ira_allocate (ira_max_point
-					     * sizeof (live_range_t));
-  memset (ira_finish_point_ranges, 0,
-	  ira_max_point * sizeof (live_range_t));
-  FOR_EACH_ALLOCNO (a, ai)
-    {
-      ira_object_t obj = ALLOCNO_OBJECT (a);
-      for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
-	{
-	  r->start_next = ira_start_point_ranges[r->start];
-	  ira_start_point_ranges[r->start] = r;
-	  r->finish_next = ira_finish_point_ranges[r->finish];
+    = (live_range_t *) ira_allocate (ira_max_point * sizeof (live_range_t));
+  memset (ira_finish_point_ranges, 0, ira_max_point * sizeof (live_range_t));
+  FOR_EACH_OBJECT (obj, oi)
+    for (r = OBJECT_LIVE_RANGES (obj); r != NULL; r = r->next)
+      {
+	r->start_next = ira_start_point_ranges[r->start];
+	ira_start_point_ranges[r->start] = r;
+	r->finish_next = ira_finish_point_ranges[r->finish];
  	  ira_finish_point_ranges[r->finish] = r;
-	}
-    }
+      }
 }
 
 /* Rebuild IRA_START_POINT_RANGES and IRA_FINISH_POINT_RANGES after
@@ -1201,7 +1316,7 @@  remove_some_program_points_and_update_li
       {
 	ira_assert (r->start <= r->finish);
 	bitmap_set_bit (born_or_died, r->start);
-	  bitmap_set_bit (born_or_died, r->finish);
+	bitmap_set_bit (born_or_died, r->finish);
       }
 
   map = (int *) ira_allocate (sizeof (int) * ira_max_point);
@@ -1222,6 +1337,7 @@  remove_some_program_points_and_update_li
 	r->start = map[r->start];
 	r->finish = map[r->finish];
       }
+
   ira_free (map);
 }
 
@@ -1241,13 +1357,27 @@  ira_debug_live_range_list (live_range_t 
   ira_print_live_range_list (stderr, r);
 }
 
+/* Print live ranges of object OBJ to file F.  */
+static void
+print_object_live_ranges (FILE *f, ira_object_t obj)
+{
+  ira_print_live_range_list (f, OBJECT_LIVE_RANGES (obj));
+}
+
 /* Print live ranges of allocno A to file F.  */
 static void
 print_allocno_live_ranges (FILE *f, ira_allocno_t a)
 {
-  ira_object_t obj = ALLOCNO_OBJECT (a);
-  fprintf (f, " a%d(r%d):", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
-  ira_print_live_range_list (f, OBJECT_LIVE_RANGES (obj));
+  int n = ALLOCNO_NUM_OBJECTS (a);
+  int i;
+  for (i = 0; i < n; i++)
+    {
+      fprintf (f, " a%d(r%d", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
+      if (n > 1)
+	fprintf (f, " [%d]", i);
+      fprintf (f, "):");
+      print_object_live_ranges (f, ALLOCNO_OBJECT (a, i));
+    }
 }
 
 /* Print live ranges of allocno A to stderr.  */
@@ -1276,12 +1406,13 @@  ira_debug_live_ranges (void)
 }
 
 /* The main entry function creates live ranges, set up
-   CONFLICT_HARD_REGS and TOTAL_CONFLICT_HARD_REGS for allocnos, and
+   CONFLICT_HARD_REGS and TOTAL_CONFLICT_HARD_REGS for objects, and
    calculate register pressure info.  */
 void
 ira_create_allocno_live_ranges (void)
 {
-  allocnos_live = sparseset_alloc (ira_allocnos_num);
+  objects_live = sparseset_alloc (ira_objects_num);
+  allocnos_processed = sparseset_alloc (ira_allocnos_num);
   curr_point = 0;
   last_call_num = 0;
   allocno_saved_at_call
@@ -1295,7 +1426,8 @@  ira_create_allocno_live_ranges (void)
     print_live_ranges (ira_dump_file);
   /* Clean up.  */
   ira_free (allocno_saved_at_call);
-  sparseset_free (allocnos_live);
+  sparseset_free (objects_live);
+  sparseset_free (allocnos_processed);
 }
 
 /* Compress allocno live ranges.  */