Patchwork [lra] patch implementing proposals from the Richard Sandiford's review of lra.c

login
register
mail settings
Submitter Vladimir Makarov
Date Oct. 17, 2012, 7:53 p.m.
Message ID <507F0CBC.5060805@redhat.com>
Download mbox | patch
Permalink /patch/192131/
State New
Headers show

Comments

Vladimir Makarov - Oct. 17, 2012, 7:53 p.m.
The following patch implements most proposals of Richard's review of 
lra.c and lra-int.h.

The patch was successfully bootstrapped and tested on x86/x86-64.

Committed as rev. 192544.

2012-10-17  Vladimir Makarov  <vmakarov@redhat.com>

     * Makefile.in (LRA_INT_H): Add $(BITMAP_H) $(RECOG_H)
     $(INSN_ATTR_H) insn-codes.h.
     * lra-int.h: Include recog.h and insn-codes.h.
     (struct lra_insn_reg, struct lra_static_insn_data): Improve
     comments.
     (lra_expand_reg_info, lra_secondary_memory): Remove.
     (lra_save_restore, lra_hard_reg_set_intersection_p): Ditto.
     (lra_add_hard_reg_set): Ditto.
     (lra_get_hard_regno_and_offset): Set up offset to zero.
     (struct target_lra_int): New.
     (default_target_lra_int, this_target_lra_int, op_alt_data): Ditto.
     * target-globals.h (this_target_lra_int): New external.
     (target_globals): New member lra_int.
     (restore_target_globals): Restore this_target_lra_int.
     * target-globals.c: Include lra-int.h.
     (default_target_globals): Add &default_target_lra_int.
     * doc/md.texi: Add new interpretation of hint * for LRA.
     * lra-assigns.c (find_hard_regno_for, spill_for): Use
     add_to_hard_reg_set instead of lra_add_hard_reg_set. Use
     overlaps_hard_reg_set_p instead of
     lra_hard_reg_set_intersection_p.
     (setup_live_pseudos_and_spill_after_risky): Ditto.
     (setup_try_hard_regno_pseudos): Use overlaps_hard_reg_set_p
     instead of lra_hard_reg_set_intersection_p.
     * lra-constraints.c (uses_hard_regs_p, contains_reg_p): Ditto.
     (need_for_call_save_p): Ditto.
     (process_alt_operands, inherit_in_ebb): Use add_to_hard_reg_set
     instead of lra_add_hard_reg_set.
     * lra-eliminations.c (spill_pseudos): Use overlaps_hard_reg_set_p
     instead of lra_hard_reg_set_intersection_p.
     * lra-spills.c (assign_spill_hard_regs): Use add_to_hard_reg_set
     instead of lra_add_hard_reg_set.  Use overlaps_hard_reg_set_p
     instead of lra_hard_reg_set_intersection_p.
     * lra.c (lra_create_new_reg_with_unique_value): Improve comments.
     (lra_emit_add): Ditto.
     (this_target_lra_int, default_target_lra_int): New.
     (op_alt_data): Move to struct target_lra_int.
     (collect_non_operand_hard_regs): Simplify code.
     (lra_set_insn_recog_data): Use recog_memoized.
     (lra_update_insn_recog_data): Fix typo in a comment.
     (initialize_lra_reg_info_element): New.
     (init_reg_info, expand_reg_info): Use
     initialize_lra_reg_info_element.
     (add_regs_to_insn_regno_info): Simplify the code.
     (check_rtl): Use AUTOINC.
     (has_nonexceptional_receiver): Simplify code.
     (update_reg_notes): Rename to update_inc_notes.  Ignore REG_DEAD
     and REG_UNUSED.
     (lra_init): Improve comment.

Patch

Index: Makefile.in
===================================================================
--- Makefile.in	(revision 192534)
+++ Makefile.in	(working copy)
@@ -939,7 +939,7 @@  TREE_DATA_REF_H = tree-data-ref.h $(OMEG
 TREE_INLINE_H = tree-inline.h vecir.h
 REAL_H = real.h $(MACHMODE_H)
 IRA_INT_H = ira.h ira-int.h $(CFGLOOP_H) alloc-pool.h
-LRA_INT_H = lra.h lra-int.h
+LRA_INT_H = lra.h $(BITMAP_H) $(RECOG_H) $(INSN_ATTR_H) insn-codes.h lra-int.h
 DBGCNT_H = dbgcnt.h dbgcnt.def
 EBITMAP_H = ebitmap.h sbitmap.h
 LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 192534)
+++ doc/md.texi	(working copy)
@@ -1,5 +1,5 @@ 
 @c Copyright (C) 1988, 1989, 1992, 1993, 1994, 1996, 1998, 1999, 2000, 2001,
-@c 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+@c 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
 @c Free Software Foundation, Inc.
 @c This is part of the GCC manual.
 @c For copying conditions, see the file gcc.texi.
@@ -1606,7 +1606,9 @@  register preferences.
 @item *
 Says that the following character should be ignored when choosing
 register preferences.  @samp{*} has no effect on the meaning of the
-constraint as a constraint, and no effect on reloading.
+constraint as a constraint, and no effect on reloading.  For LRA
+@samp{*} additionally disparages slightly the alternative if the
+following character matches the operand.
 
 @ifset INTERNALS
 Here is an example: the 68000 has an instruction to sign-extend a
Index: lra-assigns.c
===================================================================
--- lra-assigns.c	(revision 192534)
+++ lra-assigns.c	(working copy)
@@ -523,9 +523,9 @@  find_hard_regno_for (int regno, int *cos
       }
     else
       {
-	lra_add_hard_reg_set (live_pseudos_reg_renumber[conflict_regno],
-			      lra_reg_info[conflict_regno].biggest_mode,
-			      &conflict_set);
+	add_to_hard_reg_set (&conflict_set,
+			     lra_reg_info[conflict_regno].biggest_mode,
+			     live_pseudos_reg_renumber[conflict_regno]);
 	if (hard_reg_set_subset_p (reg_class_contents[rclass],
 				   conflict_set))
 	  return -1;
@@ -564,9 +564,8 @@  find_hard_regno_for (int regno, int *cos
 	hard_regno = try_only_hard_regno;
       else
 	hard_regno = ira_class_hard_regs[rclass][i];
-      if (! lra_hard_reg_set_intersection_p (hard_regno,
-					     PSEUDO_REGNO_MODE (regno),
-					     conflict_set)
+      if (! overlaps_hard_reg_set_p (conflict_set,
+				     PSEUDO_REGNO_MODE (regno), hard_regno)
 	  /* We can not use prohibited_class_mode_regs because it is
 	     not defined for all classes.  */
 	  && HARD_REGNO_MODE_OK (hard_regno, PSEUDO_REGNO_MODE (regno))
@@ -741,8 +740,8 @@  setup_try_hard_regno_pseudos (int p, enu
     {
       mode = PSEUDO_REGNO_MODE (spill_regno);
       hard_regno = live_pseudos_reg_renumber[spill_regno];
-      if (lra_hard_reg_set_intersection_p (hard_regno, mode,
-					   reg_class_contents[rclass]))
+      if (overlaps_hard_reg_set_p (reg_class_contents[rclass],
+				   mode, hard_regno))
 	{
 	  for (i = hard_regno_nregs[hard_regno][mode] - 1; i >= 0; i--)
 	    {
@@ -862,8 +861,8 @@  spill_for (int regno, bitmap spilled_pse
 	  if (lra_dump_file != NULL)
 	    fprintf (lra_dump_file, " spill %d(freq=%d)",
 		     spill_regno, lra_reg_info[spill_regno].freq);
-	  lra_add_hard_reg_set (reg_renumber[spill_regno], mode2,
-				&spilled_hard_regs);
+	  add_to_hard_reg_set (&spilled_hard_regs,
+			       mode2, reg_renumber[spill_regno]);
 	  for (r = lra_reg_info[spill_regno].live_ranges;
 	       r != NULL;
 	       r = r->next)
@@ -903,9 +902,9 @@  spill_for (int regno, bitmap spilled_pse
 	      if ((reload_hard_regno
 		   = find_hard_regno_for (reload_regno,
 					  &reload_cost, -1)) >= 0
-		  && (lra_hard_reg_set_intersection_p
-		      (reload_hard_regno, PSEUDO_REGNO_MODE (reload_regno),
-		       spilled_hard_regs)))
+		  && (overlaps_hard_reg_set_p
+		      (spilled_hard_regs,
+		       PSEUDO_REGNO_MODE (reload_regno), reload_hard_regno)))
 		{
 		  if (lra_dump_file != NULL)
 		    fprintf (lra_dump_file, " assign %d(cost=%d)",
@@ -1058,10 +1057,10 @@  setup_live_pseudos_and_spill_after_risky
 	    /* If it is multi-register pseudos they should start on
 	       the same hard register.	*/
 	    || hard_regno != reg_renumber[conflict_regno])
-	  lra_add_hard_reg_set (reg_renumber[conflict_regno],
-				lra_reg_info[conflict_regno].biggest_mode,
-				&conflict_set);
-      if (! lra_hard_reg_set_intersection_p (hard_regno, mode, conflict_set))
+	  add_to_hard_reg_set (&conflict_set,
+			       lra_reg_info[conflict_regno].biggest_mode,
+			       reg_renumber[conflict_regno]);
+      if (! overlaps_hard_reg_set_p (conflict_set, mode, hard_regno))
 	{
 	  update_lives (regno, false);
 	  continue;
@@ -1357,9 +1356,8 @@  lra_assign (void)
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     if (lra_reg_info[i].nrefs != 0 && reg_renumber[i] >= 0
 	&& lra_reg_info[i].call_p
-	&& lra_hard_reg_set_intersection_p (reg_renumber[i],
-					    PSEUDO_REGNO_MODE (i),
-					    call_used_reg_set))
+	&& overlaps_hard_reg_set_p (call_used_reg_set,
+				    PSEUDO_REGNO_MODE (i), reg_renumber[i]))
       gcc_unreachable ();
 #endif
   /* Setup insns to process on the next constraint pass.  */
Index: lra-constraints.c
===================================================================
--- lra-constraints.c	(revision 192534)
+++ lra-constraints.c	(working copy)
@@ -1465,7 +1465,7 @@  uses_hard_regs_p (rtx x, HARD_REG_SET se
       /* The real hard regno of the operand after the allocation.  */
       x_hard_regno = get_final_hard_regno (x_hard_regno, offset);
       return (x_hard_regno >= 0
-	      && lra_hard_reg_set_intersection_p (x_hard_regno, mode, set));
+	      && overlaps_hard_reg_set_p (set, mode, x_hard_regno));
     }
   if (MEM_P (x))
     {
@@ -2223,7 +2223,7 @@  process_alt_operands (int only_alternati
 	    continue;
 	  clobbered_hard_regno = hard_regno[i];
 	  CLEAR_HARD_REG_SET (temp_set);
-	  lra_add_hard_reg_set (clobbered_hard_regno, biggest_mode[i], &temp_set);
+	  add_to_hard_reg_set (&temp_set, biggest_mode[i], clobbered_hard_regno);
 	  for (j = 0; j < n_operands; j++)
 	    if (j == i
 		/* We don't want process insides of match_operator and
@@ -3330,8 +3330,7 @@  contains_reg_p (rtx x, bool hard_reg_p,
 	  if (regno < 0)
 	    return false;
 	  COMPL_HARD_REG_SET (alloc_regs, lra_no_alloc_regs);
-	  return lra_hard_reg_set_intersection_p (regno, GET_MODE (x),
-						  alloc_regs);
+	  return overlaps_hard_reg_set_p (alloc_regs, GET_MODE (x), regno);
 	}
       else
 	{
@@ -3972,9 +3971,9 @@  need_for_call_save_p (int regno)
 {
   lra_assert (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0);
   return (usage_insns[regno].calls_num < calls_num
-	  && (lra_hard_reg_set_intersection_p
-	      (reg_renumber[regno], PSEUDO_REGNO_MODE (regno),
-	       call_used_reg_set)));
+	  && (overlaps_hard_reg_set_p
+	      (call_used_reg_set,
+	       PSEUDO_REGNO_MODE (regno), reg_renumber[regno])));
 }
 
 /* Global registers occuring in the current EBB.  */
@@ -4504,9 +4503,9 @@  inherit_in_ebb (rtx head, rtx tail)
 		  if (j < FIRST_PSEUDO_REGISTER)
 		    SET_HARD_REG_BIT (live_hard_regs, j);
 		  else
-		    lra_add_hard_reg_set (reg_renumber[j],
-					  PSEUDO_REGNO_MODE (j),
-					  &live_hard_regs);
+		    add_to_hard_reg_set (&live_hard_regs,
+					 PSEUDO_REGNO_MODE (j),
+					 reg_renumber[j]);
 		  setup_next_usage_insn (j, last_insn, reloads_num, after_p);
 		}
 	    }
@@ -4605,10 +4604,10 @@  inherit_in_ebb (rtx head, rtx tail)
 		      change_p = true;
 		    CLEAR_HARD_REG_SET (s);
 		    if (dst_regno < FIRST_PSEUDO_REGISTER)
-		      lra_add_hard_reg_set (dst_regno, reg->biggest_mode, &s);
+		      add_to_hard_reg_set (&s, reg->biggest_mode, dst_regno);
 		    else
-		      lra_add_hard_reg_set (reg_renumber[dst_regno],
-					    PSEUDO_REGNO_MODE (dst_regno), &s);
+		      add_to_hard_reg_set (&s, PSEUDO_REGNO_MODE (dst_regno),
+					   reg_renumber[dst_regno]);
 		    AND_COMPL_HARD_REG_SET (live_hard_regs, s);
 		  }
 		/* We should invalidate potential inheritance for the
@@ -4704,12 +4703,12 @@  inherit_in_ebb (rtx head, rtx tail)
 		    if (NONDEBUG_INSN_P (curr_insn))
 		      {
 			if (src_regno < FIRST_PSEUDO_REGISTER)
-			  lra_add_hard_reg_set (src_regno, reg->biggest_mode,
-						&live_hard_regs);
+			  add_to_hard_reg_set (&live_hard_regs,
+					       reg->biggest_mode, src_regno);
 			else
-			  lra_add_hard_reg_set (reg_renumber[src_regno],
-						PSEUDO_REGNO_MODE (src_regno),
-						&live_hard_regs);
+			  add_to_hard_reg_set (&live_hard_regs,
+					       PSEUDO_REGNO_MODE (src_regno),
+					       reg_renumber[src_regno]);
 		      }
 		    add_next_usage_insn (src_regno, use_insn, reloads_num);
 		  }
Index: lra-eliminations.c
===================================================================
--- lra-eliminations.c	(revision 192534)
+++ lra-eliminations.c	(working copy)
@@ -1016,8 +1016,8 @@  spill_pseudos (HARD_REG_SET set)
   bitmap_initialize (&to_process, &reg_obstack);
   for (i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); i++)
     if (lra_reg_info[i].nrefs != 0 && reg_renumber[i] >= 0
-	&& lra_hard_reg_set_intersection_p (reg_renumber[i],
-					    PSEUDO_REGNO_MODE (i), set))
+	&& overlaps_hard_reg_set_p (set,
+				    PSEUDO_REGNO_MODE (i), reg_renumber[i]))
       {
 	if (lra_dump_file != NULL)
 	  fprintf (lra_dump_file, "	 Spilling r%d(%d)\n",
Index: lra-int.h
===================================================================
--- lra-int.h	(revision 192534)
+++ lra-int.h	(working copy)
@@ -21,7 +21,9 @@  along with GCC; see the file COPYING3.	I
 
 #include "lra.h"
 #include "bitmap.h"
+#include "recog.h"
 #include "insn-attr.h"
+#include "insn-codes.h"
 
 #ifdef ENABLE_CHECKING
 #define lra_assert(c) gcc_assert (c)
@@ -161,12 +163,12 @@  struct lra_operand_data
   unsigned int is_address : 1;
 };
 
-/* Info about register in an insn.  */
+/* Info about register occurrence in an insn.  */
 struct lra_insn_reg
 {
   /* The biggest mode through which the insn refers to the register
-     (remember the register can be accessed through a subreg in the
-     insn).  */
+     occurrence (remember the register can be accessed through a
+     subreg in the insn).  */
   ENUM_BITFIELD(machine_mode) biggest_mode : 16;
   /* The type of the corresponding operand which is the register.  */
   ENUM_BITFIELD (op_type) type : 8;
@@ -183,10 +185,11 @@  struct lra_insn_reg
 };
 
 /* Static part (common info for insns with the same ICODE) of LRA
-   internal insn info.	It exists in at most one exemplar for each
-   non-negative ICODE.	Warning: if the structure definition is
-   changed, the initializer for debug_insn_static_data in lra.c should
-   be changed too.  */
+   internal insn info. It exists in at most one exemplar for each
+   non-negative ICODE. There is only one exception. Each asm insn has
+   own structure.  Warning: if the structure definition is changed,
+   the initializer for debug_insn_static_data in lra.c should be
+   changed too.  */
 struct lra_static_insn_data
 {
   /* Static info about each insn operand.  */
@@ -215,9 +218,12 @@  struct lra_static_insn_data
    representation).  */
 struct lra_insn_recog_data
 {
-  int icode; /* The insn code.	*/
-  rtx insn; /* The insn itself.	 */
-  /* Common data for insns with the same ICODE.	 */
+  /* The insn code.  */
+  int icode;
+  /* The insn itself.  */
+  rtx insn;
+  /* Common data for insns with the same ICODE.  Asm insns (their
+     ICODE is negative) do not share such structures.  */
   struct lra_static_insn_data *insn_static_data;
   /* Two arrays of size correspondingly equal to the operand and the
      duplication numbers: */
@@ -235,7 +241,8 @@  struct lra_insn_recog_data
      should try to use any alternative, or the insn is a debug
      insn.  */
   int used_insn_alternative;
-  struct lra_insn_reg *regs;  /* Always NULL for a debug insn.	*/
+  /* The following member value is always NULL for a debug insn.  */
+  struct lra_insn_reg *regs;
 };
 
 typedef struct lra_insn_recog_data *lra_insn_recog_data_t;
@@ -280,7 +287,6 @@  extern void lra_invalidate_insn_regno_in
 extern void lra_update_insn_regno_info (rtx);
 extern struct lra_insn_reg *lra_get_insn_regs (int);
 
-extern void lra_expand_reg_info (void);
 extern void lra_free_copies (void);
 extern void lra_create_copy (int, int, int);
 extern lra_copy_t lra_get_copy (int);
@@ -297,8 +303,6 @@  extern int lra_constraint_new_insn_uid_s
 
 extern bitmap_head lra_special_reload_pseudos;
 
-extern rtx lra_secondary_memory[NUM_MACHINE_MODES];
-
 extern int lra_constraint_offset (int, enum machine_mode);
 
 extern int lra_constraint_iter;
@@ -346,10 +350,6 @@  extern bool lra_assign (void);
 extern int lra_coalesce_iter;
 extern bool lra_coalesce (void);
 
-/* lra-saves.c: */
-
-extern bool lra_save_restore (void);
-
 /* lra-spills.c:  */
 
 extern bool lra_need_for_spills_p (void);
@@ -368,22 +368,6 @@  extern void lra_eliminate_reg_if_possibl
 
 
 
-/* The function returns TRUE if at least one hard register from ones
-   starting with HARD_REGNO and containing value of MODE are in set
-   HARD_REGSET.	 */
-static inline bool
-lra_hard_reg_set_intersection_p (int hard_regno, enum machine_mode mode,
-				 HARD_REG_SET hard_regset)
-{
-  int i;
-
-  lra_assert (hard_regno >= 0);
-  for (i = hard_regno_nregs[hard_regno][mode] - 1; i >= 0; i--)
-    if (TEST_HARD_REG_BIT (hard_regset, hard_regno + i))
-      return true;
-  return false;
-}
-
 /* Return hard regno and offset of (sub-)register X through arguments
    HARD_REGNO and OFFSET.  If it is not (sub-)register or the hard
    register is unknown, then return -1 and 0 correspondingly.  */
@@ -392,7 +376,8 @@  lra_get_hard_regno_and_offset (rtx x, in
 {
   rtx reg;
 
-  *hard_regno = *offset = -1;
+  *hard_regno = -1;
+  *offset = 0;
   reg = x;
   if (GET_CODE (x) == SUBREG)
     reg = SUBREG_REG (x);
@@ -402,23 +387,11 @@  lra_get_hard_regno_and_offset (rtx x, in
     *hard_regno = lra_get_regno_hard_regno (*hard_regno);
   if (*hard_regno < 0)
     return;
-  *offset = 0;
   if (GET_CODE (x) == SUBREG)
     *offset += subreg_regno_offset (*hard_regno, GET_MODE (reg),
 				   SUBREG_BYTE (x),  GET_MODE (x));
 }
 
-/* Add hard registers starting with HARD_REGNO and holding value of
-   MODE to the set S.  */
-static inline void
-lra_add_hard_reg_set (int hard_regno, enum machine_mode mode, HARD_REG_SET *s)
-{
-  int i;
-
-  for (i = hard_regno_nregs[hard_regno][mode] - 1; i >= 0; i--)
-    SET_HARD_REG_BIT (*s, hard_regno + i);
-}
-
 /* Update insn operands which are duplication of NOP operand.  The
    insn is represented by its LRA internal representation ID.  */
 static inline void
@@ -470,3 +443,22 @@  lra_get_insn_recog_data (rtx insn)
     }
   return lra_set_insn_recog_data (insn);
 }
+
+
+
+struct target_lra_int
+{
+  /* Map INSN_UID -> the operand alternative data (NULL if unknown).
+     We assume that this data is valid until register info is changed
+     because classes in the data can be changed.  */
+  struct operand_alternative *x_op_alt_data[LAST_INSN_CODE];
+};
+
+extern struct target_lra_int default_target_lra_int;
+#if SWITCHABLE_TARGET
+extern struct target_lra_int *this_target_lra_int;
+#else
+#define this_target_lra_int (&default_target_lra_int)
+#endif
+
+#define op_alt_data (this_target_lra_int->x_op_alt_data)
Index: lra-spills.c
===================================================================
--- lra-spills.c	(revision 192534)
+++ lra-spills.c	(working copy)
@@ -279,8 +279,8 @@  assign_spill_hard_regs (int *pseudo_regn
 	&& (hard_regno = lra_get_regno_hard_regno (i)) >= 0)
       for (r = lra_reg_info[i].live_ranges; r != NULL; r = r->next)
 	for (p = r->start; p <= r->finish; p++)
-	  lra_add_hard_reg_set (hard_regno, lra_reg_info[i].biggest_mode,
-				&reserved_hard_regs[p]);
+	  add_to_hard_reg_set (&reserved_hard_regs[p],
+			       lra_reg_info[i].biggest_mode, hard_regno);
   bitmap_initialize (&ok_insn_bitmap, &reg_obstack);
   FOR_EACH_BB (bb)
     FOR_BB_INSNS (bb, insn)
@@ -314,8 +314,7 @@  assign_spill_hard_regs (int *pseudo_regn
       for (k = 0; k < spill_class_size; k++)
 	{
 	  hard_regno = ira_class_hard_regs[spill_class][k];
-	  if (! lra_hard_reg_set_intersection_p (hard_regno, mode,
-						 conflict_hard_regs))
+	  if (! overlaps_hard_reg_set_p (conflict_hard_regs, mode, hard_regno))
 	    break;
 	}
       if (k >= spill_class_size)
@@ -329,8 +328,8 @@  assign_spill_hard_regs (int *pseudo_regn
       /* Update reserved_hard_regs.  */
       for (r = lra_reg_info[regno].live_ranges; r != NULL; r = r->next)
 	for (p = r->start; p <= r->finish; p++)
-	  lra_add_hard_reg_set (hard_regno, lra_reg_info[regno].biggest_mode,
-				&reserved_hard_regs[p]);
+	  add_to_hard_reg_set (&reserved_hard_regs[p],
+			       lra_reg_info[regno].biggest_mode, hard_regno);
       spill_hard_reg[regno]
 	= gen_raw_REG (PSEUDO_REGNO_MODE (regno), hard_regno);
       for (nr = 0;
Index: lra.c
===================================================================
--- lra.c	(revision 192534)
+++ lra.c	(working copy)
@@ -138,11 +138,12 @@  expand_reg_data (void)
   ira_expand_reg_equiv ();
 }
 
-/* Create and return a new reg from register FROM corresponding to
-   machine description operand of mode MD_MODE.	 Initialize its
+/* Create and return a new reg of ORIGINAL mode.  If ORIGINAL is NULL
+   or of VOIDmode, use MD_MODE for the new reg.  Initialize its
    register class to RCLASS.  Print message about assigning class
-   RCLASS containing new register name TITLE unless it is NULL.	 The
-   created register will have unique held value.  */
+   RCLASS containing new register name TITLE unless it is NULL.  Use
+   attributes of ORIGINAL if it is a register.  The created register
+   will have unique held value.  */
 rtx
 lra_create_new_reg_with_unique_value (enum machine_mode md_mode, rtx original,
 				      enum reg_class rclass, const char *title)
@@ -247,8 +248,11 @@  lra_delete_dead_insn (rtx insn)
    which are frequent results of elimination.
 
    Emit insns for x = y + z.  X can be used to store intermediate
-   values and should be not in Y and Z when we use x to store an
-   intermediate value.	*/ 
+   values and should be not in Y and Z when we use X to store an
+   intermediate value.  Y + Z should form [base] [+ index[ * scale]] [
+   + disp] where base and index are registers, disp and scale are
+   constants.  Y should contain base if it is present, Z should
+   contain disp if any.  index[*scale] can be part of Y or Z.  */
 void
 lra_emit_add (rtx x, rtx y, rtx z)
 {
@@ -496,16 +500,15 @@  finish_insn_regs (void)
 /* This page contains code dealing LRA insn info (or in other words
    LRA internal insn representation).  */
 
+struct target_lra_int default_target_lra_int;
+#if SWITCHABLE_TARGET
+struct target_lra_int *this_target_lra_int = &default_target_lra_int;
+#endif
 
 /* Map INSN_CODE -> the static insn data.  This info is valid during
    all translation unit.  */
 struct lra_static_insn_data *insn_code_data[LAST_INSN_CODE];
 
-/* Map INSN_UID -> the operand alternative data (NULL if unknown).  We
-   assume that this data is valid until register info is changed
-   because classes in the data can be changed.	*/
-struct operand_alternative *op_alt_data[LAST_INSN_CODE];
-
 /* Debug insns are represented as a special insn with one input
    operand which is RTL expression in var_location.  */
 
@@ -918,10 +921,16 @@  collect_non_operand_hard_regs (rtx *x, l
 	if (! TEST_HARD_REG_BIT (lra_no_alloc_regs, regno))
 	  {
 	    for (curr = list; curr != NULL; curr = curr->next)
-	      if (curr->regno == regno)
-		break;
-	    if (curr == NULL || curr->subreg_p != subreg_p
-		|| curr->biggest_mode != mode)
+	      if (curr->regno == regno && curr->subreg_p == subreg_p
+		  && curr->biggest_mode == mode)
+		{
+		  if (curr->type != type)
+		    curr->type = OP_INOUT;
+		  if (curr->early_clobber != early_clobber)
+		    curr->early_clobber = true;
+		  break;
+		}
+	    if (curr == NULL)
 	      {
 		/* This is a new hard regno or the info can not be
 		   integrated into the found structure.	 */
@@ -936,13 +945,6 @@  collect_non_operand_hard_regs (rtx *x, l
 		list = new_insn_reg (regno, type, mode, subreg_p,
 				     early_clobber, list);
 	      }
-	    else
-	      {
-		if (curr->type != type)
-		  curr->type = OP_INOUT;
-		if (curr->early_clobber != early_clobber)
-		  curr->early_clobber = true;
-	      }
 	  }
       return list;
     }
@@ -1005,7 +1007,7 @@  lra_set_insn_recog_data (rtx insn)
       icode = INSN_CODE (insn);
       if (icode < 0)
 	/* It might be a new simple insn which is not recognized yet.  */
-	INSN_CODE (insn) = icode = recog (PATTERN (insn), insn, 0);
+	INSN_CODE (insn) = icode = recog_memoized (insn);
     }
   data = XNEW (struct lra_insn_recog_data);
   lra_insn_recog_data[uid] = data;
@@ -1231,7 +1233,7 @@  invalidate_insn_recog_data (int uid)
 }
 
 /* Update all the insn info about INSN.	 It is usually called when
-   something in the insn was changed.  Return the udpated info.	 */
+   something in the insn was changed.  Return the updated info.	 */
 lra_insn_recog_data_t
 lra_update_insn_recog_data (rtx insn)
 {
@@ -1379,6 +1381,27 @@  DEF_VEC_ALLOC_P(lra_copy_t, heap);
 /* Vec referring to pseudo copies.  */
 static VEC(lra_copy_t,heap) *copy_vec;
 
+/* Initialize I-th element of lra_reg_info.  */
+static inline void
+initialize_lra_reg_info_element (int i)
+{
+  bitmap_initialize (&lra_reg_info[i].insn_bitmap, &reg_obstack);
+#ifdef STACK_REGS
+  lra_reg_info[i].no_stack_p = false;
+#endif
+  CLEAR_HARD_REG_SET (lra_reg_info[i].conflict_hard_regs);
+  lra_reg_info[i].preferred_hard_regno1 = -1;
+  lra_reg_info[i].preferred_hard_regno2 = -1;
+  lra_reg_info[i].preferred_hard_regno_profit1 = 0;
+  lra_reg_info[i].preferred_hard_regno_profit2 = 0;
+  lra_reg_info[i].live_ranges = NULL;
+  lra_reg_info[i].nrefs = lra_reg_info[i].freq = 0;
+  lra_reg_info[i].last_reload = 0;
+  lra_reg_info[i].restore_regno = -1;
+  lra_reg_info[i].val = get_new_reg_value ();
+  lra_reg_info[i].copies = NULL;
+}
+
 /* Initialize common reg info and copies.  */
 static void
 init_reg_info (void)
@@ -1389,23 +1412,7 @@  init_reg_info (void)
   reg_info_size = max_reg_num () * 3 / 2 + 1;
   lra_reg_info = XNEWVEC (struct lra_reg, reg_info_size);
   for (i = 0; i < reg_info_size; i++)
-    {
-      bitmap_initialize (&lra_reg_info[i].insn_bitmap, &reg_obstack);
-#ifdef STACK_REGS
-      lra_reg_info[i].no_stack_p = false;
-#endif
-      CLEAR_HARD_REG_SET (lra_reg_info[i].conflict_hard_regs);
-      lra_reg_info[i].preferred_hard_regno1 = -1;
-      lra_reg_info[i].preferred_hard_regno2 = -1;
-      lra_reg_info[i].preferred_hard_regno_profit1 = 0;
-      lra_reg_info[i].preferred_hard_regno_profit2 = 0;
-      lra_reg_info[i].live_ranges = NULL;
-      lra_reg_info[i].nrefs = lra_reg_info[i].freq = 0;
-      lra_reg_info[i].last_reload = 0;
-      lra_reg_info[i].restore_regno = -1;
-      lra_reg_info[i].val = get_new_reg_value ();
-      lra_reg_info[i].copies = NULL;
-    }
+    initialize_lra_reg_info_element (i);
   copy_pool
     = create_alloc_pool ("lra copies", sizeof (struct lra_copy), 100);
   copy_vec = VEC_alloc (lra_copy_t, heap, 100);
@@ -1437,23 +1444,7 @@  expand_reg_info (void)
   reg_info_size = max_reg_num () * 3 / 2 + 1;
   lra_reg_info = XRESIZEVEC (struct lra_reg, lra_reg_info, reg_info_size);
   for (i = old; i < reg_info_size; i++)
-    {
-      bitmap_initialize (&lra_reg_info[i].insn_bitmap, &reg_obstack);
-#ifdef STACK_REGS
-      lra_reg_info[i].no_stack_p = false;
-#endif
-      CLEAR_HARD_REG_SET (lra_reg_info[i].conflict_hard_regs);
-      lra_reg_info[i].preferred_hard_regno1 = -1;
-      lra_reg_info[i].preferred_hard_regno2 = -1;
-      lra_reg_info[i].preferred_hard_regno_profit1 = 0;
-      lra_reg_info[i].preferred_hard_regno_profit2 = 0;
-      lra_reg_info[i].live_ranges = NULL;
-      lra_reg_info[i].nrefs = lra_reg_info[i].freq = 0;
-      lra_reg_info[i].last_reload = 0;
-      lra_reg_info[i].restore_regno = -1;
-      lra_reg_info[i].val = get_new_reg_value ();
-      lra_reg_info[i].copies = NULL;
-    }
+    initialize_lra_reg_info_element (i);
 }
 
 /* Free all copies.  */
@@ -1551,28 +1542,32 @@  add_regs_to_insn_regno_info (lra_insn_re
       regno = REGNO (x);
       expand_reg_info ();
       if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, uid))
-	data->regs = new_insn_reg (regno, type, mode, subreg_p, early_clobber,
-				   data->regs);
+	{
+	  data->regs = new_insn_reg (regno, type, mode, subreg_p,
+				     early_clobber, data->regs);
+	  return;
+	}
       else
 	{
 	  for (curr = data->regs; curr != NULL; curr = curr->next)
 	    if (curr->regno == regno)
-	      break;
-	  if (curr->subreg_p != subreg_p || curr->biggest_mode != mode)
-	    /* The info can not be integrated into the found
-	       structure.  */
-	    data->regs = new_insn_reg (regno, type, mode, subreg_p,
-				       early_clobber, data->regs);
-	  else
-	    {
-	      if (curr->type != type)
-		curr->type = OP_INOUT;
-	      if (curr->early_clobber != early_clobber)
-		curr->early_clobber = true;
-	    }
-	  lra_assert (curr != NULL);
+	      {
+		if (curr->subreg_p != subreg_p || curr->biggest_mode != mode)
+		  /* The info can not be integrated into the found
+		     structure.  */
+		  data->regs = new_insn_reg (regno, type, mode, subreg_p,
+					     early_clobber, data->regs);
+		else
+		  {
+		    if (curr->type != type)
+		      curr->type = OP_INOUT;
+		    if (curr->early_clobber != early_clobber)
+		      curr->early_clobber = true;
+		  }
+		return;
+	      }
+	  gcc_unreachable ();
 	}
-      return;
     }
 
   switch (code)
@@ -2039,13 +2034,7 @@  check_rtl (bool final_p)
 		   as legitimate.  Although they are legitimate if
 		   they satisfies the constraints and will be checked
 		   by insn constraints which we ignore here.  */
-		&& GET_CODE (XEXP (op, 0)) != UNSPEC
-		&& GET_CODE (XEXP (op, 0)) != PRE_DEC
-		&& GET_CODE (XEXP (op, 0)) != PRE_INC
-		&& GET_CODE (XEXP (op, 0)) != POST_DEC
-		&& GET_CODE (XEXP (op, 0)) != POST_INC
-		&& GET_CODE (XEXP (op, 0)) != PRE_MODIFY
-		&& GET_CODE (XEXP (op, 0)) != POST_MODIFY)
+		&& GET_RTX_CLASS (GET_CODE (XEXP (op, 0))) == RTX_AUTOINC)
 	      fatal_insn_not_found (insn);
 	  }
       }
@@ -2081,7 +2070,12 @@  has_nonexceptional_receiver (void)
       bb = *--tos;
 
       FOR_EACH_EDGE (e, ei, bb->preds)
-	if (!(e->flags & EDGE_ABNORMAL))
+	if (e->flags & EDGE_ABNORMAL)
+	  {
+	    free (worklist);
+	    return true;
+	  }
+	else
 	  {
 	    basic_block src = e->src;
 
@@ -2093,15 +2087,6 @@  has_nonexceptional_receiver (void)
 	  }
     }
   free (worklist);
-
-  /* Now see if there's a reachable block with an exceptional incoming
-     edge.  */
-  FOR_EACH_BB (bb)
-    if (bb->flags & BB_REACHABLE)
-      FOR_EACH_EDGE (e, ei, bb->preds)
-	if (e->flags & EDGE_ABNORMAL)
-	  return true;
-
   /* No exceptional block reached exit unexceptionally.	 */
   return false;
 }
@@ -2141,7 +2126,7 @@  add_auto_inc_notes (rtx insn, rtx x)
    that can make the notes obsolete.  DF-infrastructure does not deal
    with REG_INC notes -- so we should regenerate them here.  */
 static void
-update_reg_notes (void)
+update_inc_notes (void)
 {
   rtx *pnote;
   basic_block bb;
@@ -2154,9 +2139,7 @@  update_reg_notes (void)
 	pnote = &REG_NOTES (insn);
 	while (*pnote != 0)
 	  {
-	    if (REG_NOTE_KIND (*pnote) == REG_DEAD
-		|| REG_NOTE_KIND (*pnote) == REG_UNUSED
-		|| REG_NOTE_KIND (*pnote) == REG_INC)
+	    if (REG_NOTE_KIND (*pnote) == REG_INC)
 	      *pnote = XEXP (*pnote, 1);
 	    else
 	      pnote = &XEXP (*pnote, 1);
@@ -2361,7 +2344,7 @@  lra (FILE *f)
   regstat_free_n_sets_and_refs ();
   regstat_free_ri ();
   reload_completed = 1;
-  update_reg_notes ();
+  update_inc_notes ();
 
   inserted_p = fixup_abnormal_edges ();
 
@@ -2397,7 +2380,7 @@  lra_init_once (void)
   init_insn_code_data_once ();
 }
 
-/* Initialize LRA data once per function.  */
+/* Initialize LRA whenever register-related information is changed.  */
 void
 lra_init (void)
 {
Index: target-globals.c
===================================================================
--- target-globals.c	(revision 192534)
+++ target-globals.c	(working copy)
@@ -37,6 +37,7 @@  along with GCC; see the file COPYING3.
 #include "libfuncs.h"
 #include "cfgloop.h"
 #include "ira-int.h"
+#include "lra-int.h"
 #include "builtins.h"
 #include "gcse.h"
 #include "bb-reorder.h"
@@ -55,6 +56,7 @@  struct target_globals default_target_glo
   &default_target_cfgloop,
   &default_target_ira,
   &default_target_ira_int,
+  &default_target_lra_int,
   &default_target_builtins,
   &default_target_gcse,
   &default_target_bb_reorder,
Index: target-globals.h
===================================================================
--- target-globals.h	(revision 192534)
+++ target-globals.h	(working copy)
@@ -32,6 +32,7 @@  extern struct target_libfuncs *this_targ
 extern struct target_cfgloop *this_target_cfgloop;
 extern struct target_ira *this_target_ira;
 extern struct target_ira_int *this_target_ira_int;
+extern struct target_lra_int *this_target_lra_int;
 extern struct target_builtins *this_target_builtins;
 extern struct target_gcse *this_target_gcse;
 extern struct target_bb_reorder *this_target_bb_reorder;
@@ -49,6 +50,7 @@  struct GTY(()) target_globals {
   struct target_cfgloop *GTY((skip)) cfgloop;
   struct target_ira *GTY((skip)) ira;
   struct target_ira_int *GTY((skip)) ira_int;
+  struct target_lra_int *GTY((skip)) lra_int;
   struct target_builtins *GTY((skip)) builtins;
   struct target_gcse *GTY((skip)) gcse;
   struct target_bb_reorder *GTY((skip)) bb_reorder;
@@ -73,6 +75,7 @@  restore_target_globals (struct target_gl
   this_target_cfgloop = g->cfgloop;
   this_target_ira = g->ira;
   this_target_ira_int = g->ira_int;
+  this_target_lra_int = g->lra_int;
   this_target_builtins = g->builtins;
   this_target_gcse = g->gcse;
   this_target_bb_reorder = g->bb_reorder;