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


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

RFA: small patch to fix IRA crash of m68k compiler


The patch fixes a crash of m68k compiler found by Andreas Schwab

http://gcc.gnu.org/ml/gcc/2008-09/msg00183.html


2008-09-08 Vladimir Makarov <vmakarov@redhat.com>


   * ira-conflicts.c (process_regs_for_copy): Check that the hard
   regno is not negative.

diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/doc/passes.texi ./doc/passes.texi
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/doc/passes.texi	2008-08-21 21:13:15.000000000 -0400
+++ ./doc/passes.texi	2008-08-22 21:53:40.000000000 -0400
@@ -841,6 +841,28 @@ Global register allocation.  This pass a
 the remaining pseudo registers (those whose life spans are not
 contained in one basic block).  The pass is located in @file{global.c}.
 
+@item
+The optional integrated register allocator (@acronym{IRA}).  It can be
+used instead of the local and global allocator.  It is called
+integrated because coalescing, register live range splitting, and hard
+register preferencing are done on-the-fly during coloring.  It also
+has better integration with the reload pass.  Pseudo-registers spilled
+by the allocator or the reload have still a chance to get
+hard-registers if the reload evicts some pseudo-registers from
+hard-registers.  The allocator helps to choose better pseudos for
+spilling based on their live ranges and to coalesce stack slots
+allocated for the spilled pseudo-registers.  IRA is a regional
+register allocator which is transformed into Chaitin-Briggs allocator
+if there is one region.  By default, IRA chooses regions using
+register pressure but the user can force it to use one region or
+regions corresponding to all loops.
+
+Source files of the allocator are @file{ira.c}, @file{ira-build.c},
+@file{ira-costs.c}, @file{ira-conflicts.c}, @file{ira-color.c},
+@file{ira-emit.c}, @file{ira-lives}, plus header files @file{ira.h}
+and @file{ira-int.h} used for the communication between the allocator
+and the rest of the compiler and between the IRA files.
+
 @cindex reloading
 @item
 Reloading.  This pass renumbers pseudo registers with the hardware
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/doc/tm.texi ./doc/tm.texi
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/doc/tm.texi	2008-08-21 21:13:15.000000000 -0400
+++ ./doc/tm.texi	2008-08-22 21:53:41.000000000 -0400
@@ -2026,6 +2026,18 @@ The macro body should not assume anythin
 On most machines, it is not necessary to define this macro.
 @end defmac
 
+@defmac IRA_HARD_REGNO_ADD_COST_MULTIPLIER (@var{regno})
+In some case register allocation order is not enough for the
+Integrated Register Allocator (@acronym{IRA}) to generate a good code.
+If this macro is defined, it should return a floating point value
+based on @var{regno}.  The cost of using @var{regno} for a pseudo will
+be increased by approximately the pseudo's usage frequency times the
+value returned by this macro.  Not defining this macro is equivalent
+to having it always return @code{0.0}.
+
+On most machines, it is not necessary to define this macro.
+@end defmac
+
 @node Values in Registers
 @subsection How Values Fit in Registers
 
@@ -2814,6 +2826,19 @@ as below:
 @end smallexample
 @end defmac
 
+@defmac IRA_COVER_CLASSES
+The macro defines cover classes for the Integrated Register Allocator
+(@acronym{IRA}).  Cover classes are a set of non-intersecting register
+classes covering all hard registers used for register allocation
+purposes.  Any move between two registers in the same cover class
+should be cheaper than load or store of the registers.  The macro
+value should be the initializer for an array of register class values,
+with @code{LIM_REG_CLASSES} used as the end marker.
+
+You must define this macro in order to use the integrated register
+allocator for the target.
+@end defmac
+
 @node Old Constraints
 @section Obsolete Macros for Defining Constraints
 @cindex defining constraints, obsolete method
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/doc/invoke.texi ./doc/invoke.texi
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/doc/invoke.texi	2008-08-21 21:13:15.000000000 -0400
+++ ./doc/invoke.texi	2008-08-25 11:33:44.000000000 -0400
@@ -274,7 +274,8 @@ Objective-C and Objective-C++ Dialects}.
 @xref{Debugging Options,,Options for Debugging Your Program or GCC}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
 -fdbg-cnt-list -fdbg-cnt=@var{counter-value-list} @gol
--fdump-noaddr -fdump-unnumbered  -fdump-translation-unit@r{[}-@var{n}@r{]} @gol
+-fdump-noaddr -fdump-unnumbered @gol
+-fdump-translation-unit@r{[}-@var{n}@r{]} @gol
 -fdump-class-hierarchy@r{[}-@var{n}@r{]} @gol
 -fdump-ipa-all -fdump-ipa-cgraph -fdump-ipa-inline @gol
 -fdump-statistics @gol
@@ -332,7 +333,10 @@ Objective-C and Objective-C++ Dialects}.
 -finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol
 -finline-small-functions -fipa-cp -fipa-marix-reorg -fipa-pta @gol 
 -fipa-pure-const -fipa-reference -fipa-struct-reorg @gol
--fipa-type-escape -fivopts -fkeep-inline-functions -fkeep-static-consts @gol
+-fipa-type-escape -fira -fira-algorithm=@var{algorithm} @gol
+-fira-coalesce -fno-ira-share-save-slots @gol
+-fno-ira-share-spill-slots -fira-verbose=@var{n} @gol
+-fivopts -fkeep-inline-functions -fkeep-static-consts @gol
 -fmerge-all-constants -fmerge-constants -fmodulo-sched @gol
 -fmodulo-sched-allow-regmoves -fmove-loop-invariants -fmudflap @gol
 -fmudflapir -fmudflapth -fno-branch-count-reg -fno-default-inline @gol
@@ -5672,6 +5681,49 @@ optimization.
 
 Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
 
+@item -fira
+@opindex fira
+Use the integrated register allocator (@acronym{IRA}) for register
+allocation.  It is a default if @acronym{IRA} has been ported for the
+target.
+
+@item -fira-algorithm=@var{algorithm}
+Use specified algorithm for the integrated register allocator.  The
+@var{algorithm} argument should be one of @code{regional}, @code{CB},
+or @code{mixed}.  The second algorithm specifies Chaitin-Briggs
+coloring, the first one specifies regional coloring based on
+Chaitin-Briggs coloring, and the third one which is the default
+specifies a mix of Chaitin-Briggs and regional algorithms where loops
+with small register pressure are ignored.  The first algorithm can
+give best result for machines with small size and irregular register
+set, the second one is faster and generates decent code and the
+smallest size code, and the mixed algorithm usually give the best
+results in most cases and for most architectures.
+
+@item -fira-coalesce
+@opindex fira-coalesce
+Do optimistic register coalescing.  This option might be profitable for
+architectures with big regular register files.
+
+@item -fno-ira-share-save-slots
+@opindex fno-ira-share-save-slots
+Switch off sharing stack slots used for saving call used hard
+registers living through a call.  Each hard register will get a
+separate stack slot and as a result function stack frame will be
+bigger.
+
+@item -fno-ira-share-spill-slots
+@opindex fno-ira-share-spill-slots
+Switch off sharing stack slots allocated for pseudo-registers.  Each
+pseudo-register which did not get a hard register will get a separate
+stack slot and as a result function stack frame will be bigger.
+
+@item -fira-verbose=@var{n}
+@opindex fira-verbose
+Set up how verbose dump file for the integrated register allocator
+will be.  Default value is 5.  If the value is greater or equal to 10,
+the dump file will be stderr as if the value were @var{n} minus 10.
+
 @item -fdelayed-branch
 @opindex fdelayed-branch
 If supported for the target machine, attempt to reorder instructions
@@ -7371,6 +7423,13 @@ processing.  If this limit is hit, SCCVN
 function will not be done and optimizations depending on it will
 be disabled.  The default maximum SCC size is 10000.
 
+@item ira-max-loops-num
+IRA uses a regional register allocation by default.  If a function
+contains loops more than number given by the parameter, non-regional
+register allocator will be used even when option
+@option{-fira-algorithm} is given.  The default value of the parameter
+is 20.
+
 @end table
 @end table
 
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/flags.h ./flags.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/flags.h	2008-08-21 21:16:44.000000000 -0400
+++ ./flags.h	2008-08-22 21:53:45.000000000 -0400
@@ -205,6 +205,19 @@ extern int flag_debug_asm;
 extern int flag_next_runtime;
 
 extern int flag_dump_rtl_in_asm;
+
+/* The algorithm used for the integrated register allocator (IRA).  */
+enum ira_algorithm
+{
+  IRA_ALGORITHM_REGIONAL,
+  IRA_ALGORITHM_CB,
+  IRA_ALGORITHM_MIXED
+};
+
+extern enum ira_algorithm flag_ira_algorithm;
+
+extern unsigned int flag_ira_verbose;
+
 
 /* Other basic status info about current function.  */
 
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/postreload.c ./postreload.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/postreload.c	2008-08-21 21:16:44.000000000 -0400
+++ ./postreload.c	2008-08-22 18:09:58.000000000 -0400
@@ -1565,7 +1565,7 @@ move2add_note_store (rtx dst, const_rtx 
 static bool
 gate_handle_postreload (void)
 {
-  return (optimize > 0);
+  return (optimize > 0 && reload_completed);
 }
 
 
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/reload.c ./reload.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/reload.c	2008-08-21 21:16:44.000000000 -0400
+++ ./reload.c	2008-08-22 21:53:54.000000000 -0400
@@ -1549,8 +1549,10 @@ push_reload (rtx in, rtx out, rtx *inloc
 	    && reg_mentioned_p (XEXP (note, 0), in)
 	    /* Check that a former pseudo is valid; see find_dummy_reload.  */
 	    && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
-		|| (!bitmap_bit_p (DF_LIVE_OUT (ENTRY_BLOCK_PTR),
-				   ORIGINAL_REGNO (XEXP (note, 0)))
+		|| (! bitmap_bit_p (flag_ira
+				    ? DF_LR_OUT (ENTRY_BLOCK_PTR)
+				    : DF_LIVE_OUT (ENTRY_BLOCK_PTR),
+				    ORIGINAL_REGNO (XEXP (note, 0)))
 		    && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1))
 	    && ! refers_to_regno_for_reload_p (regno,
 					       end_hard_regno (rel_mode,
@@ -2027,7 +2029,9 @@ find_dummy_reload (rtx real_in, rtx real
 	     can ignore the conflict).  We must never introduce writes
 	     to such hardregs, as they would clobber the other live
 	     pseudo.  See PR 20973.  */
-          || (!bitmap_bit_p (DF_LIVE_OUT (ENTRY_BLOCK_PTR),
+          || (!bitmap_bit_p (flag_ira
+			     ? DF_LR_OUT (ENTRY_BLOCK_PTR)
+			     : DF_LIVE_OUT (ENTRY_BLOCK_PTR),
 			     ORIGINAL_REGNO (in))
 	      /* Similarly, only do this if we can be sure that the death
 		 note is still valid.  global can assign some hardreg to
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/tree-pass.h ./tree-pass.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/tree-pass.h	2008-08-21 21:16:44.000000000 -0400
+++ ./tree-pass.h	2008-08-22 21:53:54.000000000 -0400
@@ -469,6 +469,7 @@ extern struct rtl_opt_pass pass_sms;
 extern struct rtl_opt_pass pass_sched;
 extern struct rtl_opt_pass pass_local_alloc;
 extern struct rtl_opt_pass pass_global_alloc;
+extern struct rtl_opt_pass pass_ira;
 extern struct rtl_opt_pass pass_postreload;
 extern struct rtl_opt_pass pass_clean_state;
 extern struct rtl_opt_pass pass_branch_prob;
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/reload.h ./reload.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/reload.h	2008-08-21 21:16:44.000000000 -0400
+++ ./reload.h	2008-08-25 11:35:41.000000000 -0400
@@ -1,6 +1,6 @@
-/* Communication between reload.c and reload1.c.
-   Copyright (C) 1987, 1991, 1992, 1993, 1994, 1995, 1997, 1998,
-   1999, 2000, 2001, 2003, 2004, 2007 Free Software Foundation, Inc.
+/* Communication between reload.c, reload1.c and the rest of compiler.
+   Copyright (C) 1987, 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999,
+   2000, 2001, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -209,14 +209,20 @@ struct insn_chain
   int block;
   /* The rtx of the insn.  */
   rtx insn;
-  /* Register life information: record all live hard registers, and all
-     live pseudos that have a hard register.  */
+  /* Register life information: record all live hard registers, and
+     all live pseudos that have a hard register.  This set also
+     contains pseudos spilled by IRA.  */
   regset_head live_throughout;
   regset_head dead_or_set;
-
+  /* Register life information: record all all live pseudos that was
+     saved through given insn.  */
+  regset_head saved;
   /* Copies of the global variables computed by find_reloads.  */
   struct reload *rld;
   int n_reloads;
+  /* It is defined only when IS_CALLER_SAVE_INSN is TRUE.  The value
+     is regno of pseudo saved/restored by the insn.  */
+  int saved_pseudo_regno;
 
   /* Indicates which registers have already been used for spills.  */
   HARD_REG_SET used_spill_regs;
@@ -360,6 +366,9 @@ extern void setup_save_areas (void);
 /* Find the places where hard regs are live across calls and save them.  */
 extern void save_call_clobbered_regs (void);
 
+/* Print global save info.  */
+extern void debug_save_data (void);
+
 /* Replace (subreg (reg)) with the appropriate (reg) for any operands.  */
 extern void cleanup_subreg_operands (rtx);
 
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/cfgloopanal.c ./cfgloopanal.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/cfgloopanal.c	2008-08-21 21:16:44.000000000 -0400
+++ ./cfgloopanal.c	2008-08-22 18:09:59.000000000 -0400
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  
 #include "expr.h"
 #include "output.h"
 #include "graphds.h"
+#include "params.h"
 
 /* Checks whether BB is executed exactly once in each LOOP iteration.  */
 
@@ -372,6 +373,7 @@ init_set_costs (void)
 unsigned
 estimate_reg_pressure_cost (unsigned n_new, unsigned n_old)
 {
+  unsigned cost;
   unsigned regs_needed = n_new + n_old;
 
   /* If we have enough registers, we should use them and not restrict
@@ -379,12 +381,25 @@ estimate_reg_pressure_cost (unsigned n_n
   if (regs_needed + target_res_regs <= target_avail_regs)
     return 0;
 
-  /* If we are close to running out of registers, try to preserve them.  */
   if (regs_needed <= target_avail_regs)
-    return target_reg_cost * n_new;
-  
-  /* If we run out of registers, it is very expensive to add another one.  */
-  return target_spill_cost * n_new;
+    /* If we are close to running out of registers, try to preserve
+       them.  */
+    cost = target_reg_cost * n_new;
+  else
+    /* If we run out of registers, it is very expensive to add another
+       one.  */
+    cost = target_spill_cost * n_new;
+
+  if (optimize && flag_ira && (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
+			       || flag_ira_algorithm == IRA_ALGORITHM_MIXED)
+      && number_of_loops () <= (unsigned) IRA_MAX_LOOPS_NUM)
+    /* IRA regional allocation deals with high register pressure
+       better.  So decrease the cost (to do more accurate the cost
+       calculation for IRA, we need to know how many registers lives
+       through the loop transparently).  */
+    cost /= 2;
+
+  return cost;
 }
 
 /* Sets EDGE_LOOP_EXIT flag for all loop exits.  */
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/params.h ./params.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/params.h	2008-08-21 21:16:44.000000000 -0400
+++ ./params.h	2008-08-22 18:09:59.000000000 -0400
@@ -167,6 +167,8 @@ typedef enum compiler_param
   PARAM_VALUE (PARAM_L2_CACHE_SIZE)
 #define USE_CANONICAL_TYPES \
   PARAM_VALUE (PARAM_USE_CANONICAL_TYPES)
+#define IRA_MAX_LOOPS_NUM \
+  PARAM_VALUE (PARAM_IRA_MAX_LOOPS_NUM)
 #define SWITCH_CONVERSION_BRANCH_RATIO \
   PARAM_VALUE (PARAM_SWITCH_CONVERSION_BRANCH_RATIO)
 #endif /* ! GCC_PARAMS_H */
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/toplev.c ./toplev.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/toplev.c	2008-08-21 21:16:44.000000000 -0400
+++ ./toplev.c	2008-08-22 21:54:04.000000000 -0400
@@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.  
 #include "diagnostic.h"
 #include "params.h"
 #include "reload.h"
+#include "ira.h"
 #include "dwarf2asm.h"
 #include "integrate.h"
 #include "real.h"
@@ -270,6 +271,14 @@ int flag_next_runtime = 0;
 
 enum tls_model flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
 
+/* Set the default algorithm for the integrated register allocator.  */
+
+enum ira_algorithm flag_ira_algorithm = IRA_ALGORITHM_MIXED;
+
+/* Set the default value for -fira-verbose.  */
+
+unsigned int flag_ira_verbose = 5;
+
 /* Nonzero means change certain warnings into errors.
    Usually these are warnings about failure to conform to some standard.  */
 
@@ -2009,6 +2018,7 @@ backend_init (void)
   save_register_info ();
 
   /* Initialize the target-specific back end pieces.  */
+  ira_init_once ();
   backend_init_target ();
 }
 
@@ -2029,9 +2039,10 @@ lang_dependent_init_target (void)
   /* Do the target-specific parts of expr initialization.  */
   init_expr_target ();
 
-  /* Although the actions of init_set_costs are language-independent,
-     it uses optabs, so we cannot call it from backend_init.  */
+  /* Although the actions of these functions are language-independent,
+     they use optabs, so we cannot call them from backend_init.  */
   init_set_costs ();
+  ira_init ();
 
   expand_dummy_function_end ();
 }
@@ -2132,6 +2143,8 @@ finalize (void)
   statistics_fini ();
   finish_optimization_passes ();
 
+  ira_finish_once ();
+
   if (mem_report)
     dump_memory_report (true);
 
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/toplev.h ./toplev.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/toplev.h	2008-08-21 21:16:44.000000000 -0400
+++ ./toplev.h	2008-08-22 21:54:04.000000000 -0400
@@ -139,6 +139,12 @@ extern int flag_unroll_all_loops;
 extern int flag_unswitch_loops;
 extern int flag_cprop_registers;
 extern int time_report;
+extern int flag_ira;
+extern int flag_ira_coalesce;
+extern int flag_ira_move_spills;
+extern int flag_ira_propagate_cost;
+extern int flag_ira_share_save_slots;
+extern int flag_ira_share_spill_slots;
 
 /* Things to do with target switches.  */
 extern void print_version (FILE *, const char *);
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/regs.h ./regs.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/regs.h	2008-08-21 21:16:44.000000000 -0400
+++ ./regs.h	2008-08-22 18:09:59.000000000 -0400
@@ -262,9 +262,27 @@ extern int caller_save_needed;
 #define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) 0
 #endif
 
+/* 1 if the corresponding class does contain register of given
+   mode.  */
+extern char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
+
+typedef unsigned short move_table[N_REG_CLASSES];
+
+/* Maximum cost of moving from a register in one class to a register
+   in another class.  */
+extern move_table *move_cost[MAX_MACHINE_MODE];
+
 /* Specify number of hard registers given machine mode occupy.  */
 extern unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
 
+/* Similar, but here we don't have to move if the first index is a
+   subset of the second so in that case the cost is zero.  */
+extern move_table *may_move_in_cost[MAX_MACHINE_MODE];
+
+/* Similar, but here we don't have to move if the first index is a
+   superset of the second so in that case the cost is zero.  */
+extern move_table *may_move_out_cost[MAX_MACHINE_MODE];
+
 /* Return an exclusive upper bound on the registers occupied by hard
    register (reg:MODE REGNO).  */
 
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/caller-save.c ./caller-save.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/caller-save.c	2008-08-21 21:16:45.000000000 -0400
+++ ./caller-save.c	2008-08-25 11:50:36.000000000 -0400
@@ -1,6 +1,6 @@
 /* Save and restore call-clobbered registers which are live across a call.
    Copyright (C) 1989, 1992, 1994, 1995, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -35,9 +35,15 @@ along with GCC; see the file COPYING3.  
 #include "toplev.h"
 #include "tm_p.h"
 #include "addresses.h"
+#include "output.h"
+#include "cfgloop.h"
 #include "df.h"
 #include "ggc.h"
 
+/* Call used hard registers which can not be saved because there is no
+   insn for this.  */
+HARD_REG_SET no_caller_save_reg_set;
+
 #ifndef MAX_MOVE_MAX
 #define MAX_MOVE_MAX MOVE_MAX
 #endif
@@ -62,6 +68,12 @@ static enum machine_mode
 static rtx
   regno_save_mem[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
 
+/* The number of elements in the subsequent array.  */
+static int save_slots_num;
+
+/* Allocated slots so far.  */
+static rtx save_slots[FIRST_PSEUDO_REGISTER];
+
 /* We will only make a register eligible for caller-save if it can be
    saved in its widest mode with a simple SET insn as long as the memory
    address is valid.  We record the INSN_CODE is those insns here since
@@ -84,18 +96,55 @@ static int n_regs_saved;
 /* Computed by mark_referenced_regs, all regs referenced in a given
    insn.  */
 static HARD_REG_SET referenced_regs;
+/* Computed by mark_referenced_regs, all regs modified in a given insn.  */
+static HARD_REG_SET modified_regs;
+
 
+static int reg_save_code (int, enum machine_mode);
+static int reg_restore_code (int, enum machine_mode);
+
+struct saved_hard_reg;
+static void initiate_saved_hard_regs (void);
+static struct saved_hard_reg *new_saved_hard_reg (int, int);
+static void finish_saved_hard_regs (void);
+static int saved_hard_reg_compare_func (const void *, const void *);
+static void calculate_local_save_info (void);
+static bool restore_trans_fun (int);
+static void restore_con_fun_0 (basic_block);
+static void restore_con_fun_n (edge);
+static void calculate_restore_in_out (void);
+static int calculate_restore_here (void);
+static bool save_trans_fun (int);
+static void save_con_fun_0 (basic_block);
+static void save_con_fun_n (edge);
+static void calculate_save_in_out (void);
+static int calculate_save_here (void);
+static bool free_trans_fun (int);
+static void free_con_fun_0 (basic_block);
+static void free_con_fun_n (edge);
+static void calculate_free_in_out (void);
+
+static void make_global_save_analysis (void);
+static void print_annotated_hard_reg_set (FILE *, HARD_REG_SET,
+					  unsigned char *, int *);
+static void print_hard_reg_set (FILE *, HARD_REG_SET);
+static void print_save_data (FILE *);
+static void set_hard_reg_saved (HARD_REG_SET, unsigned char *,
+				enum machine_mode *, int *, int *);
 
 static void mark_set_regs (rtx, const_rtx, void *);
-static void mark_referenced_regs (rtx);
+static void add_stored_regs (rtx, const_rtx, void *);
+static void mark_referenced_regs (rtx, int);
 static int insert_save (struct insn_chain *, int, int, HARD_REG_SET *,
-			enum machine_mode *);
+			enum machine_mode *, int *);
 static int insert_restore (struct insn_chain *, int, int, int,
-			   enum machine_mode *);
+			   enum machine_mode *, int *);
 static struct insn_chain *insert_one_insn (struct insn_chain *, int, int,
 					   rtx);
 static void add_stored_regs (rtx, const_rtx, void *);
+
 
+
 static GTY(()) rtx savepat;
 static GTY(()) rtx restpat;
 static GTY(()) rtx test_reg;
@@ -180,6 +229,7 @@ init_caller_save (void)
   rtx address;
   int i, j;
 
+  CLEAR_HARD_REG_SET (no_caller_save_reg_set);
   /* First find all the registers that we need to deal with and all
      the modes that they can have.  If we can't find a mode to use,
      we can't have the register live over calls.  */
@@ -217,7 +267,7 @@ init_caller_save (void)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (TEST_HARD_REG_BIT
 	(reg_class_contents
-	 [(int) base_reg_class (regno_save_mode [i][1], PLUS, CONST_INT)], i))
+	 [(int) base_reg_class (regno_save_mode[i][1], PLUS, CONST_INT)], i))
       break;
 
   gcc_assert (i < FIRST_PSEUDO_REGISTER);
@@ -264,10 +314,14 @@ init_caller_save (void)
 	    {
 	      call_fixed_regs[i] = 1;
 	      SET_HARD_REG_BIT (call_fixed_reg_set, i);
+	      if (call_used_regs[i])
+		SET_HARD_REG_BIT (no_caller_save_reg_set, i);
 	    }
 	}
 }
+
 
+
 /* Initialize save areas by showing that we haven't allocated any yet.  */
 
 void
@@ -278,6 +332,100 @@ init_save_areas (void)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     for (j = 1; j <= MOVE_MAX_WORDS; j++)
       regno_save_mem[i][j] = 0;
+  save_slots_num = 0;
+    
+}
+
+/* The structure represents a hard register which should be saved
+   through the call.  It is used when the integrated register
+   allocator (IRA) is used and sharing save slots is on.  */
+struct saved_hard_reg
+{
+  /* Order number starting with 0.  */
+  int num;
+  /* The hard regno.  */
+  int hard_regno;
+  /* Execution frequency of all calls through which given hard
+     register should be saved.  */
+  int call_freq;
+  /* Stack slot reserved to save the hard register through calls.  */
+  rtx slot;
+  /* True if it is first hard register in the chain of hard registers
+     sharing the same stack slot.  */
+  int first_p;
+  /* Order number of the next hard register structure with the same
+     slot in the chain.  -1 represents end of the chain.  */
+  int next;
+};
+
+/* Map: hard register number to the corresponding structure.  */
+static struct saved_hard_reg *hard_reg_map[FIRST_PSEUDO_REGISTER];
+
+/* The number of all structures representing hard registers should be
+   saved, in order words, the number of used elements in the following
+   array.  */
+static int saved_regs_num;
+
+/* Pointers to all the structures.  Index is the order number of the
+   corresponding structure.  */
+static struct saved_hard_reg *all_saved_regs[FIRST_PSEUDO_REGISTER];
+
+/* First called function for work with saved hard registers.  */
+static void
+initiate_saved_hard_regs (void)
+{
+  int i;
+
+  saved_regs_num = 0;
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    hard_reg_map[i] = NULL;
+}
+
+/* Allocate and return new saved hard register with given REGNO and
+   CALL_FREQ.  */
+static struct saved_hard_reg *
+new_saved_hard_reg (int regno, int call_freq)
+{
+  struct saved_hard_reg *saved_reg;
+
+  saved_reg
+    = (struct saved_hard_reg *) xmalloc (sizeof (struct saved_hard_reg));
+  hard_reg_map[regno] = all_saved_regs[saved_regs_num] = saved_reg;
+  saved_reg->num = saved_regs_num++;
+  saved_reg->hard_regno = regno;
+  saved_reg->call_freq = call_freq;
+  saved_reg->first_p = FALSE;
+  saved_reg->next = -1;
+  return saved_reg;
+}
+
+/* Free memory allocated for the saved hard registers.  */
+static void
+finish_saved_hard_regs (void)
+{
+  int i;
+
+  for (i = 0; i < saved_regs_num; i++)
+    free (all_saved_regs[i]);
+}
+
+/* The function is used to sort the saved hard register structures
+   according their frequency.  */
+static int
+saved_hard_reg_compare_func (const void *v1p, const void *v2p)
+{
+  const struct saved_hard_reg *p1 = *(struct saved_hard_reg * const *) v1p;
+  const struct saved_hard_reg *p2 = *(struct saved_hard_reg * const *) v2p;
+  
+  if (flag_omit_frame_pointer)
+    {
+      if (p1->call_freq - p2->call_freq != 0)
+	return p1->call_freq - p2->call_freq;
+    }
+  else if (p2->call_freq - p1->call_freq != 0)
+    return p2->call_freq - p1->call_freq;
+
+  return p1->num - p2->num;
 }
 
 /* Allocate save areas for any hard registers that might need saving.
@@ -286,6 +434,10 @@ init_save_areas (void)
    overestimate slightly (especially if some of these registers are later
    used as spill registers), but it should not be significant.
 
+   For IRA we use priority coloring to decrease stack slots needed for
+   saving hard registers through calls.  We build conflicts for them
+   to do coloring.
+
    Future work:
 
      In the fallback case we should iterate backwards across all possible
@@ -317,65 +469,297 @@ setup_save_areas (void)
 	unsigned int regno = reg_renumber[i];
 	unsigned int endregno
 	  = end_hard_regno (GET_MODE (regno_reg_rtx[i]), regno);
-
 	for (r = regno; r < endregno; r++)
 	  if (call_used_regs[r])
 	    SET_HARD_REG_BIT (hard_regs_used, r);
       }
 
-  /* Now run through all the call-used hard-registers and allocate
-     space for them in the caller-save area.  Try to allocate space
-     in a manner which allows multi-register saves/restores to be done.  */
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    for (j = MOVE_MAX_WORDS; j > 0; j--)
-      {
-	int do_save = 1;
+  if (flag_ira && optimize && flag_ira_share_save_slots)
+    {
+      rtx insn, slot;
+      struct insn_chain *chain, *next;
+      char *saved_reg_conflicts;
+      unsigned int regno;
+      int next_k, freq;
+      struct saved_hard_reg *saved_reg, *saved_reg2, *saved_reg3;
+      int call_saved_regs_num;
+      struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER];
+      HARD_REG_SET hard_regs_to_save, used_regs, this_insn_sets;
+      reg_set_iterator rsi;
+      int best_slot_num;
+      int prev_save_slots_num;
+      rtx prev_save_slots[FIRST_PSEUDO_REGISTER];
+      
+      initiate_saved_hard_regs ();
+      /* Create hard reg saved regs.  */
+      for (chain = reload_insn_chain; chain != 0; chain = next)
+	{
+	  insn = chain->insn;
+	  next = chain->next;
+	  if (GET_CODE (insn) != CALL_INSN
+	      || find_reg_note (insn, REG_NORETURN, NULL))
+	    continue;
+	  freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
+	  REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
+				   &chain->live_throughout);
+	  COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+
+	  /* Record all registers set in this call insn.  These don't
+	     need to be saved.  N.B. the call insn might set a subreg
+	     of a multi-hard-reg pseudo; then the pseudo is considered
+	     live during the call, but the subreg that is set
+	     isn't.  */
+	  CLEAR_HARD_REG_SET (this_insn_sets);
+	  note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
+	  /* Sibcalls are considered to set the return value.  */
+	  if (SIBLING_CALL_P (insn) && crtl->return_rtx)
+	    mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
+
+	  AND_COMPL_HARD_REG_SET (used_regs, call_fixed_reg_set);
+	  AND_COMPL_HARD_REG_SET (used_regs, this_insn_sets);
+	  AND_HARD_REG_SET (hard_regs_to_save, used_regs);
+	  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+	    if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+	      {
+		if (hard_reg_map[regno] != NULL)
+		  hard_reg_map[regno]->call_freq += freq;
+		else
+		  saved_reg = new_saved_hard_reg (regno, freq);
+	      }
+	  /* Look through all live pseudos, mark their hard registers.  */
+	  EXECUTE_IF_SET_IN_REG_SET
+	    (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
+	    {
+	      int r = reg_renumber[regno];
+	      int bound;
+	      
+	      if (r < 0)
+		continue;
+	      
+	      bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+	      for (; r < bound; r++)
+		if (TEST_HARD_REG_BIT (used_regs, r))
+		  {
+		    if (hard_reg_map[r] != NULL)
+		      hard_reg_map[r]->call_freq += freq;
+		    else
+		      saved_reg = new_saved_hard_reg (r, freq);
+		    SET_HARD_REG_BIT (hard_regs_to_save, r);
+		  }
+	    }
+	}
+      /* Find saved hard register conflicts.  */
+      saved_reg_conflicts = (char *) xmalloc (saved_regs_num * saved_regs_num);
+      memset (saved_reg_conflicts, 0, saved_regs_num * saved_regs_num);
+      for (chain = reload_insn_chain; chain != 0; chain = next)
+	{
+	  call_saved_regs_num = 0;
+	  insn = chain->insn;
+	  next = chain->next;
+	  if (GET_CODE (insn) != CALL_INSN
+	      || find_reg_note (insn, REG_NORETURN, NULL))
+	    continue;
+	  REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
+				   &chain->live_throughout);
+	  COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+
+	  /* Record all registers set in this call insn.  These don't
+	     need to be saved.  N.B. the call insn might set a subreg
+	     of a multi-hard-reg pseudo; then the pseudo is considered
+	     live during the call, but the subreg that is set
+	     isn't.  */
+	  CLEAR_HARD_REG_SET (this_insn_sets);
+	  note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
+	  /* Sibcalls are considered to set the return value,
+	     compare flow.c:propagate_one_insn.  */
+	  if (SIBLING_CALL_P (insn) && crtl->return_rtx)
+	    mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
+
+	  AND_COMPL_HARD_REG_SET (used_regs, call_fixed_reg_set);
+	  AND_COMPL_HARD_REG_SET (used_regs, this_insn_sets);
+	  AND_HARD_REG_SET (hard_regs_to_save, used_regs);
+	  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+	    if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+	      {
+		gcc_assert (hard_reg_map[regno] != NULL);
+		call_saved_regs[call_saved_regs_num++] = hard_reg_map[regno];
+	      }
+	  /* Look through all live pseudos, mark their hard registers.  */
+	  EXECUTE_IF_SET_IN_REG_SET
+	    (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
+	    {
+	      int r = reg_renumber[regno];
+	      int bound;
+	      
+	      if (r < 0)
+		continue;
 
-	/* If no mode exists for this size, try another.  Also break out
-	   if we have already saved this hard register.  */
-	if (regno_save_mode[i][j] == VOIDmode || regno_save_mem[i][1] != 0)
-	  continue;
-
-	/* See if any register in this group has been saved.  */
-	for (k = 0; k < j; k++)
-	  if (regno_save_mem[i + k][1])
-	    {
-	      do_save = 0;
-	      break;
-	    }
-	if (! do_save)
-	  continue;
-
-	for (k = 0; k < j; k++)
-	  if (! TEST_HARD_REG_BIT (hard_regs_used, i + k))
-	    {
-	      do_save = 0;
-	      break;
-	    }
-	if (! do_save)
-	  continue;
-
-	/* We have found an acceptable mode to store in.  Since hard
-	   register is always saved in the widest mode available,
-	   the mode may be wider than necessary, it is OK to reduce
-	   the alignment of spill space.  We will verify that it is
-	   equal to or greater than required when we restore and save
-	   the hard register in insert_restore and insert_save.  */
-	regno_save_mem[i][j]
-	  = assign_stack_local_1 (regno_save_mode[i][j],
-				GET_MODE_SIZE (regno_save_mode[i][j]),
-				0, true);
-
-	/* Setup single word save area just in case...  */
-	for (k = 0; k < j; k++)
-	  /* This should not depend on WORDS_BIG_ENDIAN.
-	     The order of words in regs is the same as in memory.  */
-	  regno_save_mem[i + k][1]
-	    = adjust_address_nv (regno_save_mem[i][j],
-				 regno_save_mode[i + k][1],
-				 k * UNITS_PER_WORD);
-      }
+	      bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+	      for (; r < bound; r++)
+		if (TEST_HARD_REG_BIT (used_regs, r))
+		  call_saved_regs[call_saved_regs_num++] = hard_reg_map[r];
+	    }
+	  for (i = 0; i < call_saved_regs_num; i++)
+	    {
+	      saved_reg = call_saved_regs[i];
+	      for (j = 0; j < call_saved_regs_num; j++)
+		if (i != j)
+		  {
+		    saved_reg2 = call_saved_regs[j];
+		    saved_reg_conflicts[saved_reg->num * saved_regs_num
+					+ saved_reg2->num]
+		      = saved_reg_conflicts[saved_reg2->num * saved_regs_num
+					    + saved_reg->num]
+		      = TRUE;
+		  }
+	    }
+	}
+      /* Sort saved hard regs.  */
+      qsort (all_saved_regs, saved_regs_num, sizeof (struct saved_hard_reg *),
+	     saved_hard_reg_compare_func);
+      /* Initiate slots available from the previous reload
+	 iteration.  */
+      prev_save_slots_num = save_slots_num;
+      memcpy (prev_save_slots, save_slots, save_slots_num * sizeof (rtx));
+      save_slots_num = 0;
+      /* Allocate stack slots for the saved hard registers.  */
+      for (i = 0; i < saved_regs_num; i++)
+	{
+	  saved_reg = all_saved_regs[i];
+	  regno = saved_reg->hard_regno;
+	  for (j = 0; j < i; j++)
+	    {
+	      saved_reg2 = all_saved_regs[j];
+	      if (! saved_reg2->first_p)
+		continue;
+	      slot = saved_reg2->slot;
+	      for (k = j; k >= 0; k = next_k)
+		{
+		  saved_reg3 = all_saved_regs[k];
+		  next_k = saved_reg3->next;
+		  if (saved_reg_conflicts[saved_reg->num * saved_regs_num
+					  + saved_reg3->num])
+		    break;
+		}
+	      if (k < 0
+		  && (GET_MODE_SIZE (regno_save_mode[regno][1])
+		      <= GET_MODE_SIZE (regno_save_mode
+					[saved_reg2->hard_regno][1])))
+		{
+		  saved_reg->slot
+		    = adjust_address_nv
+		      (slot, regno_save_mode[saved_reg->hard_regno][1], 0);
+		  regno_save_mem[regno][1] = saved_reg->slot;
+		  saved_reg->next = saved_reg2->next;
+		  saved_reg2->next = i;
+		  if (dump_file != NULL)
+		    fprintf (dump_file, "%d uses slot of %d\n",
+			     regno, saved_reg2->hard_regno);
+		  break;
+		}
+	    }
+	  if (j == i)
+	    {
+	      saved_reg->first_p = TRUE;
+	      for (best_slot_num = -1, j = 0; j < prev_save_slots_num; j++)
+		{
+		  slot = prev_save_slots[j];
+		  if (slot == NULL_RTX)
+		    continue;
+		  if (GET_MODE_SIZE (regno_save_mode[regno][1])
+		      <= GET_MODE_SIZE (GET_MODE (slot))
+		      && best_slot_num < 0)
+		    best_slot_num = j;
+		  if (GET_MODE (slot) == regno_save_mode[regno][1])
+		    break;
+		}
+	      if (best_slot_num >= 0)
+		{
+		  saved_reg->slot = prev_save_slots[best_slot_num];
+		  saved_reg->slot
+		    = adjust_address_nv
+		      (saved_reg->slot,
+		       regno_save_mode[saved_reg->hard_regno][1], 0);
+		  if (dump_file != NULL)
+		    fprintf (dump_file,
+			     "%d uses a slot from prev iteration\n", regno);
+		  prev_save_slots[best_slot_num] = NULL_RTX;
+		  if (best_slot_num + 1 == prev_save_slots_num)
+		    prev_save_slots_num--;
+		}
+	      else
+		{
+		  saved_reg->slot
+		    = assign_stack_local_1
+		      (regno_save_mode[regno][1],
+		       GET_MODE_SIZE (regno_save_mode[regno][1]), 0, true);
+		  if (dump_file != NULL)
+		    fprintf (dump_file, "%d uses a new slot\n", regno);
+		}
+	      regno_save_mem[regno][1] = saved_reg->slot;
+	      save_slots[save_slots_num++] = saved_reg->slot;
+	    }
+	}
+      free (saved_reg_conflicts);
+      finish_saved_hard_regs ();
+    }
+  else
+    {
+      /* Now run through all the call-used hard-registers and allocate
+	 space for them in the caller-save area.  Try to allocate space
+	 in a manner which allows multi-register saves/restores to be done.  */
+      
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+	for (j = MOVE_MAX_WORDS; j > 0; j--)
+	  {
+	    int do_save = 1;
+	    
+	    /* If no mode exists for this size, try another.  Also break out
+	       if we have already saved this hard register.  */
+	    if (regno_save_mode[i][j] == VOIDmode || regno_save_mem[i][1] != 0)
+	      continue;
+	    
+	    /* See if any register in this group has been saved.  */
+	    for (k = 0; k < j; k++)
+	      if (regno_save_mem[i + k][1])
+		{
+		  do_save = 0;
+		  break;
+		}
+	    if (! do_save)
+	      continue;
+	    
+	    for (k = 0; k < j; k++)
+	      if (! TEST_HARD_REG_BIT (hard_regs_used, i + k))
+		{
+		  do_save = 0;
+		  break;
+		}
+	    if (! do_save)
+	      continue;
+	    
+	    /* We have found an acceptable mode to store in.  Since
+	       hard register is always saved in the widest mode
+	       available, the mode may be wider than necessary, it is
+	       OK to reduce the alignment of spill space.  We will
+	       verify that it is equal to or greater than required
+	       when we restore and save the hard register in
+	       insert_restore and insert_save.  */
+	    regno_save_mem[i][j]
+	      = assign_stack_local_1 (regno_save_mode[i][j],
+				      GET_MODE_SIZE (regno_save_mode[i][j]),
+				      0, true);
+	    
+	    /* Setup single word save area just in case...  */
+	    for (k = 0; k < j; k++)
+	      /* This should not depend on WORDS_BIG_ENDIAN.
+		 The order of words in regs is the same as in memory.  */
+	      regno_save_mem[i + k][1]
+		= adjust_address_nv (regno_save_mem[i][j],
+				     regno_save_mode[i + k][1],
+				     k * UNITS_PER_WORD);
+	  }
+    }
 
   /* Now loop again and set the alias set of any save areas we made to
      the alias set used to represent frame objects.  */
@@ -384,61 +768,1033 @@ setup_save_areas (void)
       if (regno_save_mem[i][j] != 0)
 	set_mem_alias_set (regno_save_mem[i][j], get_frame_alias_set ());
 }
+
+
+
+/* This page contains code for global analysis for better placement
+   save/restore insn when IRA is used.
+
+   First, we calculate local BB info in function calculate_local_save_info:
+     o hard registers set/mentioned in basic blocks (they prevents
+       moving corresponding saves/restores further up/down in CFG) --
+       see comments for save_kill/restore_kill.
+     o hard registers needed to be saved/restored around calls and
+       which are not set/mentioned before/after the call in the basic
+       block -- see comments for save_gen/restore_gen.
+     o free hard registers at the basic block start -- see comments
+       for free_gen.  This set can be different from save_gen.  For
+       example, in the following situation
+
+       BB:
+          ...
+          insn using R
+          ...
+          call through which R live through and should be saved/restored.
+          ...
+
+       save_gen contains R because we can put save at the BB start but
+       free_gen does not contain R because we can not use R for other
+       purposes from the BB start till the insn using R.
+       
+   Second, we calculate the global info for placement saves/restores
+   in functions -- see comments for save_in, save_out, restore_in,
+   restore_out, free_in, free_out.
+
+   The equations for the global info calculation are not trivial
+   because we can not put saves/restores on CFG edges as the reload
+   can not work when new BBs added.  For example, it means that all
+   save_out set of BB should be a subset of intersections of save_in
+   of all successors of the BB.  Preventing putting the code on edges
+   makes data flow problem bidirectional.  The data flow functions are
+   also complicated by necessity to propagate saving modes (e.g. x86
+   fp register can be saved in XFmode or DFmode).
+
+   The equations do not permit to propagate info into the loops
+   because we can not put saves/restores in more frequently executed
+   points.  But if the loop does not contains references for a hard
+   register, we permit to propagate info for the register into the
+   loop because the info will be propagated through all the loop and
+   as consequence corresponding saves/restores will be moved through
+   the loop.
+
+   Third, using this info we place saves/restores and set up member
+   `saved' in function save_call_clobbered_regs.
+
+  */
+
+/* The following structure contains basic block data flow information
+   used to optimize save/restore placement.  Data flow equations are
+   bidirectional because we don't want to put save/restore code on CFG
+   edges.  */
+struct bb_info
+{
+  /* True if save_out/restore_in should be empty for this block.  */
+  int empty_save_out_p, empty_restore_in_p;
+  /* Hard registers set/mentioned in the BB.  */
+  HARD_REG_SET save_kill;
+  HARD_REG_SET restore_kill;
+  /* Hard registers needed to be saved and this save not killed (see above)
+     by an insn in the BB before that.  */
+  HARD_REG_SET save_gen;
+  /* Hard registers needed to be restored and this restore not killed
+     by an insn in the BB after that.  */
+  HARD_REG_SET restore_gen;
+  /* Hard registers free and not killed by an insn in the BB before
+     that.  */
+  HARD_REG_SET free_gen;
+  /* Registers needed to be saved/restored at the start and end of the
+     basic block.  */
+  HARD_REG_SET save_in, save_out, restore_in, restore_out;
+  /* Registers free at the start and end of the basic block.  */
+  HARD_REG_SET free_in, free_out;
+  /* Hard registers living at the start/end of the basic block.  */
+  HARD_REG_SET live_at_start, live_at_end;
+  /* We don't want to generate save/restore insns on edges because it
+     changes CFG during the reload.  To prevent this we use the
+     following set.  This set defines what hard registers should be
+     saved/restored at the start/end of basic block.  */
+  HARD_REG_SET save_here, restore_here;
+  /* It corresponds to set SAVE_GEN right after the call of
+     calculate_local_save_info.  */
+  unsigned char save_in_mode[FIRST_PSEUDO_REGISTER];
+  /* Saving modes at the end of the basic block.  */
+  unsigned char save_out_mode[FIRST_PSEUDO_REGISTER];
+  /* Restoring modes at the start of the basic block.  */
+  unsigned char restore_in_mode[FIRST_PSEUDO_REGISTER];
+  /* It corresponds to set RESTORE_GEN right after the call of
+     calculate_local_save_info.  */
+  unsigned char restore_out_mode[FIRST_PSEUDO_REGISTER];
+  /* Analogous but the corresponding pseudo-register numbers.  */
+  int save_in_pseudo[FIRST_PSEUDO_REGISTER];
+  int save_out_pseudo[FIRST_PSEUDO_REGISTER];
+  int restore_in_pseudo[FIRST_PSEUDO_REGISTER];
+  int restore_out_pseudo[FIRST_PSEUDO_REGISTER];
+};
+
+/* Macros for accessing data flow information of basic blocks.  */
+#define BB_INFO(BB) ((struct bb_info *) (BB)->aux)
+#define BB_INFO_BY_INDEX(N) BB_INFO (BASIC_BLOCK(N))
+
+/* The following structure contains loop info necessary for
+   save/restore placement optimization.  */
+struct loop_info
+{
+  /* All hard registers mentioned in the loop.  If a pseudo is
+     mentioned in the loop, the hard registers assigned to it are also
+     believed to be mentioned in the loop.  */
+  HARD_REG_SET mentioned_regs;
+};
+
+/* Macro for accessing data flow information of LOOP.  */
+#define LOOP_INFO(LOOP) ((struct loop_info *) (LOOP)->aux)
+
+/* The function calculates sets KILL, GEN, LIVE_AT_START and
+   RESTORE_OUT_MODES corresponding to GEN for basic blocks.  */
+static void
+calculate_local_save_info (void)
+{
+  int i, empty_save_out_p, empty_restore_in_p;
+  struct insn_chain *chain, *next;
+  struct bb_info *bb_info;
+  /* Computed in mark_set_regs, holds all registers set by the current
+     instruction.  */
+  HARD_REG_SET save_kill, restore_kill;
+  HARD_REG_SET this_insn_sets, save_gen, restore_gen, free_gen, temp_set;
+  unsigned regno;
+  reg_set_iterator rsi;
+  /* A map: hard register being saved to the mode used for its
+     saving.  */
+  enum machine_mode save_mode[FIRST_PSEUDO_REGISTER];
+  /* A map: hard register being saved to the pseudo-register assigned
+     to the hard register at given point.  */
+  int save_pseudo[FIRST_PSEUDO_REGISTER];
+
+  CLEAR_HARD_REG_SET (save_gen);
+  CLEAR_HARD_REG_SET (restore_gen);
+  CLEAR_HARD_REG_SET (free_gen);
+  CLEAR_HARD_REG_SET (save_kill);
+  CLEAR_HARD_REG_SET (restore_kill);
+  empty_save_out_p = FALSE;
+  empty_restore_in_p = FALSE;
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      save_mode[i] = VOIDmode;
+      save_pseudo[i] = -1;
+    }
+
+  for (chain = reload_insn_chain; chain != 0; chain = next)
+    {
+      rtx insn = chain->insn;
+      enum rtx_code code = GET_CODE (insn);
+
+      next = chain->next;
+
+      bb_info = BB_INFO_BY_INDEX (chain->block);
+      if (INSN_P (insn))
+	{
+	  CLEAR_HARD_REG_SET (referenced_regs);
+	  CLEAR_HARD_REG_SET (modified_regs);
+	  mark_referenced_regs (PATTERN (insn), FALSE);
+	  AND_COMPL_HARD_REG_SET (restore_gen, referenced_regs);
+	  IOR_HARD_REG_SET (restore_kill, referenced_regs);
+	  IOR_HARD_REG_SET (save_kill, modified_regs);
+
+	  if (code == CALL_INSN && find_reg_note (insn, REG_NORETURN, NULL))
+	    {
+	      SET_HARD_REG_SET (save_kill);
+	      SET_HARD_REG_SET (restore_kill);
+	    }
+	  else if (code == CALL_INSN)
+	    {
+	      HARD_REG_SET hard_regs_to_save, used_regs;
+	      
+	      /* Use the register life information in CHAIN to compute
+		 which regs are live during the call.  */
+	      REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
+				       &chain->live_throughout);
+	      /* Look through all live pseudos, mark their hard registers
+		 and choose proper mode for saving.  */
+	      EXECUTE_IF_SET_IN_REG_SET
+		(&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
+		{
+		  int r = reg_renumber[regno];
+		  int nregs;
+		  enum machine_mode mode;
+		  
+		  /* Remember live_throughout can contain spilled
+		     registers when IRA is used.  */
+		  if (flag_ira && optimize && r < 0)
+		    continue;
+		  gcc_assert (r >= 0);
+
+		  nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+		  mode = HARD_REGNO_CALLER_SAVE_MODE
+		         (r, nregs, PSEUDO_REGNO_MODE (regno));
+		  if (nregs == 1)
+		    {
+		      SET_HARD_REG_BIT (hard_regs_to_save, r);
+		      save_mode[r] = mode;
+		      save_pseudo[r] = regno;
+		    }
+		  else
+		    {
+		      while (nregs-- > 0)
+			{
+			  SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
+			  save_mode[r + nregs]
+			    = regno_save_mode[r + nregs][1];
+			  save_pseudo[r + nregs] = regno;
+			}
+		    }
+		}
+	      
+	      /* Record all registers set in this call insn.  These
+		 don't need to be saved.  N.B. the call insn might set
+		 a subreg of a multi-hard-reg pseudo; then the pseudo
+		 is considered live during the call, but the subreg
+		 that is set isn't.  */
+	      CLEAR_HARD_REG_SET (this_insn_sets);
+	      note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
+	      /* Sibcalls are considered to set the return value.  */
+	      if (SIBLING_CALL_P (insn) && crtl->return_rtx)
+		mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
+	      
+	      /* Compute which hard regs must be saved before this call.  */
+	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, call_fixed_reg_set);
+	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, this_insn_sets);
+	      COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+	      AND_HARD_REG_SET (hard_regs_to_save, used_regs);
+	      IOR_HARD_REG_SET (restore_gen, hard_regs_to_save);
+	      COPY_HARD_REG_SET (temp_set, hard_regs_to_save);
+	      AND_COMPL_HARD_REG_SET (temp_set, save_kill);
+	      AND_COMPL_HARD_REG_SET (temp_set, save_gen);
+	      IOR_HARD_REG_SET (save_gen, temp_set);
+	      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+		if (TEST_HARD_REG_BIT (temp_set, i))
+		  {
+		    bb_info->save_in_mode[i] = save_mode[i];
+		    bb_info->save_in_pseudo[i] = save_pseudo[i];
+		  }
+	      COPY_HARD_REG_SET (temp_set, hard_regs_to_save);
+	      AND_COMPL_HARD_REG_SET (temp_set, save_kill);
+	      AND_COMPL_HARD_REG_SET (temp_set, restore_kill);
+	      IOR_HARD_REG_SET (free_gen, temp_set);
+	    }
+	}
+
+      if (chain->next == 0 || chain->next->block != chain->block)
+	{
+	  basic_block bb = BASIC_BLOCK (chain->block);
+	  edge e;
+	  edge_iterator ei;
+	  loop_p loop;
+
+	  if (! empty_save_out_p)
+	    FOR_EACH_EDGE (e, ei, bb->succs)
+	      if (e->flags & EDGE_ABNORMAL)
+		{
+		  empty_save_out_p = TRUE;
+		  break;
+		}
+	  bb_info->empty_save_out_p = empty_save_out_p;
+	  empty_save_out_p = FALSE;
+	  if (! empty_restore_in_p)
+	    FOR_EACH_EDGE (e, ei, bb->preds)
+	      if (e->flags & EDGE_ABNORMAL)
+		{
+		  empty_restore_in_p = TRUE;
+		  break;
+		}
+	  bb_info->empty_restore_in_p = empty_restore_in_p;
+	  empty_restore_in_p = FALSE;
+	  COPY_HARD_REG_SET (bb_info->save_gen, save_gen);
+	  COPY_HARD_REG_SET (bb_info->restore_gen, restore_gen);
+	  COPY_HARD_REG_SET (bb_info->free_gen, free_gen);
+	  CLEAR_HARD_REG_SET (bb_info->restore_in);
+	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+	    {
+	      bb_info->save_out_mode[i] = VOIDmode;
+	      bb_info->save_out_pseudo[i] = -1;
+	      if (!TEST_HARD_REG_BIT (save_gen, i))
+		{
+		  bb_info->save_in_mode[i] = VOIDmode;
+		  bb_info->save_in_pseudo[i] = -1;
+		}
+	      bb_info->restore_in_mode[i] = VOIDmode;
+	      bb_info->restore_in_pseudo[i] = -1;
+	      if (TEST_HARD_REG_BIT (restore_gen, i))
+		{
+		  bb_info->restore_out_mode[i] = save_mode[i];
+		  bb_info->restore_out_pseudo[i] = save_pseudo[i];
+		}
+	      else
+		{
+		  bb_info->restore_out_mode[i] = VOIDmode;
+		  bb_info->restore_out_pseudo[i] = -1;
+		}
+	    }
+	  COPY_HARD_REG_SET (bb_info->save_kill, save_kill);
+	  COPY_HARD_REG_SET (bb_info->restore_kill, restore_kill);
+	  for (loop = bb->loop_father;
+	       loop != current_loops->tree_root;
+	       loop = loop_outer (loop))
+	    {
+	      struct loop_info *loop_info = LOOP_INFO (loop);
+	      
+	      IOR_HARD_REG_SET (loop_info->mentioned_regs, save_kill);
+	      IOR_HARD_REG_SET (loop_info->mentioned_regs, restore_kill);
+	    }
+	  CLEAR_HARD_REG_SET (bb_info->save_in);
+	  CLEAR_HARD_REG_SET (bb_info->restore_out);
+	  CLEAR_HARD_REG_SET (bb_info->free_in);
+	  /* We don't use LIVE for IRA.  */
+	  REG_SET_TO_HARD_REG_SET
+	    (bb_info->live_at_end,
+	     flag_ira ? DF_LR_OUT (bb) : DF_LIVE_OUT (bb));
+	  EXECUTE_IF_SET_IN_REG_SET
+	    ((flag_ira ? DF_LR_OUT (bb) : DF_LIVE_OUT (bb)),
+	     FIRST_PSEUDO_REGISTER, regno, rsi)
+	    {
+	      int r = reg_renumber[regno];
+	      int nregs;
+	      
+	      if (r < 0)
+		continue;
+	      nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+	      while (nregs-- > 0)
+		SET_HARD_REG_BIT (bb_info->live_at_end, r + nregs);
+	    }
+	  REG_SET_TO_HARD_REG_SET
+	    (bb_info->live_at_start,
+	     flag_ira ? DF_LR_IN (bb) : DF_LIVE_IN (bb));
+	  EXECUTE_IF_SET_IN_REG_SET
+	    ((flag_ira ? DF_LR_IN (bb) : DF_LIVE_IN (bb)),
+	     FIRST_PSEUDO_REGISTER, regno, rsi)
+	    {
+	      int r = reg_renumber[regno];
+	      int nregs;
+	      
+	      if (r < 0)
+		continue;
+	      nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+	      while (nregs-- > 0)
+		SET_HARD_REG_BIT (bb_info->live_at_start, r + nregs);
+	    }
+	  CLEAR_HARD_REG_SET (bb_info->save_here);
+	  CLEAR_HARD_REG_SET (bb_info->restore_here);
+	  CLEAR_HARD_REG_SET (save_gen);
+	  CLEAR_HARD_REG_SET (restore_gen);
+	  CLEAR_HARD_REG_SET (free_gen);
+	  CLEAR_HARD_REG_SET (save_kill);
+	  CLEAR_HARD_REG_SET (restore_kill);
+	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+	    {
+	      save_mode[i] = VOIDmode;
+	      save_pseudo[i] = -1;
+	    }
+	}
+    }
+}
+
+/* The transfer function used by the DF equation solver to propagate restore
+   info through block with BB_INDEX according to the following
+   equation:
+
+   bb.restore_out = (bb.restore_in - bb.restore_kill) U bb.restore_gen.
+
+   The function also propagates saving modes of the hard
+   registers.  */
+static bool
+restore_trans_fun (int bb_index)
+{
+  int i;
+  HARD_REG_SET temp_set;
+  struct bb_info *bb_info = BB_INFO_BY_INDEX (bb_index);
+
+  COPY_HARD_REG_SET (temp_set, bb_info->restore_in);
+  AND_COMPL_HARD_REG_SET (temp_set, bb_info->restore_kill);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (TEST_HARD_REG_BIT (temp_set, i)
+	&& ! TEST_HARD_REG_BIT (bb_info->restore_gen, i))
+      {
+	gcc_assert (bb_info->restore_out_mode[i] == VOIDmode
+		    || ((bb_info->restore_out_mode[i]
+			 == bb_info->restore_in_mode[i])
+			&& (bb_info->restore_out_pseudo[i]
+			    == bb_info->restore_in_pseudo[i])));
+	bb_info->restore_out_mode[i] = bb_info->restore_in_mode[i];
+	bb_info->restore_out_pseudo[i] = bb_info->restore_in_pseudo[i];
+      }
+  IOR_HARD_REG_SET (temp_set, bb_info->restore_gen);
+  if (! hard_reg_set_equal_p (temp_set, bb_info->restore_out))
+    {
+      COPY_HARD_REG_SET (bb_info->restore_out, temp_set);
+      return true;
+    }
+  return false;
+}
+
+/* The confluence function used by the DF equation solver to set up restore info
+   for a block BB without predecessor.  */
+static void
+restore_con_fun_0 (basic_block bb)
+{
+  CLEAR_HARD_REG_SET (BB_INFO (bb)->restore_in);
+}
+
+/* The confluence function used by the DF equation solver to propagate
+   restore info from predecessor to successor on edge E (pred->bb)
+   according to the following equation:
+
+     bb.restore_in  = empty for entry block or one with empty_restore_in_p
+                    | ^(pred.restore_out - pred.restore_here) ^ bb.live_at_start
+		    
+   If the edge is a loop enter we do not propagate the info because we
+   don't want to put restores in more frequently executed places.
+
+ */
+static void
+restore_con_fun_n (edge e)
+{
+  int i;
+  HARD_REG_SET temp_set;
+  basic_block pred = e->src;
+  basic_block bb = e->dest;
+  struct bb_info *bb_info = BB_INFO (bb);
+  
+  if (bb_info->empty_restore_in_p)
+    return;
+
+  COPY_HARD_REG_SET (temp_set, BB_INFO (pred)->restore_out);
+  AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (pred)->restore_here);
+  if (bb->loop_depth > pred->loop_depth)
+    AND_COMPL_HARD_REG_SET (temp_set,
+			    LOOP_INFO (bb->loop_father)->mentioned_regs);
+  AND_HARD_REG_SET (temp_set, bb_info->live_at_start);
+  if (EDGE_PRED (bb, 0) == e)
+    COPY_HARD_REG_SET (bb_info->restore_in, temp_set);
+  else
+    AND_HARD_REG_SET (bb_info->restore_in, temp_set);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (TEST_HARD_REG_BIT (temp_set, i))
+      {
+	if (bb_info->restore_in_mode[i] != VOIDmode
+	    && BB_INFO (pred)->restore_out_mode[i] != VOIDmode
+	    && (bb_info->restore_in_mode[i]
+		!= BB_INFO (pred)->restore_out_mode[i]
+		|| bb_info->restore_in_pseudo[i]
+		!= BB_INFO (pred)->restore_out_pseudo[i]))
+	  CLEAR_HARD_REG_BIT (bb_info->restore_in, i);
+	else if (BB_INFO (pred)->restore_out_mode[i] != VOIDmode)
+	  {
+	    bb_info->restore_in_mode[i]
+	      = BB_INFO (pred)->restore_out_mode[i];
+	    bb_info->restore_in_pseudo[i]
+	      = BB_INFO (pred)->restore_out_pseudo[i];
+	  }
+      }
+}
+
+/* Basic blocks for data flow problem -- all bocks except the special
+   ones.  */
+static bitmap all_blocks;
+
+/* The function calculates global restore information according
+   to the following equations:
+
+     bb.restore_in  = empty for entry block or one with empty_restore_in_p
+                    | ^(pred.restore_out - pred.restore_here) ^ bb.live_at_start
+     bb.restore_out = (bb.restore_in - bb.restore_kill) U bb.restore_gen.
+
+   The function also calculates restore_in_mode and restore_out_mode.
+*/
+static void
+calculate_restore_in_out (void)
+{
+  df_simple_dataflow (DF_FORWARD, NULL, restore_con_fun_0, restore_con_fun_n,
+		      restore_trans_fun, all_blocks,
+		      df_get_postorder (DF_FORWARD),
+		      df_get_n_blocks (DF_FORWARD));
+}
+
+/* The function calculates RESTORE_HERE according to the equation
+   bb.restore_here = U ((bb.restore_out - succ.restore_in)
+                        ^ succ.live_at_start).  */
+static int
+calculate_restore_here (void)
+{
+  basic_block bb;
+  edge e;
+  edge_iterator ei;
+  HARD_REG_SET restore_here, temp_set;
+  int changed_p = FALSE;
+
+  FOR_EACH_BB (bb)
+    {
+      CLEAR_HARD_REG_SET (restore_here);
+      FOR_EACH_EDGE (e, ei, bb->succs)
+	{
+	  basic_block dest = e->dest;
+
+	  COPY_HARD_REG_SET (temp_set, BB_INFO (bb)->restore_out);
+	  AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (dest)->restore_in);
+	  AND_HARD_REG_SET (temp_set, BB_INFO (dest)->live_at_start);
+	  IOR_HARD_REG_SET (restore_here, temp_set);
+	}
+
+      if (! hard_reg_set_equal_p (restore_here, BB_INFO (bb)->restore_here))
+	{
+	  COPY_HARD_REG_SET (BB_INFO (bb)->restore_here, restore_here);
+	  changed_p = TRUE;
+	}
+    }
+  return changed_p;
+}
+
+/* The transfer function used by the DF equation solver to propagate save info
+   through block with BB_INDEX according to the following
+   equation:
+
+   bb.save_in = ((bb.save_out - bb.save_kill) U bb.save_gen) - bb.restore_in.
+
+   The function also propagates saving modes of the hard
+   registers.  */
+
+static bool
+save_trans_fun (int bb_index)
+{
+  int i;
+  HARD_REG_SET temp_set;
+  struct bb_info *bb_info = BB_INFO_BY_INDEX (bb_index);
+
+  COPY_HARD_REG_SET (temp_set, bb_info->save_out);
+  AND_COMPL_HARD_REG_SET (temp_set, bb_info->save_kill);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (TEST_HARD_REG_BIT (temp_set, i)
+	&& ! TEST_HARD_REG_BIT (bb_info->save_gen, i))
+      {
+	gcc_assert (bb_info->save_in_mode[i] == VOIDmode
+		    || ((bb_info->save_in_mode[i]
+			 == bb_info->save_out_mode[i])
+			&& (bb_info->save_in_pseudo[i]
+			    == bb_info->save_out_pseudo[i])));
+	bb_info->save_in_mode[i] = bb_info->save_out_mode[i];
+	bb_info->save_in_pseudo[i] = bb_info->save_out_pseudo[i];
+      }
+  IOR_HARD_REG_SET (temp_set, bb_info->save_gen);
+  AND_COMPL_HARD_REG_SET (temp_set, bb_info->restore_in);
+  if (! hard_reg_set_equal_p (temp_set, bb_info->save_in))
+    {
+      COPY_HARD_REG_SET (bb_info->save_in, temp_set);
+      return true;
+    }
+  return false;
+}
+
+/* The confluence function used by the DF equation solver to set up
+   save info for a block BB without successor.  */
+static void
+save_con_fun_0 (basic_block bb)
+{
+  CLEAR_HARD_REG_SET (BB_INFO (bb)->save_out);
+}
+
+/* The confluence function used by the DF equation solver to propagate
+   save info from successor to predecessor on edge E (bb->succ)
+   according to the following equation:
+
+     bb.save_out  = empty for exit block or one with empty_save_out_p
+                    | ^(succ.save_in - succ.save_here) ^ bb.live_at_end
+
+   If the edge is a loop exit we do not propagate the info because we
+   don't want to put saves in more frequently executed places.
+*/
+static void
+save_con_fun_n (edge e)
+{
+  int i;
+  HARD_REG_SET temp_set;
+  basic_block succ = e->dest;
+  basic_block bb = e->src;
+  struct bb_info *bb_info = BB_INFO (bb);
+  
+  if (bb_info->empty_save_out_p)
+    return;
+
+  COPY_HARD_REG_SET (temp_set, BB_INFO (succ)->save_in);
+  AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (succ)->save_here);
+  if (bb->loop_depth > succ->loop_depth)
+    AND_COMPL_HARD_REG_SET (temp_set,
+			    LOOP_INFO (bb->loop_father)->mentioned_regs);
+  AND_HARD_REG_SET (temp_set, bb_info->live_at_end);
+  if (EDGE_SUCC (bb, 0) == e)
+    COPY_HARD_REG_SET (bb_info->save_out, temp_set);
+  else
+    AND_HARD_REG_SET (bb_info->save_out, temp_set);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (TEST_HARD_REG_BIT (temp_set, i))
+      {
+	if (bb_info->save_out_mode[i] != VOIDmode
+	    && BB_INFO (succ)->save_in_mode[i] != VOIDmode
+	    && ((bb_info->save_out_mode[i]
+		 != BB_INFO (succ)->save_in_mode[i])
+		|| (bb_info->save_out_pseudo[i]
+		    != BB_INFO (succ)->save_in_pseudo[i])))
+	  CLEAR_HARD_REG_BIT (bb_info->save_out, i);
+	else if (BB_INFO (succ)->save_in_mode[i] != VOIDmode)
+	  {
+	    bb_info->save_out_mode[i]
+	      = BB_INFO (succ)->save_in_mode[i];
+	    bb_info->save_out_pseudo[i]
+	      = BB_INFO (succ)->save_in_pseudo[i];
+	  }
+      }
+}
+
+/* The transfer function calculates global save information according
+   to the following equations:
+
+     bb.save_out  = empty for exit block or one with empty_save_out_p
+                    | ^(succ.save_in - succ.save_here) ^ bb.live_at_end
+     bb.save_in = ((bb.save_out - bb.save_kill) U bb.save_gen) - bb.restore_in.
+
+   The function also calculates save_in_mode and save_out_mode.
+*/
+static void
+calculate_save_in_out (void)
+{
+  df_simple_dataflow (DF_BACKWARD, NULL, save_con_fun_0, save_con_fun_n,
+		      save_trans_fun, all_blocks,
+		      df_get_postorder (DF_BACKWARD),
+		      df_get_n_blocks (DF_BACKWARD));
+}
+
+/* The function calculates SAVE_HERE according to the equation
+   bb.save_here = U ((bb.save_in - pred.save_out) ^ pred.live_at_end).  */
+static int
+calculate_save_here (void)
+{
+  basic_block bb;
+  edge e;
+  edge_iterator ei;
+  HARD_REG_SET save_here, temp_set;
+  int changed_p = FALSE;
+
+  FOR_EACH_BB (bb)
+    {
+      CLEAR_HARD_REG_SET (save_here);
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	{
+	  basic_block src = e->src;
+
+	  COPY_HARD_REG_SET (temp_set, BB_INFO (bb)->save_in);
+	  AND_COMPL_HARD_REG_SET (temp_set, BB_INFO (src)->save_out);
+	  AND_HARD_REG_SET (temp_set, BB_INFO (src)->live_at_end);
+	  IOR_HARD_REG_SET (save_here, temp_set);
+	}
+
+      if (! hard_reg_set_equal_p (save_here, BB_INFO (bb)->save_here))
+	{
+	  COPY_HARD_REG_SET (BB_INFO (bb)->save_here, save_here);
+	  changed_p = TRUE;
+	}
+    }
+  return changed_p;
+}
+
+/* The transfer function used by the DF equation solver to propagate
+   free info through block with BB_INDEX according to the following
+   equation:
+
+   bb.free_in = ((bb.free_out - bb.save_kill - bb.restore_kill) U bb.free_gen)
+                 - bb.save_here)
+
+*/
+static bool
+free_trans_fun (int bb_index)
+{
+  HARD_REG_SET temp_set;
+  struct bb_info *bb_info = BB_INFO_BY_INDEX (bb_index);
+
+  COPY_HARD_REG_SET (temp_set, bb_info->free_out);
+  AND_COMPL_HARD_REG_SET (temp_set, bb_info->save_kill);
+  AND_COMPL_HARD_REG_SET (temp_set, bb_info->restore_kill);
+  IOR_HARD_REG_SET (temp_set, bb_info->free_gen);
+  AND_COMPL_HARD_REG_SET (temp_set, bb_info->save_here);
+  if (! hard_reg_set_equal_p (temp_set, bb_info->free_in))
+    {
+      COPY_HARD_REG_SET (bb_info->free_in, temp_set);
+      return true;
+    }
+  return false;
+}
+
+/* The confluence function used by the DF equation solver to set up
+   free info for a block BB without successor.  */
+static void
+free_con_fun_0 (basic_block bb)
+{
+  CLEAR_HARD_REG_SET (BB_INFO (bb)->free_out);
+}
+
+/* The confluence function used by the DF equation solver to propagate
+   free info from successor to predecessor on edge E (bb->succ)
+   according to the following equation:
+
+     bb.free_out = ^(succ.free_in ^ bb.live_at_end)
+*/
+static void
+free_con_fun_n (edge e)
+{
+  HARD_REG_SET temp_set;
+  basic_block succ = e->dest;
+  basic_block bb = e->src;
+  struct bb_info *bb_info = BB_INFO (bb);
+  
+  COPY_HARD_REG_SET (temp_set, BB_INFO (succ)->free_in);
+  if (EDGE_SUCC (bb, 0) == e)
+    COPY_HARD_REG_SET (bb_info->free_out, temp_set);
+  else
+    AND_HARD_REG_SET (bb_info->free_out, temp_set);
+  AND_HARD_REG_SET (bb_info->free_out, bb_info->live_at_end);
+}
+
+/* The function calculates global free information according
+   to the following equations:
+
+   bb.free_out = ^(succ.free_in ^ bb.live_at_end)
+   bb.free_in = ((bb.free_out - bb.save_kill - bb.restore_kill) U bb.free_gen)
+                 - bb.save_here)
+
+   The function also calculates free_in_mode and free_out_mode.
+*/
+static void
+calculate_free_in_out (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    {
+      struct bb_info *bb_info = BB_INFO (bb);
+
+      COPY_HARD_REG_SET (bb_info->free_in, bb_info->save_in);
+      IOR_HARD_REG_SET (bb_info->free_in, bb_info->restore_in);
+      COPY_HARD_REG_SET (bb_info->free_out, bb_info->save_out);
+      IOR_HARD_REG_SET (bb_info->free_out, bb_info->restore_out);
+    }
+  df_simple_dataflow (DF_BACKWARD, NULL, free_con_fun_0, free_con_fun_n,
+		      free_trans_fun, all_blocks,
+		      df_get_postorder (DF_BACKWARD),
+		      df_get_n_blocks (DF_BACKWARD));
+}
+
+/* The function calculates the global save/restore information used to put
+   save/restore code without generating new blocks.  This is a
+   bidirectional data flow problem (calculation of SAVE_IN and
+   SAVE_OUT is a backward data flow problem and SAVE_HERE is forward
+   one; calculation of RESTORE_IN and RESTORE_OUT is a forward data
+   flow problem and RESTORE_HERE is backward one).  It is complicated
+   by necessity of calculation of modes for saving/restoring callee
+   clobbered hard registers.  */
+static void
+make_global_save_analysis (void)
+{
+  basic_block bb;
+  int iter, changed_p;
+
+  all_blocks = BITMAP_ALLOC (NULL);
+  FOR_ALL_BB (bb)
+    {
+      bitmap_set_bit (all_blocks, bb->index);
+    }
+  calculate_local_save_info ();
+  for (iter = 1;; iter++)
+    {
+      calculate_restore_in_out ();
+      changed_p = calculate_restore_here ();
+      if (! changed_p)
+	break;
+    }
+  if (dump_file != NULL)
+    fprintf (dump_file, " Number of global restore analysis iterations %d\n",
+	     iter);
+  for (iter = 1;; iter++)
+    {
+      calculate_save_in_out ();
+      changed_p = calculate_save_here ();
+      if (! changed_p)
+	break;
+    }
+  if (dump_file != NULL)
+    fprintf (dump_file, " Number of global save analysis iterations %d\n",
+	     iter);
+  calculate_free_in_out ();
+  BITMAP_FREE (all_blocks);
+}
+
+/* Print hard registers in SET to file F.  The registers are printed
+   with its mode given in MODES and corresponding pseudo given in
+   PSEUDOS.  */
+static void
+print_annotated_hard_reg_set (FILE *f, HARD_REG_SET set,
+			      unsigned char *modes, int *pseudos)
+{
+  int i;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (TEST_HARD_REG_BIT (set, i))
+      {
+	fprintf (f, " %d", i);
+	if (pseudos[i] >= 0)
+	  fprintf (f, "(%d)", pseudos[i]);
+	fprintf (f, ":%s %s", GET_MODE_NAME (modes[i]), reg_names[i]);
+      }
+}
+
+/* Print hard registers in SET to file F.  */  
+static void
+print_hard_reg_set (FILE *f, HARD_REG_SET set)
+{
+  int i;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (TEST_HARD_REG_BIT (set, i))
+      fprintf (f, " %d %s", i, reg_names[i]);
+}
+
+/* Print the save information for each block to file F.  */  
+static void
+print_save_data (FILE *f)
+{
+  basic_block bb;
+  struct bb_info *bb_info;
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_BB (bb)
+    {
+      bb_info = BB_INFO (bb);
+      fprintf (f, "bb %d (preds", bb->index);
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	{
+	  fprintf (f, " %d", e->src->index);
+	}
+      fprintf (f, ") (succs");
+      FOR_EACH_EDGE (e, ei, bb->succs)
+	{
+	  fprintf (f, " %d", e->dest->index);
+	}
+      fprintf (f, ")\n  empty_save_out_p=%d", bb_info->empty_save_out_p);
+      fprintf (f, ", empty_restore_in_p=%d", bb_info->empty_restore_in_p);
+      fprintf (f, "\n  save_in:");
+      print_annotated_hard_reg_set
+	(f, bb_info->save_in, bb_info->save_in_mode, bb_info->save_in_pseudo);
+      fprintf (f, "\n  save_out:");
+      print_annotated_hard_reg_set
+	(f, bb_info->save_out,
+	 bb_info->save_out_mode, bb_info->save_out_pseudo);
+      fprintf (f, "\n  restore_in:");
+      print_annotated_hard_reg_set
+	(f, bb_info->restore_in,
+	 bb_info->restore_in_mode, bb_info->restore_in_pseudo);
+      fprintf (f, "\n  restore_out:");
+      print_annotated_hard_reg_set
+	(f, bb_info->restore_out,
+	 bb_info->restore_out_mode, bb_info->restore_out_pseudo);
+      fprintf (f, "\n  free_in:");
+      print_hard_reg_set (f, bb_info->free_in);
+      fprintf (f, "\n  free_out:");
+      print_hard_reg_set (f, bb_info->free_out);
+      fprintf (f, "\n  live_at_start:");
+      print_hard_reg_set (f, bb_info->live_at_start);
+      fprintf (f, "\n  live_at_end:");
+      print_hard_reg_set (f, bb_info->live_at_end);
+      fprintf (f, "\n  save_here:");
+      print_hard_reg_set (f, bb_info->save_here);
+      fprintf (f, "\n  restore_here:");
+      print_hard_reg_set (f, bb_info->restore_here);
+      fprintf (f, "\n  save_kill:");
+      print_hard_reg_set (f, bb_info->save_kill);
+      fprintf (f, "\n  restore_kill:");
+      print_hard_reg_set (f, bb_info->restore_kill);
+      fprintf (f, "\n  save_gen:");
+      print_hard_reg_set (f, bb_info->save_gen);
+      fprintf (f, "\n  restore_gen:");
+      print_hard_reg_set (f, bb_info->restore_gen);
+      fprintf (f, "\n  free_gen:");
+      print_hard_reg_set (f, bb_info->save_gen);
+      fprintf (f, "\n\n");
+    }
+}
+
+/* Print the save information for each block to stderr.  */  
+void
+debug_save_data (void)
+{
+  print_save_data (stderr);
+}
+
+
+/* Setup hard registers in SET to save.  Setup also their save modes
+   in SAVE_MODE from FROM_SAVE_MODE and their pseudos in SAVE_PSEUDO
+   from FROM_SAVE_PSEUDO.  */  
+static void
+set_hard_reg_saved (HARD_REG_SET set, unsigned char *from_saved_mode,
+		    enum machine_mode *save_mode, int *from_saved_pseudo,
+		    int *save_pseudo)
+{
+  int regno;
+
+  n_regs_saved = 0;
+  COPY_HARD_REG_SET (hard_regs_saved, set);
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (TEST_HARD_REG_BIT (set, regno))
+      {
+	n_regs_saved++;
+	save_mode[regno] = from_saved_mode[regno];
+	save_pseudo[regno] = from_saved_pseudo[regno];
+      }
+    else
+      {
+	save_mode[regno] = VOIDmode;
+	save_pseudo[regno] = -1;
+      }
+}
+
 
+
 /* Find the places where hard regs are live across calls and save them.  */
 
 void
 save_call_clobbered_regs (void)
 {
-  struct insn_chain *chain, *next;
-  enum machine_mode save_mode [FIRST_PSEUDO_REGISTER];
-
+  unsigned int regno;
   /* Computed in mark_set_regs, holds all registers set by the current
      instruction.  */
-  HARD_REG_SET this_insn_sets;
+  HARD_REG_SET this_insn_sets, hard_regs_to_save, saved;
+  struct insn_chain *chain, *last, *next, *prev, *last_restore_chain, *where;
+  struct bb_info *bb_info;
+  enum machine_mode save_mode[FIRST_PSEUDO_REGISTER];
+  loop_p loop;
+  loop_iterator li;
+  int save_pseudo[FIRST_PSEUDO_REGISTER];
+  int free_pseudo[FIRST_PSEUDO_REGISTER];
+  bool do_placement_opt_p = 0 /* flag_ira && optimize */;
+
+  if (do_placement_opt_p)
+    {
+      /* Do global analysis for better placement of spill code. */
+      alloc_aux_for_blocks (sizeof (struct bb_info));
+      FOR_EACH_LOOP (li, loop, 0)
+	{
+	  loop->aux = xmalloc (sizeof (struct loop_info));
+	  CLEAR_HARD_REG_SET (LOOP_INFO (loop)->mentioned_regs);
+	}
+      memset (BB_INFO (ENTRY_BLOCK_PTR), 0, sizeof (struct bb_info));
+      memset (BB_INFO (EXIT_BLOCK_PTR), 0, sizeof (struct bb_info));
+      make_global_save_analysis ();
+    }
 
   CLEAR_HARD_REG_SET (hard_regs_saved);
   n_regs_saved = 0;
 
+  if (do_placement_opt_p && reload_insn_chain != NULL)
+    {
+      bb_info = BB_INFO_BY_INDEX (reload_insn_chain->block);
+      set_hard_reg_saved (bb_info->restore_in,
+			  bb_info->restore_in_mode, save_mode,
+			  bb_info->restore_in_pseudo, save_pseudo);
+    }
+
+  last = NULL;
   for (chain = reload_insn_chain; chain != 0; chain = next)
     {
       rtx insn = chain->insn;
       enum rtx_code code = GET_CODE (insn);
 
+      last = chain;
       next = chain->next;
 
-      gcc_assert (!chain->is_caller_save_insn);
-
       if (INSN_P (insn))
 	{
-	  /* If some registers have been saved, see if INSN references
-	     any of them.  We must restore them before the insn if so.  */
-
 	  if (n_regs_saved)
 	    {
-	      int regno;
-
-	      if (code == JUMP_INSN)
+	      if (!do_placement_opt_p && code == JUMP_INSN)
 		/* Restore all registers if this is a JUMP_INSN.  */
 		COPY_HARD_REG_SET (referenced_regs, hard_regs_saved);
 	      else
 		{
 		  CLEAR_HARD_REG_SET (referenced_regs);
-		  mark_referenced_regs (PATTERN (insn));
+		  CLEAR_HARD_REG_SET (modified_regs);
+		  mark_referenced_regs (PATTERN (insn), FALSE);
 		  AND_HARD_REG_SET (referenced_regs, hard_regs_saved);
 		}
 
+	      /* If some registers have been saved, see if INSN
+		 references any of them.  We must restore them before
+		 the insn if so.  */
+
 	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
 		if (TEST_HARD_REG_BIT (referenced_regs, regno))
-		  regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS, save_mode);
+		  {
+		    unsigned int before = regno;
+		    
+		    regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS,
+					     save_mode, save_pseudo);
+		    if (do_placement_opt_p)
+		      {
+			gcc_assert (before == regno);
+			save_mode[before] = VOIDmode;
+			save_pseudo[before] = -1;
+		      }
+		  }
 	    }
 
 	  if (code == CALL_INSN
 	      && ! SIBLING_CALL_P (insn)
 	      && ! find_reg_note (insn, REG_NORETURN, NULL))
 	    {
-	      unsigned regno;
-	      HARD_REG_SET hard_regs_to_save;
+	      HARD_REG_SET used_regs;
 	      reg_set_iterator rsi;
 
 	      /* Use the register life information in CHAIN to compute which
@@ -447,10 +1803,13 @@ save_call_clobbered_regs (void)
 				       &chain->live_throughout);
 	      /* Save hard registers always in the widest mode available.  */
 	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-		if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
-		  save_mode [regno] = regno_save_mode [regno][1];
-		else
-		  save_mode [regno] = VOIDmode;
+		{
+		  if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+		    save_mode[regno] = regno_save_mode[regno][1];
+		  else
+		    save_mode[regno] = VOIDmode;
+		  save_pseudo[regno] = -1;
+		}
 
 	      /* Look through all live pseudos, mark their hard registers
 		 and choose proper mode for saving.  */
@@ -461,15 +1820,23 @@ save_call_clobbered_regs (void)
 		  int nregs;
 		  enum machine_mode mode;
 
+		  /* Remember live_throughout can contain spilled
+		     registers when IRA is used.  */
+		  if (flag_ira && optimize && r < 0)
+		    continue;
 		  gcc_assert (r >= 0);
+
 		  nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
 		  mode = HARD_REGNO_CALLER_SAVE_MODE
-		    (r, nregs, PSEUDO_REGNO_MODE (regno));
+		         (r, nregs, PSEUDO_REGNO_MODE (regno));
 		  if (GET_MODE_BITSIZE (mode)
 		      > GET_MODE_BITSIZE (save_mode[r]))
 		    save_mode[r] = mode;
 		  while (nregs-- > 0)
-		    SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
+		    {
+		      SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
+		      save_pseudo[r + nregs] = regno;
+		    }
 		}
 
 	      /* Record all registers set in this call insn.  These don't need
@@ -483,12 +1850,21 @@ save_call_clobbered_regs (void)
 	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, call_fixed_reg_set);
 	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, this_insn_sets);
 	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
-	      AND_HARD_REG_SET (hard_regs_to_save, call_used_reg_set);
-
-	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-		if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
-		  regno += insert_save (chain, 1, regno, &hard_regs_to_save, save_mode);
+	      COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+	      AND_HARD_REG_SET (hard_regs_to_save, used_regs);
 
+	      if (do_placement_opt_p)
+		IOR_HARD_REG_SET (hard_regs_saved, hard_regs_to_save);
+	      else
+		{
+		  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+		    if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+		      regno += insert_save (chain, 1, regno,
+					    &hard_regs_to_save, save_mode,
+					    save_pseudo);
+		  
+		}
+	     
 	      /* Must recompute n_regs_saved.  */
 	      n_regs_saved = 0;
 	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
@@ -497,27 +1873,308 @@ save_call_clobbered_regs (void)
 	    }
 	}
 
-      if (chain->next == 0 || chain->next->block > chain->block)
+      if (chain->next == 0 || chain->next->block != chain->block)
 	{
-	  int regno;
+	  struct bb_info *next_bb_info;
+
+	  next_bb_info = (chain->next != NULL
+			  ? BB_INFO_BY_INDEX (chain->next->block) : NULL);
+
 	  /* At the end of the basic block, we must restore any registers that
 	     remain saved.  If the last insn in the block is a JUMP_INSN, put
 	     the restore before the insn, otherwise, put it after the insn.  */
 
+	  if (do_placement_opt_p)
+	    set_hard_reg_saved
+	      (BB_INFO_BY_INDEX (chain->block)->restore_here,
+	       BB_INFO_BY_INDEX (chain->block)->restore_out_mode, save_mode,
+	       BB_INFO_BY_INDEX (chain->block)->restore_out_pseudo,
+	       save_pseudo);
+
 	  if (n_regs_saved)
 	    for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
 	      if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
-		regno += insert_restore (chain, JUMP_P (insn),
-					 regno, MOVE_MAX_WORDS, save_mode);
+		{
+		  unsigned int before = regno;
+
+		  regno += insert_restore (chain, JUMP_P (insn),
+					   regno, MOVE_MAX_WORDS, save_mode,
+					   save_pseudo);
+		  gcc_assert (before == regno);
+		  save_mode[before] = VOIDmode;
+		  save_pseudo[before] = -1;
+		}
+
+	  if (do_placement_opt_p && next_bb_info != NULL)
+	    set_hard_reg_saved (next_bb_info->restore_in,
+				next_bb_info->restore_in_mode, save_mode,
+				next_bb_info->restore_in_pseudo, save_pseudo);
+
+	}
+    }
+
+  if (!do_placement_opt_p)
+    return;
+
+  CLEAR_HARD_REG_SET (hard_regs_to_save);
+  n_regs_saved = 0;
+  last_restore_chain = NULL;
+  
+  if (last == NULL)
+    CLEAR_HARD_REG_SET (saved);
+  else
+    {
+      bb_info = BB_INFO_BY_INDEX (last->block);
+      set_hard_reg_saved (bb_info->save_out,
+			  bb_info->save_out_mode, save_mode,
+			  bb_info->save_out_pseudo, save_pseudo);
+      COPY_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
+      COPY_HARD_REG_SET (saved, bb_info->free_out);
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+	if (!TEST_HARD_REG_BIT (saved, regno))
+	  free_pseudo[regno] = -1;
+	else
+	  {
+	    if (TEST_HARD_REG_BIT (bb_info->save_out, regno))
+	      free_pseudo [regno] = bb_info->save_out_pseudo [regno];
+	    else
+	      {
+		gcc_assert (TEST_HARD_REG_BIT (bb_info->restore_out, regno));
+		free_pseudo [regno] = bb_info->restore_out_pseudo [regno];
+	      }
+	  }
+    }
+  for (chain = last; chain != 0; chain = prev)
+    {
+      rtx insn = chain->insn;
+      enum rtx_code code = GET_CODE (insn);
+      
+      prev = chain->prev;
+      
+      if (INSN_P (insn))
+	{
+	  bb_info = BB_INFO_BY_INDEX (chain->block);
+	  
+	  CLEAR_HARD_REG_SET (referenced_regs);
+	  CLEAR_HARD_REG_SET (modified_regs);
+	  mark_referenced_regs (PATTERN (insn), FALSE);
+	  AND_HARD_REG_SET (modified_regs, hard_regs_to_save);
+	  AND_COMPL_HARD_REG_SET (saved, referenced_regs);
+	  AND_COMPL_HARD_REG_SET (saved, modified_regs);
+	  
+	  if (chain->is_caller_save_insn)
+	    {
+	      if (last_restore_chain == NULL)
+		last_restore_chain = chain;
+	    }
+	  else
+	    {
+	      /* If some registers have been saved, see if INSN
+		 references any of them.  We must restore them before
+		 the insn if so.  */
+	      
+	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+		if (TEST_HARD_REG_BIT (modified_regs, regno))
+		  {
+		    unsigned int before = regno;
+		    
+		    /* We should put save insns before restore insns
+		       between the two calls because the same stack
+		       slot for different hard registers can be used
+		       for restoring in the first call and saving for
+		       the second call.  */
+		    regno += insert_save (last_restore_chain != NULL
+					  ? last_restore_chain : chain,
+					  last_restore_chain == NULL
+					  && JUMP_P (chain->insn),
+					  regno, &hard_regs_to_save,
+					  save_mode, save_pseudo);
+		    gcc_assert (before == regno);
+
+		    CLEAR_HARD_REG_BIT (saved, regno);
+		    CLEAR_HARD_REG_BIT (hard_regs_to_save, regno);
+		    save_mode[before] = VOIDmode;
+		    save_pseudo[before] = -1;
+		    free_pseudo[before] = -1;
+		  }
+	    }
+
+	  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+	    if (TEST_HARD_REG_BIT (saved, regno) && free_pseudo[regno] >= 0)
+	      SET_REGNO_REG_SET (&chain->saved, free_pseudo[regno]);
+	  if (chain->is_caller_save_insn && chain->saved_pseudo_regno >= 0)
+	    {
+	      int i;
+	      enum machine_mode mode;
+
+	      mode = GET_MODE (regno_reg_rtx[chain->saved_pseudo_regno]);
+	      regno = reg_renumber[chain->saved_pseudo_regno];
+	      add_to_hard_reg_set (&saved, mode, regno);
+	      for (i = hard_regno_nregs[regno][mode] - 1; i >= 0; i--)
+		free_pseudo[regno + i] = chain->saved_pseudo_regno;
+	    }
+	  if (code == CALL_INSN
+	      && ! SIBLING_CALL_P (insn)
+	      && ! find_reg_note (insn, REG_NORETURN, NULL))
+	    {
+	      HARD_REG_SET used_regs;
+	      reg_set_iterator rsi;
+	      
+	      last_restore_chain = NULL;
+	      
+	      /* Use the register life information in CHAIN to
+		 compute which regs are live during the call.  */
+	      REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
+				       &chain->live_throughout);
+	      /* Save hard registers always in the widest mode
+		 available.  */
+	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+		{
+		  if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+		    {
+		      CLEAR_HARD_REG_SET (this_insn_sets);
+		      note_stores (PATTERN (insn), mark_set_regs,
+				   &this_insn_sets);
+		      save_mode[regno] = regno_save_mode[regno][1];
+		    }
+		  else
+		    save_mode[regno] = VOIDmode;
+		  save_pseudo[regno] = -1;
+		}
+	      
+	      /* Look through all live pseudos, mark their hard
+		 registers and choose proper mode for saving.  */
+	      EXECUTE_IF_SET_IN_REG_SET
+		(&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
+		{
+		  int r = reg_renumber[regno];
+		  int nregs;
+		  enum machine_mode mode;
+		  
+		  /* Remember live_throughout can contain spilled
+		     registers when IRA is used.  */
+		  if (flag_ira && r < 0)
+		    continue;
+		  gcc_assert (r >= 0);
+
+		  nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+		  mode = HARD_REGNO_CALLER_SAVE_MODE
+		         (r, nregs, PSEUDO_REGNO_MODE (regno));
+		  if (GET_MODE_BITSIZE (mode)
+		      > GET_MODE_BITSIZE (save_mode[r]))
+		    save_mode[r] = mode;
+		  while (nregs-- > 0)
+		    {
+		      SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
+		      save_pseudo[r + nregs] = regno;
+		      free_pseudo[r + nregs] = regno;
+		    }
+		}
+	      
+	      /* Record all registers set in this call insn.  These
+		 don't need to be saved.  N.B. the call insn might set
+		 a subreg of a multi-hard-reg pseudo; then the pseudo
+		 is considered live during the call, but the subreg
+		 that is set isn't.  */
+	      CLEAR_HARD_REG_SET (this_insn_sets);
+	      note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
+	      
+	      /* Compute which hard regs must be saved before this call.  */
+	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, call_fixed_reg_set);
+	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, this_insn_sets);
+	      COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+	      AND_HARD_REG_SET (hard_regs_to_save, used_regs);
+	      COPY_HARD_REG_SET (saved, hard_regs_to_save);
+	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+		if (!TEST_HARD_REG_BIT (saved, regno))
+		  {
+		    free_pseudo[regno] = -1;
+		    save_pseudo[regno] = -1;
+		    save_mode[regno] = VOIDmode;
+		  }
+	    }
 	}
+      
+      if (chain->prev == 0 || chain->prev->block != chain->block)
+	{
+	  struct bb_info *prev_bb_info;
+	  
+	  prev_bb_info = (chain->prev != NULL
+			  ? BB_INFO_BY_INDEX (chain->prev->block) : NULL);
+	  
+	  /* At the start of the basic block, we must save any
+	     registers from save_here.  */
+	  
+	  set_hard_reg_saved
+	    (BB_INFO_BY_INDEX (chain->block)->save_here,
+	     BB_INFO_BY_INDEX (chain->block)->save_in_mode, save_mode,
+	     BB_INFO_BY_INDEX (chain->block)->save_in_pseudo, save_pseudo);
+	  COPY_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
+	  
+	  where = (last_restore_chain != NULL
+		   ? last_restore_chain->next : chain);
+	  /* An addr_vec is placed outside any basic block but its
+	     chain has the same block as the block of subsequent insn.
+	     So skip to the real start of the basic block.  */
+	  if (GET_CODE (where->insn) == CODE_LABEL && where->next != NULL
+	      && JUMP_P (where->next->insn)
+	      && (GET_CODE (PATTERN (where->next->insn)) == ADDR_DIFF_VEC
+		  || GET_CODE (PATTERN (where->next->insn)) == ADDR_VEC)
+	      && where->next->next != NULL)
+	    where = where->next->next;
+	  
+	  if (!hard_reg_set_empty_p (hard_regs_to_save))
+	    for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+	      if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+		{
+		  unsigned int before = regno;
+		  
+		  regno += insert_save (where, INSN_P (where->insn), regno,
+					&hard_regs_to_save, save_mode,
+					save_pseudo);
+		  gcc_assert (before == regno);
+		  save_mode[before] = VOIDmode;
+		  save_pseudo[before] = -1;
+		}
+	  
+	  if (prev_bb_info != NULL)
+	    {
+	      last_restore_chain = NULL;
+	      set_hard_reg_saved (prev_bb_info->save_out,
+				  prev_bb_info->save_out_mode, save_mode,
+				  prev_bb_info->save_out_pseudo, save_pseudo);
+	      COPY_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
+	      COPY_HARD_REG_SET (saved, prev_bb_info->free_out);
+	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+		if (!TEST_HARD_REG_BIT (saved, regno))
+		  free_pseudo[regno] = -1;
+		else
+		  {
+		    if (TEST_HARD_REG_BIT (prev_bb_info->save_out, regno))
+		      free_pseudo [regno]
+			= prev_bb_info->save_out_pseudo [regno];
+		    else
+		      {
+			gcc_assert (TEST_HARD_REG_BIT (prev_bb_info->restore_out, regno));
+			free_pseudo [regno]
+			  = prev_bb_info->restore_out_pseudo [regno];
+		      }
+		  }
+	    }
+	}
+    }
+      
+  FOR_EACH_LOOP (li, loop, 0)
+    {
+      free (loop->aux);
     }
+  if (flag_ira && optimize)
+    free_aux_for_blocks ();
 }
 
-/* Here from note_stores, or directly from save_call_clobbered_regs, when
-   an insn stores a value in a register.
-   Set the proper bit or bits in this_insn_sets.  All pseudos that have
-   been assigned hard regs have had their register number changed already,
-   so we can ignore pseudos.  */
+/* Here from note_stores, or directly from save_call_clobbered_regs,
+   when an insn stores a value in a register.  Set the proper bit or
+   bits in this_insn_sets.  */
 static void
 mark_set_regs (rtx reg, const_rtx setter ATTRIBUTE_UNUSED, void *data)
 {
@@ -527,16 +2184,34 @@ mark_set_regs (rtx reg, const_rtx setter
   if (GET_CODE (reg) == SUBREG)
     {
       rtx inner = SUBREG_REG (reg);
-      if (!REG_P (inner) || REGNO (inner) >= FIRST_PSEUDO_REGISTER)
+      if (!REG_P (inner))
 	return;
-      regno = subreg_regno (reg);
-      endregno = regno + subreg_nregs (reg);
+      if ((regno = REGNO (inner)) >= FIRST_PSEUDO_REGISTER)
+	{
+	  if (reg_renumber[regno] < 0)
+	    return;
+	  regno = reg_renumber[regno];
+	  endregno
+	    = hard_regno_nregs[regno][PSEUDO_REGNO_MODE (REGNO (inner))];
+	}
+      else
+	{
+	  regno = subreg_regno (reg);
+	  endregno = regno + subreg_nregs (reg);
+	}
     }
-  else if (REG_P (reg)
-	   && REGNO (reg) < FIRST_PSEUDO_REGISTER)
+  else if (REG_P (reg))
     {
-      regno = REGNO (reg);
-      endregno = END_HARD_REGNO (reg);
+      if ((regno = REGNO (reg)) < FIRST_PSEUDO_REGISTER)
+	endregno = END_HARD_REGNO (reg);
+      else
+	{
+	  if (reg_renumber[regno] < 0)
+	    return;
+	  regno = reg_renumber[regno];
+	  endregno
+	    = hard_regno_nregs[regno][PSEUDO_REGNO_MODE (REGNO (reg))];
+	}
     }
   else
     return;
@@ -583,72 +2258,93 @@ add_stored_regs (rtx reg, const_rtx sett
     SET_REGNO_REG_SET ((regset) data, i);
 }
 
-/* Walk X and record all referenced registers in REFERENCED_REGS.  */
+/* Walk X and record all referenced registers in REFERENCED_REG and
+   modified registers in MODIFIED_REGS.  */
 static void
-mark_referenced_regs (rtx x)
+mark_referenced_regs (rtx x, int set_p)
 {
-  enum rtx_code code = GET_CODE (x);
+  enum rtx_code code;
   const char *fmt;
   int i, j;
-
-  if (code == SET)
-    mark_referenced_regs (SET_SRC (x));
-  if (code == SET || code == CLOBBER)
+  int stop_p;
+  
+  for (stop_p = FALSE; !stop_p; )
     {
-      x = SET_DEST (x);
+      while (GET_CODE (x) == STRICT_LOW_PART || GET_CODE (x) == ZERO_EXTRACT)
+	x = XEXP (x, 0);
       code = GET_CODE (x);
-      if ((code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
-	  || code == PC || code == CC0
-	  || (code == SUBREG && REG_P (SUBREG_REG (x))
-	      && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
-	      /* If we're setting only part of a multi-word register,
-		 we shall mark it as referenced, because the words
-		 that are not being set should be restored.  */
-	      && ((GET_MODE_SIZE (GET_MODE (x))
-		   >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-		  || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
-		      <= UNITS_PER_WORD))))
-	return;
-    }
-  if (code == MEM || code == SUBREG)
-    {
-      x = XEXP (x, 0);
-      code = GET_CODE (x);
-    }
-
-  if (code == REG)
-    {
-      int regno = REGNO (x);
-      int hardregno = (regno < FIRST_PSEUDO_REGISTER ? regno
-		       : reg_renumber[regno]);
-
-      if (hardregno >= 0)
-	add_to_hard_reg_set (&referenced_regs, GET_MODE (x), hardregno);
-      /* If this is a pseudo that did not get a hard register, scan its
-	 memory location, since it might involve the use of another
-	 register, which might be saved.  */
-      else if (reg_equiv_mem[regno] != 0)
-	mark_referenced_regs (XEXP (reg_equiv_mem[regno], 0));
-      else if (reg_equiv_address[regno] != 0)
-	mark_referenced_regs (reg_equiv_address[regno]);
-      return;
-    }
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e')
-	mark_referenced_regs (XEXP (x, i));
-      else if (fmt[i] == 'E')
-	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-	  mark_referenced_regs (XVECEXP (x, i, j));
+      switch (code)
+	{
+	case SET:
+	  gcc_assert (!set_p);
+	  mark_referenced_regs (SET_DEST (x), TRUE);
+	  x = SET_SRC (x);
+	  break;
+	case CLOBBER:
+	  mark_referenced_regs (SET_DEST (x), TRUE);
+	  return;
+	case PRE_INC:
+	case POST_INC:
+	case PRE_DEC:
+	case POST_DEC:
+	  gcc_assert (!set_p);
+	  x = XEXP (x, 0);
+	  mark_referenced_regs (x, TRUE);
+	  break;
+	case PRE_MODIFY:
+	case POST_MODIFY:
+	  set_p = FALSE;
+	  mark_referenced_regs (XEXP (x, 0), FALSE);
+	  mark_referenced_regs (XEXP (x, 0), TRUE);
+	  x = XEXP (x, 1);
+	  mark_referenced_regs (x, FALSE);
+	  break;
+	case SUBREG:
+	  x = SUBREG_REG (x);
+	  break;
+	case REG:
+	  {
+	    int regno = REGNO (x);
+	    int hardregno = (regno < FIRST_PSEUDO_REGISTER ? regno
+			     : reg_renumber[regno]);
+	    
+	    if (hardregno >= 0)
+	      {
+		if (set_p)
+		  add_to_hard_reg_set (&modified_regs, GET_MODE (x), hardregno);
+		add_to_hard_reg_set (&referenced_regs, GET_MODE (x), hardregno);
+	      }
+	    /* If this is a pseudo that did not get a hard register, scan
+	       its memory location, since it might involve the use of
+	       another register, which might be saved.  */
+	    else if (reg_equiv_mem[regno] != 0)
+	      mark_referenced_regs (XEXP (reg_equiv_mem[regno], 0), set_p);
+	    else if (reg_equiv_address[regno] != 0)
+	      mark_referenced_regs (reg_equiv_address[regno], set_p);
+	    return;
+	  }
+	default:
+	  fmt = GET_RTX_FORMAT (code);
+	  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+	    {
+	      if (fmt[i] == 'e')
+		mark_referenced_regs (XEXP (x, i), FALSE);
+	      else if (fmt[i] == 'E')
+		for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+		  mark_referenced_regs (XVECEXP (x, i, j), FALSE);
+	    }
+	  stop_p = TRUE;
+	  break;
+	}
     }
 }
 
-/* Insert a sequence of insns to restore.  Place these insns in front of
-   CHAIN if BEFORE_P is nonzero, behind the insn otherwise.  MAXRESTORE is
-   the maximum number of registers which should be restored during this call.
-   It should never be less than 1 since we only work with entire registers.
+/* Insert a sequence of insns to restore.  Place these insns in front
+   of CHAIN if BEFORE_P is nonzero, behind the insn otherwise.
+   MAXRESTORE is the maximum number of registers which should be
+   restored during this call.  It should never be less than 1 since we
+   only work with entire registers.  SAVE_PSEUDO maps hard registers
+   into the corresponding pseudos.
 
    Note that we have verified in init_caller_save that we can do this
    with a simple SET, so use it.  Set INSN_CODE to what we save there
@@ -660,7 +2356,8 @@ mark_referenced_regs (rtx x)
 
 static int
 insert_restore (struct insn_chain *chain, int before_p, int regno,
-		int maxrestore, enum machine_mode *save_mode)
+		int maxrestore, enum machine_mode *save_mode,
+		int *save_pseudo)
 {
   int i, k;
   rtx pat = NULL_RTX;
@@ -703,23 +2400,31 @@ insert_restore (struct insn_chain *chain
       break;
     }
 
-  mem = regno_save_mem [regno][numregs];
-  if (save_mode [regno] != VOIDmode
-      && save_mode [regno] != GET_MODE (mem)
-      && numregs == (unsigned int) hard_regno_nregs[regno][save_mode [regno]])
-    mem = adjust_address (mem, save_mode[regno], 0);
+  mem = regno_save_mem[regno][numregs];
+  if (save_mode[regno] != VOIDmode
+      && save_mode[regno] != GET_MODE (mem)
+      && numregs == (unsigned int) hard_regno_nregs[regno][save_mode[regno]]
+      && reg_save_code (regno, save_mode[regno]) >= 0)
+    mem = adjust_address_nv (mem, save_mode[regno], 0);
   else
     mem = copy_rtx (mem);
 
   /* Verify that the alignment of spill space is equal to or greater
      than required.  */
-  gcc_assert (GET_MODE_ALIGNMENT (GET_MODE (mem)) <= MEM_ALIGN (mem));
+  gcc_assert (MIN (MAX_SUPPORTED_STACK_ALIGNMENT,
+		   GET_MODE_ALIGNMENT (GET_MODE (mem))) <= MEM_ALIGN (mem));
 
   pat = gen_rtx_SET (VOIDmode,
 		     gen_rtx_REG (GET_MODE (mem),
 				  regno), mem);
   code = reg_restore_code (regno, GET_MODE (mem));
   new_chain = insert_one_insn (chain, before_p, code, pat);
+  new_chain->saved_pseudo_regno = save_pseudo[regno];
+
+  if (dump_file != NULL)
+    fprintf (dump_file, "inserting restore insn %u for pseudo %d %s %u\n",
+	     INSN_UID (new_chain->insn), save_pseudo[regno],
+	     before_p ? "before" : "after", INSN_UID (chain->insn));
 
   /* Clear status for all registers we restored.  */
   for (k = 0; k < i; k++)
@@ -737,7 +2442,8 @@ insert_restore (struct insn_chain *chain
 
 static int
 insert_save (struct insn_chain *chain, int before_p, int regno,
-	     HARD_REG_SET (*to_save), enum machine_mode *save_mode)
+	     HARD_REG_SET (*to_save), enum machine_mode *save_mode,
+	     int *save_pseudo)
 {
   int i;
   unsigned int k;
@@ -780,23 +2486,31 @@ insert_save (struct insn_chain *chain, i
       break;
     }
 
-  mem = regno_save_mem [regno][numregs];
-  if (save_mode [regno] != VOIDmode
-      && save_mode [regno] != GET_MODE (mem)
-      && numregs == (unsigned int) hard_regno_nregs[regno][save_mode [regno]])
-    mem = adjust_address (mem, save_mode[regno], 0);
+  mem = regno_save_mem[regno][numregs];
+  if (save_mode[regno] != VOIDmode
+      && save_mode[regno] != GET_MODE (mem)
+      && numregs == (unsigned int) hard_regno_nregs[regno][save_mode[regno]]
+      && reg_save_code (regno, save_mode[regno]) >= 0)
+    mem = adjust_address_nv (mem, save_mode[regno], 0);
   else
     mem = copy_rtx (mem);
 
   /* Verify that the alignment of spill space is equal to or greater
      than required.  */
-  gcc_assert (GET_MODE_ALIGNMENT (GET_MODE (mem)) <= MEM_ALIGN (mem));
+  gcc_assert (MIN (MAX_SUPPORTED_STACK_ALIGNMENT,
+		   GET_MODE_ALIGNMENT (GET_MODE (mem))) <= MEM_ALIGN (mem));
 
   pat = gen_rtx_SET (VOIDmode, mem,
 		     gen_rtx_REG (GET_MODE (mem),
 				  regno));
   code = reg_save_code (regno, GET_MODE (mem));
   new_chain = insert_one_insn (chain, before_p, code, pat);
+  new_chain->saved_pseudo_regno = save_pseudo[regno];
+
+  if (dump_file != NULL)
+    fprintf (dump_file, "inserting save insn %u for pseudo %d %s %u\n",
+	     INSN_UID (new_chain->insn), save_pseudo[regno],
+	     before_p ? "before" : "after", INSN_UID (chain->insn));
 
   /* Set hard_regs_saved and dead_or_set for all the registers we saved.  */
   for (k = 0; k < numregs; k++)
@@ -909,15 +2623,23 @@ insert_one_insn (struct insn_chain *chai
 	new_chain->next->prev = new_chain;
       chain->next = new_chain;
       new_chain->prev = chain;
-      new_chain->insn = emit_insn_after (pat, insn);
+      if (GET_CODE (insn) != CODE_LABEL)
+	new_chain->insn = emit_insn_after (pat, insn);
+      else
+	{
+	  /* Put the insn after bb note in a empty basic block.  */
+	  gcc_assert (NEXT_INSN (insn) && NOTE_P (NEXT_INSN (insn)));
+	  new_chain->insn = emit_insn_after (pat, NEXT_INSN (insn));
+	}
       /* ??? It would be nice if we could exclude the already / still saved
 	 registers from the live sets, and observe REG_UNUSED notes.  */
       COPY_REG_SET (&new_chain->live_throughout, &chain->live_throughout);
       /* Registers that are set in CHAIN->INSN live in the new insn.
 	 (Unless there is a REG_UNUSED note for them, but we don't
 	  look for them here.) */
-      note_stores (PATTERN (chain->insn), add_stored_regs,
-		   &new_chain->live_throughout);
+      if (INSN_P (chain->insn))
+	note_stores (PATTERN (chain->insn), add_stored_regs,
+		     &new_chain->live_throughout);
       CLEAR_REG_SET (&new_chain->dead_or_set);
       if (chain->insn == BB_END (BASIC_BLOCK (chain->block)))
 	BB_END (BASIC_BLOCK (chain->block)) = new_chain->insn;
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/global.c ./global.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/global.c	2008-08-21 21:16:45.000000000 -0400
+++ ./global.c	2008-08-25 11:35:41.000000000 -0400
@@ -188,7 +188,7 @@ compute_regs_asm_clobbered (char *regs_a
 
 /* All registers that can be eliminated.  */
 
-static HARD_REG_SET eliminable_regset;
+HARD_REG_SET eliminable_regset;
 
 static int regno_compare (const void *, const void *);
 static int allocno_compare (const void *, const void *);
@@ -197,7 +197,6 @@ static void prune_preferences (void);
 static void set_preferences (void);
 static void find_reg (int, HARD_REG_SET, int, int, int);
 static void dump_conflicts (FILE *);
-static void build_insn_chain (void);
 
 
 /* Look through the list of eliminable registers.  Set ELIM_SET to the
@@ -1355,7 +1366,8 @@ mark_elimination (int from, int to)
 
   FOR_EACH_BB (bb)
     {
-      regset r = DF_LIVE_IN (bb);
+      /* We don't use LIVE info in IRA.  */
+      regset r = (flag_ira ? DF_LR_IN (bb) : DF_LIVE_IN (bb));
       if (REGNO_REG_SET_P (r, from))
 	{
 	  CLEAR_REGNO_REG_SET (r, from);
@@ -1372,6 +1384,7 @@ print_insn_chain (FILE *file, struct ins
   fprintf (file, "insn=%d, ", INSN_UID(c->insn));
   bitmap_print (file, &c->live_throughout, "live_throughout: ", ", ");
   bitmap_print (file, &c->dead_or_set, "dead_or_set: ", "\n");
+  bitmap_print (file, &c->saved, "saved: ", "\n");
 }
 
 
@@ -1385,11 +1398,21 @@ print_insn_chains (FILE *file)
     print_insn_chain (file, c);
 }
 
+/* Return true if pseudo REGNO should be added to set live_throughout
+   or dead_or_set of the insn chains for reload consideration.  */
+
+static bool
+pseudo_for_reload_consideration_p (int regno)
+{
+  /* Consider spilled pseudos too for IRA because they still have a
+     chance to get hard-registers in the reload when IRA is used.  */
+  return reg_renumber[regno] >= 0 || (flag_ira && optimize);
+}
 
 /* Walk the insns of the current function and build reload_insn_chain,
    and record register life information.  */
 
-static void
+void
 build_insn_chain (void)
 {
   unsigned int i;
@@ -1412,7 +1435,6 @@ build_insn_chain (void)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (TEST_HARD_REG_BIT (eliminable_regset, i))
       bitmap_set_bit (elim_regset, i);
-
   FOR_EACH_BB_REVERSE (bb)
     {
       bitmap_iterator bi;
@@ -1430,7 +1452,7 @@ build_insn_chain (void)
 
       EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), FIRST_PSEUDO_REGISTER, i, bi)
 	{
-	  if (reg_renumber[i] >= 0)
+	  if (pseudo_for_reload_consideration_p (i))
 	    bitmap_set_bit (live_relevant_regs, i);
 	}
 
@@ -1467,11 +1489,13 @@ build_insn_chain (void)
 			    if (!fixed_regs[regno])
 			      bitmap_set_bit (&c->dead_or_set, regno);
 			  }
-			else if (reg_renumber[regno] >= 0)
+			else if (pseudo_for_reload_consideration_p (regno))
 			  bitmap_set_bit (&c->dead_or_set, regno);
 		      }
 
-		    if ((regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+		    if ((regno < FIRST_PSEUDO_REGISTER
+			 || reg_renumber[regno] >= 0
+			 || (flag_ira && optimize))
 			&& (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
 		      {
 			rtx reg = DF_REF_REG (def);
@@ -1567,11 +1591,12 @@ build_insn_chain (void)
 			    if (!fixed_regs[regno])
 			      bitmap_set_bit (&c->dead_or_set, regno);
 			  }
-			else if (reg_renumber[regno] >= 0)
+			else if (pseudo_for_reload_consideration_p (regno))
 			  bitmap_set_bit (&c->dead_or_set, regno);
 		      }
 		    
-		    if (regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+		    if (regno < FIRST_PSEUDO_REGISTER
+			|| pseudo_for_reload_consideration_p (regno))
 		      {
 			if (GET_CODE (reg) == SUBREG
 			    && !DF_REF_FLAGS_IS_SET (use,
@@ -1748,6 +1773,13 @@ dump_global_regs (FILE *file)
   fprintf (file, "\n\n");
 }
 
+
+static bool
+gate_handle_global_alloc (void)
+{
+  return ! flag_ira;
+}
+
 /* Run old register allocator.  Return TRUE if we must exit
    rest_of_compilation upon return.  */
 static unsigned int
@@ -1811,7 +1843,7 @@ struct rtl_opt_pass pass_global_alloc =
  {
   RTL_PASS,
   "greg",                               /* name */
-  NULL,                                 /* gate */
+  gate_handle_global_alloc,             /* gate */
   rest_of_handle_global_alloc,          /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/opts.c ./opts.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/opts.c	2008-08-21 21:16:46.000000000 -0400
+++ ./opts.c	2008-08-25 11:31:49.000000000 -0400
@@ -878,6 +878,11 @@ decode_options (unsigned int argc, const
       flag_section_anchors = 0;
     }
 
+#ifdef IRA_COVER_CLASSES
+  /* Use IRA if it is implemented for the target.  */
+  flag_ira = 1;
+#endif
+
   /* Originally we just set the variables if a particular optimization level,
      but with the advent of being able to change the optimization level for a
      function, we need to reset optimizations.  */
@@ -1119,6 +1124,14 @@ decode_options (unsigned int argc, const
       flag_reorder_blocks = 1;
     }
 
+#ifndef IRA_COVER_CLASSES
+  if (flag_ira)
+    {
+      inform ("-fira does not work on this architecture");
+      flag_ira = 0;
+    }
+#endif
+
   /* Save the current optimization options if this is the first call.  */
   if (first_time_p)
     {
@@ -1970,6 +1983,21 @@ common_handle_option (size_t scode, cons
 	warning (0, "unknown tls-model \"%s\"", arg);
       break;
 
+    case OPT_fira_algorithm_:
+      if (!strcmp (arg, "regional"))
+	flag_ira_algorithm = IRA_ALGORITHM_REGIONAL;
+      else if (!strcmp (arg, "CB"))
+	flag_ira_algorithm = IRA_ALGORITHM_CB;
+      else if (!strcmp (arg, "mixed"))
+	flag_ira_algorithm = IRA_ALGORITHM_MIXED;
+      else
+	warning (0, "unknown ira algorithm \"%s\"", arg);
+      break;
+
+    case OPT_fira_verbose_:
+      flag_ira_verbose = value;
+      break;
+
     case OPT_ftracer:
       flag_tracer_set = true;
       break;
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/timevar.def ./timevar.def
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/timevar.def	2008-08-21 21:16:46.000000000 -0400
+++ ./timevar.def	2008-08-22 18:09:59.000000000 -0400
@@ -179,6 +179,8 @@ DEFTIMEVAR (TV_SMS		     , "sms modulo s
 DEFTIMEVAR (TV_SCHED                 , "scheduling")
 DEFTIMEVAR (TV_LOCAL_ALLOC           , "local alloc")
 DEFTIMEVAR (TV_GLOBAL_ALLOC          , "global alloc")
+DEFTIMEVAR (TV_IRA	   	     , "integrated RA")
+DEFTIMEVAR (TV_RELOAD	   	     , "reload")
 DEFTIMEVAR (TV_RELOAD_CSE_REGS       , "reload CSE regs")
 DEFTIMEVAR (TV_SEQABSTR              , "sequence abstraction")
 DEFTIMEVAR (TV_GCSE_AFTER_RELOAD      , "load CSE after reload")
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/regmove.c ./regmove.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/regmove.c	2008-08-21 21:16:46.000000000 -0400
+++ ./regmove.c	2008-08-22 18:09:59.000000000 -0400
@@ -1117,7 +1117,8 @@ regmove_optimize (rtx f, int nregs)
 
   for (pass = 0; pass <= 2; pass++)
     {
-      if (! flag_regmove && pass >= flag_expensive_optimizations)
+      /* We need fewer optimizations for IRA.  */
+      if ((! flag_regmove || flag_ira) && pass >= flag_expensive_optimizations)
 	goto done;
 
       if (dump_file)
@@ -1165,7 +1166,9 @@ regmove_optimize (rtx f, int nregs)
 		    }
 		}
 	    }
-	  if (! flag_regmove)
+
+	  /* All optimizations important for IRA have been done.  */
+	  if (! flag_regmove || flag_ira)
 	    continue;
 
 	  if (! find_matches (insn, &match))
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/hard-reg-set.h ./hard-reg-set.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/hard-reg-set.h	2008-08-21 21:16:46.000000000 -0400
+++ ./hard-reg-set.h	2008-08-22 18:09:59.000000000 -0400
@@ -538,6 +538,11 @@ extern char global_regs[FIRST_PSEUDO_REG
 
 extern HARD_REG_SET regs_invalidated_by_call;
 
+/* Call used hard registers which can not be saved because there is no
+   insn for this.  */
+
+extern HARD_REG_SET no_caller_save_reg_set;
+
 #ifdef REG_ALLOC_ORDER
 /* Table of register numbers in the order in which to try to use them.  */
 
@@ -556,6 +561,10 @@ extern HARD_REG_SET reg_class_contents[N
 
 extern unsigned int reg_class_size[N_REG_CLASSES];
 
+/* For each reg class, table listing all the classes contained in it.  */
+
+extern enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];
+
 /* For each pair of reg classes,
    a largest reg class contained in their union.  */
 
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/local-alloc.c ./local-alloc.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/local-alloc.c	2008-08-21 21:16:46.000000000 -0400
+++ ./local-alloc.c	2008-08-22 18:09:59.000000000 -0400
@@ -298,7 +298,6 @@ static int equiv_init_movable_p (rtx, in
 static int contains_replace_regs (rtx);
 static int memref_referenced_p (rtx, rtx);
 static int memref_used_between_p (rtx, rtx, rtx);
-static void update_equiv_regs (void);
 static void no_equiv (rtx, const_rtx, void *);
 static void block_alloc (int);
 static int qty_sugg_compare (int, int);
@@ -795,9 +794,11 @@ memref_used_between_p (rtx memref, rtx s
    into the using insn.  If it succeeds, we can eliminate the register
    completely.
 
-   Initialize the REG_EQUIV_INIT array of initializing insns.  */
+   Initialize the REG_EQUIV_INIT array of initializing insns.
 
-static void
+   Return non-zero if jump label rebuilding should be done.  */
+
+int
 update_equiv_regs (void)
 {
   rtx insn;
@@ -1183,6 +1184,8 @@ update_equiv_regs (void)
 		      new_insn = emit_insn_before (PATTERN (equiv_insn), insn);
 		      REG_NOTES (new_insn) = REG_NOTES (equiv_insn);
 		      REG_NOTES (equiv_insn) = 0;
+		      /* Rescan it to process the notes.  */
+		      df_insn_rescan (new_insn);
 
 		      /* Make sure this insn is recognized before
 			 reload begins, otherwise
@@ -1227,6 +1230,7 @@ update_equiv_regs (void)
 
   end_alias_analysis ();
   free (reg_equiv);
+  return recorded_label_ref;
 }
 
 /* Mark REG as having no known equivalence.
@@ -2442,6 +2446,12 @@ find_stack_regs (void)
 }
 #endif
 
+static bool
+gate_handle_local_alloc (void)
+{
+  return ! flag_ira;
+}
+
 /* Run old register allocator.  Return TRUE if we must exit
    rest_of_compilation upon return.  */
 static unsigned int
@@ -2517,7 +2527,7 @@ struct rtl_opt_pass pass_local_alloc =
  {
   RTL_PASS,
   "lreg",                               /* name */
-  NULL,                                 /* gate */
+  gate_handle_local_alloc,              /* gate */
   rest_of_handle_local_alloc,           /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/alias.c ./alias.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/alias.c	2008-08-21 21:16:46.000000000 -0400
+++ ./alias.c	2008-08-22 18:09:59.000000000 -0400
@@ -1975,6 +1975,34 @@ adjust_offset_for_component_ref (tree x,
   return GEN_INT (ioffset);
 }
 
+/* The function returns nonzero if X is an address containg VALUE.  */
+static int
+value_addr_p (rtx x)
+{
+  if (GET_CODE (x) == VALUE)
+    return 1;
+  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == VALUE)
+    return 1;
+  return 0;
+}
+
+/* The function returns nonzero if X is a stack address.  */
+static int
+stack_addr_p (rtx x)
+{
+  if (x == hard_frame_pointer_rtx || x == frame_pointer_rtx
+      || x == arg_pointer_rtx || x == stack_pointer_rtx)
+    return 1;
+  if (GET_CODE (x) == PLUS
+      && (XEXP (x, 0) == hard_frame_pointer_rtx
+	  || XEXP (x, 0) == frame_pointer_rtx
+	  || XEXP (x, 0) == arg_pointer_rtx
+	  || XEXP (x, 0) == stack_pointer_rtx)
+      && CONSTANT_P (XEXP (x, 1)))
+    return 1;
+  return 0;
+}
+
 /* Return nonzero if we can determine the exprs corresponding to memrefs
    X and Y and they do not overlap.  */
 
@@ -1984,9 +2012,27 @@ nonoverlapping_memrefs_p (const_rtx x, c
   tree exprx = MEM_EXPR (x), expry = MEM_EXPR (y);
   rtx rtlx, rtly;
   rtx basex, basey;
+  rtx x_addr, y_addr;
   rtx moffsetx, moffsety;
   HOST_WIDE_INT offsetx = 0, offsety = 0, sizex, sizey, tem;
 
+  if (flag_ira && optimize && reload_completed)
+    {
+      /* We need this code for IRA because of stack slot sharing.  RTL
+	 in decl can be different than RTL used in insns.  It is a
+	 safe code although it can be conservative sometime.  */
+      x_addr = canon_rtx (get_addr (XEXP (x, 0)));
+      y_addr = canon_rtx (get_addr (XEXP (y, 0)));
+      
+      if (value_addr_p (x_addr) || value_addr_p (y_addr))
+	return 0;
+       
+      if (stack_addr_p (x_addr) && stack_addr_p (y_addr)
+	  && memrefs_conflict_p (SIZE_FOR_MODE (y), y_addr,
+				 SIZE_FOR_MODE (x), x_addr, 0))
+	return 0;
+    }
+
   /* Unless both have exprs, we can't tell anything.  */
   if (exprx == 0 || expry == 0)
     return 0;
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/common.opt ./common.opt
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/common.opt	2008-08-21 21:16:46.000000000 -0400
+++ ./common.opt	2008-08-22 21:58:23.000000000 -0400
@@ -649,6 +653,30 @@ Common Report Var(flag_ipa_struct_reorg)
 Perform structure layout optimizations based
 on profiling information.
 
+fira
+Common Report Var(flag_ira) Init(0)
+Use integrated register allocator.
+
+fira-algorithm=
+Common Joined RejectNegative
+-fira-algorithm=[regional|CB|mixed] Set the used IRA algorithm
+
+fira-coalesce
+Common Report Var(flag_ira_coalesce) Init(0)
+Do optimistic coalescing.
+
+fira-share-save-slots
+Common Report Var(flag_ira_share_save_slots) Init(1)
+Share slots for saving different hard registers.
+
+fira-share-spill-slots
+Common Report Var(flag_ira_share_spill_slots) Init(1)
+Share stack slots for spilled pseudo-registers.
+
+fira-verbose=
+Common RejectNegative Joined UInteger
+-fira-verbose=<number> Control IRA's level of diagnostic messages.
+
 fivopts
 Common Report Var(flag_ivopts) Init(1) Optimization
 Optimize induction variables on trees
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/regclass.c ./regclass.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/regclass.c	2008-08-21 21:16:46.000000000 -0400
+++ ./regclass.c	2008-08-22 18:10:01.000000000 -0400
@@ -178,7 +178,7 @@ static enum reg_class reg_class_supercla
 
 /* For each reg class, table listing all the classes contained in it.  */
 
-static enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];
+enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];
 
 /* For each pair of reg classes,
    a largest reg class contained in their union.  */
@@ -211,24 +211,22 @@ bool have_regs_of_mode [MAX_MACHINE_MODE
 
 /* 1 if class does contain register of given mode.  */
 
-static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
-
-typedef unsigned short move_table[N_REG_CLASSES];
+char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
 
 /* Maximum cost of moving from a register in one class to a register in
    another class.  Based on REGISTER_MOVE_COST.  */
 
-static move_table *move_cost[MAX_MACHINE_MODE];
+move_table *move_cost[MAX_MACHINE_MODE];
 
 /* Similar, but here we don't have to move if the first index is a subset
    of the second so in that case the cost is zero.  */
 
-static move_table *may_move_in_cost[MAX_MACHINE_MODE];
+move_table *may_move_in_cost[MAX_MACHINE_MODE];
 
 /* Similar, but here we don't have to move if the first index is a superset
    of the second so in that case the cost is zero.  */
 
-static move_table *may_move_out_cost[MAX_MACHINE_MODE];
+move_table *may_move_out_cost[MAX_MACHINE_MODE];
 
 /* Keep track of the last mode we initialized move costs for.  */
 static int last_mode_for_init_move_cost;
@@ -313,7 +311,7 @@ init_reg_sets (void)
 
 /* Initialize may_move_cost and friends for mode M.  */
 
-static void
+void
 init_move_cost (enum machine_mode m)
 {
   static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES];
@@ -1024,6 +1022,7 @@ reg_preferred_class (int regno)
 {
   if (reg_pref == 0)
     return GENERAL_REGS;
+
   return (enum reg_class) reg_pref[regno].prefclass;
 }
 
@@ -2283,6 +2282,32 @@ auto_inc_dec_reg_p (rtx reg, enum machin
 }
 #endif
 
+
+/* Allocate space for reg info.  */
+void
+allocate_reg_info (void)
+{
+  int size = max_reg_num ();
+
+  gcc_assert (! reg_pref && ! reg_renumber);
+  reg_renumber = XNEWVEC (short, size);
+  reg_pref = XCNEWVEC (struct reg_pref, size);
+  memset (reg_renumber, -1, size * sizeof (short));
+}
+
+
+/* Resize reg info. The new elements will be uninitialized.  */
+void
+resize_reg_info (void)
+{
+  int size = max_reg_num ();
+
+  gcc_assert (reg_pref && reg_renumber);
+  reg_renumber = XRESIZEVEC (short, reg_renumber, size);
+  reg_pref = XRESIZEVEC (struct reg_pref, reg_pref, size);
+}
+
+
 /* Free up the space allocated by allocate_reg_info.  */
 void
 free_reg_info (void)
@@ -2300,6 +2325,21 @@ free_reg_info (void)
     }
 }
 
+
+
+
+/* Set up preferred and alternate classes for REGNO as PREFCLASS and
+   ALTCLASS.  */
+void
+setup_reg_classes (int regno,
+		   enum reg_class prefclass, enum reg_class altclass)
+{
+  if (reg_pref == NULL)
+    return;
+  reg_pref[regno].prefclass = prefclass;
+  reg_pref[regno].altclass = altclass;
+}
+
 
 /* This is the `regscan' pass of the compiler, run just before cse and
    again just before loop.  It finds the first and last use of each
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/rtl.h ./rtl.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/rtl.h	2008-08-21 21:16:46.000000000 -0400
+++ ./rtl.h	2008-08-22 18:10:01.000000000 -0400
@@ -1805,6 +1805,12 @@ rtx remove_list_elem (rtx, rtx *);
 
 /* regclass.c */
 
+/* Initialize may_move_cost and friends for mode M.  */
+extern void init_move_cost (enum machine_mode);
+/* Allocate register info memory.  */
+extern void allocate_reg_info (void);
+/* Resize reg info.  */
+extern void resize_reg_info (void);
 /* Free up register info memory.  */
 extern void free_reg_info (void);
 
@@ -1815,6 +1821,7 @@ extern const char *decode_asm_operands (
 
 extern enum reg_class reg_preferred_class (int);
 extern enum reg_class reg_alternate_class (int);
+extern void setup_reg_classes (int, enum reg_class, enum reg_class);
 
 extern void split_all_insns (void);
 extern unsigned int split_all_insns_noflow (void);
@@ -2183,12 +2190,16 @@ extern bool can_copy_p (enum machine_mod
 extern rtx fis_get_condition (rtx);
 
 /* In global.c */
+#ifdef HARD_CONST
+extern HARD_REG_SET eliminable_regset;
+#endif
 extern void mark_elimination (int, int);
 extern void dump_global_regs (FILE *);
 #ifdef HARD_CONST
 /* Yes, this ifdef is silly, but HARD_REG_SET is not always defined.  */
 extern void retry_global_alloc (int, HARD_REG_SET);
 #endif
+extern void build_insn_chain (void);
 
 /* In regclass.c */
 extern int reg_classes_intersect_p (enum reg_class, enum reg_class);
@@ -2214,6 +2225,7 @@ extern void dbr_schedule (rtx);
 
 /* In local-alloc.c */
 extern void dump_local_alloc (FILE *);
+extern int update_equiv_regs (void);
 
 /* In reload1.c */
 extern int function_invariant_p (const_rtx);
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/Makefile.in ./Makefile.in
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/Makefile.in	2008-08-21 21:16:46.000000000 -0400
+++ ./Makefile.in	2008-08-25 11:35:41.000000000 -0400
@@ -849,6 +849,7 @@ TREE_DATA_REF_H = tree-data-ref.h $(LAMB
 VARRAY_H = varray.h $(MACHMODE_H) $(SYSTEM_H) coretypes.h $(TM_H)
 TREE_INLINE_H = tree-inline.h $(VARRAY_H) pointer-set.h
 REAL_H = real.h $(MACHMODE_H)
+IRA_INT_H = ira.h ira-int.h $(CFGLOOP_H) alloc-pool.h
 DBGCNT_H = dbgcnt.h dbgcnt.def
 EBIMAP_H = ebitmap.h sbitmap.h
 IPA_PROP_H = ipa-prop.h $(TREE_H) vec.h $(CGRAPH_H)
@@ -1097,6 +1098,13 @@ OBJS-common = \
 	init-regs.o \
 	integrate.o \
 	intl.o \
+	ira.o \
+	ira-build.o \
+	ira-costs.o \
+	ira-conflicts.o \
+	ira-color.o \
+	ira-emit.o \
+	ira-lives.o \
 	jump.o \
 	lambda-code.o \
 	lambda-mat.o \
@@ -2408,7 +2416,7 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM
    $(INSN_ATTR_H) output.h $(DIAGNOSTIC_H) debug.h insn-config.h intl.h \
    $(RECOG_H) Makefile $(TOPLEV_H) dwarf2out.h sdbout.h dbxout.h $(EXPR_H) \
    hard-reg-set.h $(BASIC_BLOCK_H) graph.h except.h $(REGS_H) $(TIMEVAR_H) \
-   value-prof.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \
+   value-prof.h $(PARAMS_H) $(TM_P_H) reload.h ira.h dwarf2asm.h $(TARGET_H) \
    langhooks.h insn-flags.h $(CFGLAYOUT_H) $(CFGLOOP_H) hosthooks.h \
    $(CGRAPH_H) $(COVERAGE_H) alloc-pool.h $(GGC_H) $(INTEGRATE_H) \
    opts.h params.def tree-mudflap.h $(REAL_H) tree-pass.h $(GIMPLE_H)
@@ -2771,7 +2779,7 @@ cfgloop.o : cfgloop.c $(CONFIG_H) $(SYST
    $(GGC_H)
 cfgloopanal.o : cfgloopanal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
    $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) \
-   $(OBSTACK_H) output.h graphds.h
+   $(OBSTACK_H) output.h graphds.h $(PARAMS_H)
 graphds.o : graphds.c graphds.h $(CONFIG_H) $(SYSTEM_H) $(BITMAP_H) $(OBSTACK_H) \
    coretypes.h vec.h vecprim.h
 loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
@@ -2835,7 +2843,7 @@ reload1.o : reload1.c $(CONFIG_H) $(SYST
    $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \
    $(BASIC_BLOCK_H) $(RECOG_H) output.h $(FUNCTION_H) $(TOPLEV_H) $(TM_P_H) \
    addresses.h except.h $(TREE_H) $(REAL_H) $(FLAGS_H) $(MACHMODE_H) \
-   $(OBSTACK_H) $(DF_H) $(TARGET_H) dse.h
+   $(OBSTACK_H) $(DF_H) $(TARGET_H) dse.h ira.h
 rtlhooks.o :  rtlhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    rtlhooks-def.h $(EXPR_H) $(RECOG_H)
 postreload.o : postreload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
@@ -2851,7 +2859,7 @@ postreload-gcse.o : postreload-gcse.c $(
 caller-save.o : caller-save.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(FLAGS_H) $(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) $(FUNCTION_H) \
    addresses.h $(RECOG_H) reload.h $(EXPR_H) $(TOPLEV_H) $(TM_P_H) $(DF_H) \
-   gt-caller-save.h $(GGC_H)
+   output.h $(CFGLOOP_H) ira.h gt-caller-save.h $(GGC_H)
 bt-load.o : bt-load.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) except.h \
    $(RTL_H) hard-reg-set.h $(REGS_H) $(TM_P_H) $(FIBHEAP_H) output.h $(EXPR_H) \
    $(TARGET_H) $(FLAGS_H) $(INSN_ATTR_H) $(FUNCTION_H) tree-pass.h $(TOPLEV_H) \
@@ -2872,6 +2880,37 @@ stack-ptr-mod.o : stack-ptr-mod.c $(CONF
 init-regs.o : init-regs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) $(TREE_H) $(RTL_H) $(REGS_H) $(EXPR_H) tree-pass.h \
    $(BASIC_BLOCK_H) $(FLAGS_H) $(DF_H)
+ira-build.o: ira-build.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
+   insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) \
+   $(PARAMS_H) $(DF_H) sparseset.h $(IRA_INT_H)
+ira-costs.o: ira-costs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TARGET_H) $(RTL_H) insn-config.h $(RECOG_H) \
+   $(REGS_H) hard-reg-set.h $(FLAGS_H) errors.h \
+   $(EXPR_H) $(BASIC_BLOCK_H) $(TM_P_H) \
+   $(IRA_INT_H)
+ira-conflicts.o: ira-conflicts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
+   insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(PARAMS_H) \
+   $(DF_H) sparseset.h $(IRA_INT_H)
+ira-color.o: ira-color.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
+   $(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(PARAMS_H) \
+   $(DF_H) $(SPLAY_TREE_H) $(IRA_INT_H)
+ira-emit.o: ira-emit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
+   $(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(PARAMS_H) \
+   $(IRA_INT_H)
+ira-lives.o: ira-lives.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
+   insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(PARAMS_H) \
+   $(DF_H) sparseset.h $(IRA_INT_H)
+ira.o: ira.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+   $(TARGET_H) $(TM_H) $(RTL_H) $(RECOG_H) \
+   $(REGS_H) hard-reg-set.h $(FLAGS_H) $(OBSTACK_H) \
+   $(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) \
+   $(DF_H) $(IRA_INT_H)  $(PARAMS_H) $(TIMEVAR_H) $(INTEGRATE_H) \
+   tree-pass.h output.h
 regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    insn-config.h $(TIMEVAR_H) tree-pass.h $(DF_H)\
    $(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/passes.c ./passes.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/passes.c	2008-08-21 21:16:46.000000000 -0400
+++ ./passes.c	2008-08-22 21:58:34.000000000 -0400
@@ -767,6 +767,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_subregs_of_mode_init);
       NEXT_PASS (pass_local_alloc);
       NEXT_PASS (pass_global_alloc);
+      NEXT_PASS (pass_ira);
       NEXT_PASS (pass_subregs_of_mode_finish);
       NEXT_PASS (pass_postreload);
 	{
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/params.def ./params.def
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/params.def	2008-08-21 21:16:46.000000000 -0400
+++ ./params.def	2008-08-22 18:10:01.000000000 -0400
@@ -710,6 +710,11 @@ DEFPARAM (PARAM_DF_DOUBLE_QUEUE_THRESHOL
 	  "Multiplier used for determining the double-queueing threshold",
 	  2, 0, 0)
 
+DEFPARAM (PARAM_IRA_MAX_LOOPS_NUM,
+	  "ira-max-loops-num",
+	  "max loops number for regional RA",
+	  50, 0, 0)
+
 /* Switch initialization conversion will refuse to create arrays that are
    bigger than this parameter times the number of switch branches.  */
 
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/reload1.c ./reload1.c
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/reload1.c	2008-08-21 21:16:46.000000000 -0400
+++ ./reload1.c	2008-08-25 11:35:41.000000000 -0400
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  
 #include "toplev.h"
 #include "except.h"
 #include "tree.h"
+#include "ira.h"
 #include "df.h"
 #include "target.h"
 #include "dse.h"
@@ -257,6 +258,9 @@ static unsigned int spill_stack_slot_wid
 /* Record which pseudos needed to be spilled.  */
 static regset_head spilled_pseudos;
 
+/* Record which pseudos changed their allocation in finish_spills.  */
+static regset_head changed_allocation_pseudos;
+
 /* Used for communication between order_regs_for_reload and count_pseudo.
    Used to avoid counting one pseudo twice.  */
 static regset_head pseudos_counted;
@@ -389,7 +393,7 @@ static void delete_caller_save_insns (vo
 static void spill_failure (rtx, enum reg_class);
 static void count_spilled_pseudo (int, int, int);
 static void delete_dead_insn (rtx);
-static void alter_reg (int, int);
+static void alter_reg (int, int, bool);
 static void set_label_offsets (rtx, rtx, int);
 static void check_eliminable_occurrences (rtx);
 static void elimination_effects (rtx, enum machine_mode);
@@ -443,6 +447,8 @@ static rtx inc_for_reload (rtx, rtx, rtx
 static void add_auto_inc_notes (rtx, rtx);
 #endif
 static void copy_eh_notes (rtx, rtx);
+static void substitute (rtx *, const_rtx, rtx);
+static bool gen_reload_chain_without_interm_reg_p (int, int);
 static int reloads_conflict (int, int);
 static rtx gen_reload (rtx, rtx, int, enum reload_type);
 static rtx emit_insn_if_valid_for_reload (rtx);
@@ -501,6 +507,7 @@ init_reload (void)
   reload_startobj = XOBNEWVAR (&reload_obstack, char, 0);
 
   INIT_REG_SET (&spilled_pseudos);
+  INIT_REG_SET (&changed_allocation_pseudos);
   INIT_REG_SET (&pseudos_counted);
 }
 
@@ -518,6 +525,7 @@ new_insn_chain (void)
       c = XOBNEW (&reload_obstack, struct insn_chain);
       INIT_REG_SET (&c->live_throughout);
       INIT_REG_SET (&c->dead_or_set);
+      INIT_REG_SET (&c->saved);
     }
   else
     {
@@ -546,11 +554,11 @@ compute_use_by_pseudos (HARD_REG_SET *to
 
       if (r < 0)
 	{
-	  /* reload_combine uses the information from
-	     DF_LIVE_IN (BASIC_BLOCK), which might still
-	     contain registers that have not actually been allocated
-	     since they have an equivalence.  */
-	  gcc_assert (reload_completed);
+	  /* reload_combine uses the information from DF_LIVE_IN,
+	     which might still contain registers that have not
+	     actually been allocated since they have an
+	     equivalence.  */
+	  gcc_assert ((flag_ira && optimize) || reload_completed);
 	}
       else
 	add_to_hard_reg_set (to, PSEUDO_REGNO_MODE (regno), r);
@@ -684,6 +692,9 @@ static int something_needs_operands_chan
 /* Nonzero means we couldn't get enough spill regs.  */
 static int failure;
 
+/* Temporary array of pseudo-register number.  */
+static int *temp_pseudo_reg_arr;
+
 /* Main entry point for the reload pass.
 
    FIRST is the first insn of the function being compiled.
@@ -700,7 +711,7 @@ static int failure;
 int
 reload (rtx first, int global)
 {
-  int i;
+  int i, n;
   rtx insn;
   struct elim_table *ep;
   basic_block bb;
@@ -883,12 +894,21 @@ reload (rtx first, int global)
   offsets_known_at = XNEWVEC (char, num_labels);
   offsets_at = (HOST_WIDE_INT (*)[NUM_ELIMINABLE_REGS]) xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT));
 
-  /* Alter each pseudo-reg rtx to contain its hard reg number.
-     Assign stack slots to the pseudos that lack hard regs or equivalents.
+  /* Alter each pseudo-reg rtx to contain its hard reg number.  Assign
+     stack slots to the pseudos that lack hard regs or equivalents.
      Do not touch virtual registers.  */
 
-  for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
-    alter_reg (i, -1);
+  temp_pseudo_reg_arr = XNEWVEC (int, max_regno - LAST_VIRTUAL_REGISTER - 1);
+  for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
+    temp_pseudo_reg_arr[n++] = i;
+  
+  if (flag_ira && optimize)
+    /* Ask IRA to order pseudo-registers for better stack slot
+       sharing.  */
+    ira_sort_regnos_for_alter_reg (temp_pseudo_reg_arr, n, reg_max_ref_width);
+
+  for (i = 0; i < n; i++)
+    alter_reg (temp_pseudo_reg_arr[i], -1, false);
 
   /* If we have some registers we think can be eliminated, scan all insns to
      see if there is an insn that sets one of these registers to something
@@ -1002,7 +1022,7 @@ reload (rtx first, int global)
 		   the loop.  */
 		reg_equiv_memory_loc[i] = 0;
 		reg_equiv_init[i] = 0;
-		alter_reg (i, -1);
+		alter_reg (i, -1, true);
 	      }
 	  }
 
@@ -1036,7 +1056,12 @@ reload (rtx first, int global)
 
       calculate_needs_all_insns (global);
 
-      CLEAR_REG_SET (&spilled_pseudos);
+      if (! flag_ira || ! optimize)
+	/* Don't do it for IRA.  We need this info because we don't
+	   change live_throughout and dead_or_set for chains when IRA
+	   is used.  */
+	CLEAR_REG_SET (&spilled_pseudos);
+
       did_spill = 0;
 
       something_changed = 0;
@@ -1094,6 +1119,11 @@ reload (rtx first, int global)
       obstack_free (&reload_obstack, reload_firstobj);
     }
 
+  if (flag_ira && optimize)
+    /* Restore the original insn chain order for correct reload work
+       (e.g. for correct inheritance).  */
+    ira_sort_insn_chain (false);
+
   /* If global-alloc was run, notify it of any register eliminations we have
      done.  */
   if (global)
@@ -1163,6 +1193,7 @@ reload (rtx first, int global)
      regs.  */
  failed:
 
+  CLEAR_REG_SET (&changed_allocation_pseudos);
   CLEAR_REG_SET (&spilled_pseudos);
   reload_in_progress = 0;
 
@@ -1333,6 +1364,8 @@ reload (rtx first, int global)
   VEC_free (rtx, gc, reg_equiv_memory_loc_vec);
   reg_equiv_memory_loc = 0;
 
+  free (temp_pseudo_reg_arr);
+
   if (offsets_known_at)
     free (offsets_known_at);
   if (offsets_at)
@@ -1573,10 +1606,24 @@ calculate_needs_all_insns (int global)
 	    {
 	      rtx set = single_set (insn);
 	      if (set
-		  && SET_SRC (set) == SET_DEST (set)
-		  && REG_P (SET_SRC (set))
-		  && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
+		  &&
+		  ((SET_SRC (set) == SET_DEST (set)
+		    && REG_P (SET_SRC (set))
+		    && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
+		   || (REG_P (SET_SRC (set)) && REG_P (SET_DEST (set))
+		       && reg_renumber[REGNO (SET_SRC (set))] < 0
+		       && reg_renumber[REGNO (SET_DEST (set))] < 0
+		       && reg_equiv_memory_loc[REGNO (SET_SRC (set))] != NULL
+		       && reg_equiv_memory_loc[REGNO (SET_DEST (set))] != NULL
+		       && rtx_equal_p (reg_equiv_memory_loc
+				       [REGNO (SET_SRC (set))],
+				       reg_equiv_memory_loc
+				       [REGNO (SET_DEST (set))]))))
 		{
+		  if (flag_ira && optimize)
+		    /* Inform IRA about the insn deletion.  */
+		    ira_mark_memory_move_deletion (REGNO (SET_DEST (set)),
+						   REGNO (SET_SRC (set)));
 		  delete_insn (insn);
 		  /* Delete it from the reload chain.  */
 		  if (chain->prev)
@@ -1665,6 +1712,10 @@ static int spill_cost[FIRST_PSEUDO_REGIS
    only the first hard reg for a multi-reg pseudo.  */
 static int spill_add_cost[FIRST_PSEUDO_REGISTER];
 
+/* Map of hard regno to pseudo regno currently occupying the hard
+   reg.  */
+static int hard_regno_to_pseudo_regno[FIRST_PSEUDO_REGISTER];
+
 /* Update the spill cost arrays, considering that pseudo REG is live.  */
 
 static void
@@ -1675,7 +1726,10 @@ count_pseudo (int reg)
   int nregs;
 
   if (REGNO_REG_SET_P (&pseudos_counted, reg)
-      || REGNO_REG_SET_P (&spilled_pseudos, reg))
+      || REGNO_REG_SET_P (&spilled_pseudos, reg)
+      /* Ignore spilled pseudo-registers which can be here only if IRA
+	 is used.  */
+      || (flag_ira && optimize && r < 0))
     return;
 
   SET_REGNO_REG_SET (&pseudos_counted, reg);
@@ -1683,10 +1737,12 @@ count_pseudo (int reg)
   gcc_assert (r >= 0);
 
   spill_add_cost[r] += freq;
-
   nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)];
   while (nregs-- > 0)
-    spill_cost[r + nregs] += freq;
+    {
+      hard_regno_to_pseudo_regno[r + nregs] = reg;
+      spill_cost[r + nregs] += freq;
+    }
 }
 
 /* Calculate the SPILL_COST and SPILL_ADD_COST arrays and determine the
@@ -1704,6 +1760,8 @@ order_regs_for_reload (struct insn_chain
 
   memset (spill_cost, 0, sizeof spill_cost);
   memset (spill_add_cost, 0, sizeof spill_add_cost);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    hard_regno_to_pseudo_regno[i] = -1;
 
   /* Count number of uses of each hard reg by pseudo regs allocated to it
      and then order them by decreasing use.  First exclude hard registers
@@ -1721,11 +1779,13 @@ order_regs_for_reload (struct insn_chain
   EXECUTE_IF_SET_IN_REG_SET
     (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi)
     {
-      count_pseudo (i);
+      if (!REGNO_REG_SET_P (&chain->saved, i))
+	count_pseudo (i);
     }
   EXECUTE_IF_SET_IN_REG_SET
     (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi)
     {
+      gcc_assert (!REGNO_REG_SET_P (&chain->saved, i));
       count_pseudo (i);
     }
   CLEAR_REG_SET (&pseudos_counted);
@@ -1746,18 +1806,25 @@ static HARD_REG_SET used_spill_regs_loca
 static void
 count_spilled_pseudo (int spilled, int spilled_nregs, int reg)
 {
+  int freq = REG_FREQ (reg);
   int r = reg_renumber[reg];
   int nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)];
 
-  if (REGNO_REG_SET_P (&spilled_pseudos, reg)
+  /* Ignore spilled pseudo-registers which can be here only if IRA is
+     used.  */
+  if ((flag_ira && optimize && r < 0)
+      || REGNO_REG_SET_P (&spilled_pseudos, reg)
       || spilled + spilled_nregs <= r || r + nregs <= spilled)
     return;
 
   SET_REGNO_REG_SET (&spilled_pseudos, reg);
 
-  spill_add_cost[r] -= REG_FREQ (reg);
+  spill_add_cost[r] -= freq;
   while (nregs-- > 0)
-    spill_cost[r + nregs] -= REG_FREQ (reg);
+    {
+      hard_regno_to_pseudo_regno[r + nregs] = -1;
+      spill_cost[r + nregs] -= freq;
+    }
 }
 
 /* Find reload register to use for reload number ORDER.  */
@@ -1769,11 +1836,13 @@ find_reg (struct insn_chain *chain, int 
   struct reload *rl = rld + rnum;
   int best_cost = INT_MAX;
   int best_reg = -1;
-  unsigned int i, j;
+  unsigned int i, j, n;
   int k;
   HARD_REG_SET not_usable;
   HARD_REG_SET used_by_other_reload;
   reg_set_iterator rsi;
+  static int regno_pseudo_regs[FIRST_PSEUDO_REGISTER];
+  static int best_regno_pseudo_regs[FIRST_PSEUDO_REGISTER];
 
   COPY_HARD_REG_SET (not_usable, bad_spill_regs);
   IOR_HARD_REG_SET (not_usable, bad_spill_regs_global);
@@ -1791,7 +1860,11 @@ find_reg (struct insn_chain *chain, int 
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
+#ifdef REG_ALLOC_ORDER
+      unsigned int regno = reg_alloc_order[i];
+#else
       unsigned int regno = i;
+#endif
 
       if (! TEST_HARD_REG_BIT (not_usable, regno)
 	  && ! TEST_HARD_REG_BIT (used_by_other_reload, regno)
@@ -1810,6 +1883,38 @@ find_reg (struct insn_chain *chain, int 
 	    }
 	  if (! ok)
 	    continue;
+
+	  if (flag_ira && optimize)
+	    {
+	      /* Ask IRA to find a better pseudo-register for
+		 spilling.  */
+	      for (n = j = 0; j < this_nregs; j++)
+		{
+		  int r = hard_regno_to_pseudo_regno[regno + j];
+
+		  if (r < 0)
+		    continue;
+		  if (n == 0 || regno_pseudo_regs[n - 1] != r)
+		    regno_pseudo_regs[n++] = r;
+		}
+	      regno_pseudo_regs[n++] = -1;
+	      if (best_reg < 0
+		  || ira_better_spill_reload_regno_p (regno_pseudo_regs,
+						      best_regno_pseudo_regs,
+						      rl->in, rl->out,
+						      chain->insn))
+		{
+		  best_reg = regno;
+		  for (j = 0;; j++)
+		    {
+		      best_regno_pseudo_regs[j] = regno_pseudo_regs[j];
+		      if (regno_pseudo_regs[j] < 0)
+			break;
+		    }
+		}
+	      continue;
+	    }
+
 	  if (rl->in && REG_P (rl->in) && REGNO (rl->in) == regno)
 	    this_cost--;
 	  if (rl->out && REG_P (rl->out) && REGNO (rl->out) == regno)
@@ -1841,15 +1946,36 @@ find_reg (struct insn_chain *chain, int 
   rl->nregs = hard_regno_nregs[best_reg][rl->mode];
   rl->regno = best_reg;
 
+  if (dump_file != NULL)
+    EXECUTE_IF_SET_IN_REG_SET
+      (&chain->saved, FIRST_PSEUDO_REGISTER, j, rsi)
+      {
+	int nregs;
+	int r = reg_renumber[j];
+	
+	if (r < 0)
+	  continue;
+	nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (j)];
+	if ((best_reg <= r && r < best_reg + (int) rl->nregs)
+	    || (r <= best_reg && best_reg < r + nregs))
+	{
+	  fprintf (dump_file, "using saved reg %d (of %u) for insn %u\n",
+		   r, j, INSN_UID (chain->insn));
+	  break;
+	}
+      }
+
   EXECUTE_IF_SET_IN_REG_SET
     (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j, rsi)
     {
-      count_spilled_pseudo (best_reg, rl->nregs, j);
+      if (!REGNO_REG_SET_P (&chain->saved, j))
+	count_spilled_pseudo (best_reg, rl->nregs, j);
     }
 
   EXECUTE_IF_SET_IN_REG_SET
     (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j, rsi)
     {
+      gcc_assert (!REGNO_REG_SET_P (&chain->saved, j));
       count_spilled_pseudo (best_reg, rl->nregs, j);
     }
 
@@ -1857,6 +1983,7 @@ find_reg (struct insn_chain *chain, int 
     {
       gcc_assert (spill_cost[best_reg + i] == 0);
       gcc_assert (spill_add_cost[best_reg + i] == 0);
+      gcc_assert (hard_regno_to_pseudo_regno[best_reg + i] == -1);
       SET_HARD_REG_BIT (used_spill_regs_local, best_reg + i);
     }
   return 1;
@@ -1948,13 +2075,18 @@ delete_caller_save_insns (void)
 {
   struct insn_chain *c = reload_insn_chain;
 
-  while (c != 0)
+  CLEAR_HARD_REG_SET (used_spill_regs);
+  for (;;)
     {
       while (c != 0 && c->is_caller_save_insn)
 	{
 	  struct insn_chain *next = c->next;
 	  rtx insn = c->insn;
 
+	  if (dump_file)
+	    fprintf (dump_file, "removing caller save insn %u\n",
+		     INSN_UID (insn));
+
 	  if (c == reload_insn_chain)
 	    reload_insn_chain = next;
 	  delete_insn (insn);
@@ -1967,8 +2099,52 @@ delete_caller_save_insns (void)
 	  unused_insn_chains = c;
 	  c = next;
 	}
-      if (c != 0)
-	c = c->next;
+      if (c == 0)
+	break;
+      /* Invalidating spill hard registers got from caller-saved hard
+	 registers.  */
+      if (c->need_reload)
+	{
+	  HARD_REG_SET saved;
+	  int i;
+	  unsigned int regno;
+	  reg_set_iterator rsi;
+
+	  CLEAR_HARD_REG_SET (saved);
+	  EXECUTE_IF_SET_IN_REG_SET (&c->saved, FIRST_PSEUDO_REGISTER,
+				     regno, rsi)
+	    {
+	      int r = reg_renumber[regno];
+
+	      if (r < 0)
+		continue;
+	      add_to_hard_reg_set (&saved, PSEUDO_REGNO_MODE (regno), r);
+	    }
+	  if (!hard_reg_set_empty_p (saved))
+	    for (i = 0; i < c->n_reloads; i++)
+	      {
+		int nregs;
+		struct reload *rl = &c->rld[i];
+		int r = rl->regno;
+		
+		if (rl->regno < 0)
+		  continue;
+		nregs = rl->nregs;
+		for (nregs--; nregs >= 0; nregs--)
+		  if (TEST_HARD_REG_BIT (saved, r + nregs))
+		    {
+		      if (dump_file != NULL)
+			fprintf (dump_file,
+				 "invalidating %d reg for insn %u reload\n",
+				 rl->regno, INSN_UID (c->insn));
+		      rl->regno = -1;
+		      break;
+		    }
+	      }
+	  AND_COMPL_HARD_REG_SET (c->used_spill_regs, saved);
+	  IOR_HARD_REG_SET (used_spill_regs, c->used_spill_regs);
+	}
+      c = c->next;
     }
 }
 
@@ -2026,7 +2202,7 @@ delete_dead_insn (rtx insn)
    can share one stack slot.  */
 
 static void
-alter_reg (int i, int from_reg)
+alter_reg (int i, int from_reg, bool dont_share_p)
 {
   /* When outputting an inline function, this can happen
      for a reg that isn't actually used.  */
@@ -2059,7 +2235,15 @@ alter_reg (int i, int from_reg)
       unsigned int total_size = MAX (inherent_size, reg_max_ref_width[i]);
       unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT;
       int adjust = 0;
+      bool shared_p = false;
 
+      if (flag_ira && optimize)
+	/* Mark the spill for IRA.  */
+	SET_REGNO_REG_SET (&spilled_pseudos, i);
+      x = (dont_share_p || ! flag_ira || ! optimize
+	   ? NULL_RTX : ira_reuse_stack_slot (i, inherent_size, total_size));
+      if (x)
+	shared_p = true;
       /* Each pseudo reg has an inherent size which comes from its own mode,
 	 and a total size which provides room for paradoxical subregs
 	 which refer to the pseudo reg in wider modes.
@@ -2068,7 +2252,7 @@ alter_reg (int i, int from_reg)
 	 enough inherent space and enough total space.
 	 Otherwise, we allocate a new slot, making sure that it has no less
 	 inherent space, and no less total space, then the previous slot.  */
-      if (from_reg == -1)
+      else if (from_reg == -1 || (! dont_share_p && flag_ira && optimize))
 	{
 	  alias_set_type alias_set = new_alias_set ();
 
@@ -2086,6 +2270,10 @@ alter_reg (int i, int from_reg)
 	  /* Nothing can alias this slot except this pseudo.  */
 	  set_mem_alias_set (x, alias_set);
 	  dse_record_singleton_alias_set (alias_set, mode);
+
+	  if (! dont_share_p && flag_ira && optimize)
+	    /* Inform IRA about allocation a new stack slot.  */
+	    ira_mark_new_stack_slot (x, i, total_size);
 	}
 
       /* Reuse a stack slot if possible.  */
@@ -2164,8 +2352,13 @@ alter_reg (int i, int from_reg)
 
       /* If we have a decl for the original register, set it for the
 	 memory.  If this is a shared MEM, make a copy.  */
-      if (REG_EXPR (regno_reg_rtx[i])
-	  && DECL_P (REG_EXPR (regno_reg_rtx[i])))
+      if (shared_p)
+	{
+	  x = copy_rtx (x);
+	  set_mem_attrs_from_reg (x, regno_reg_rtx[i]);
+	}
+      else if (REG_EXPR (regno_reg_rtx[i])
+	       && DECL_P (REG_EXPR (regno_reg_rtx[i])))
 	{
 	  rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i]));
 
@@ -2441,7 +2634,7 @@ eliminate_regs_1 (rtx x, enum machine_mo
 	  /* There exists at least one use of REGNO that cannot be
 	     eliminated.  Prevent the defining insn from being deleted.  */
 	  reg_equiv_init[regno] = NULL_RTX;
-	  alter_reg (regno, -1);
+	  alter_reg (regno, -1, true);
 	}
       return x;
 
@@ -3817,18 +4010,22 @@ finish_spills (int global)
       spill_reg_order[i] = -1;
 
   EXECUTE_IF_SET_IN_REG_SET (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i, rsi)
-    {
-      /* Record the current hard register the pseudo is allocated to in
-	 pseudo_previous_regs so we avoid reallocating it to the same
-	 hard reg in a later pass.  */
-      gcc_assert (reg_renumber[i] >= 0);
-
-      SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]);
-      /* Mark it as no longer having a hard register home.  */
-      reg_renumber[i] = -1;
-      /* We will need to scan everything again.  */
-      something_changed = 1;
-    }
+    if (! flag_ira || ! optimize || reg_renumber[i] >= 0)
+      {
+	/* Record the current hard register the pseudo is allocated to
+	   in pseudo_previous_regs so we avoid reallocating it to the
+	   same hard reg in a later pass.  */
+	gcc_assert (reg_renumber[i] >= 0);
+	
+	SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]);
+	/* Mark it as no longer having a hard register home.  */
+	reg_renumber[i] = -1;
+	if (flag_ira && optimize)
+	  /* Inform IRA about the change.  */
+	  ira_mark_allocation_change (i);
+	/* We will need to scan everything again.  */
+	something_changed = 1;
+      }
 
   /* Retry global register allocation if possible.  */
   if (global)
@@ -3848,29 +4045,56 @@ finish_spills (int global)
 	  EXECUTE_IF_SET_IN_REG_SET
 	    (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi)
 	    {
+	      gcc_assert (!REGNO_REG_SET_P (&chain->saved, i));
 	      IOR_HARD_REG_SET (pseudo_forbidden_regs[i],
 				chain->used_spill_regs);
 	    }
 	}
 
-      /* Retry allocating the spilled pseudos.  For each reg, merge the
-	 various reg sets that indicate which hard regs can't be used,
-	 and call retry_global_alloc.
-	 We change spill_pseudos here to only contain pseudos that did not
-	 get a new hard register.  */
-      for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
-	if (reg_old_renumber[i] != reg_renumber[i])
-	  {
-	    HARD_REG_SET forbidden;
-	    COPY_HARD_REG_SET (forbidden, bad_spill_regs_global);
-	    IOR_HARD_REG_SET (forbidden, pseudo_forbidden_regs[i]);
-	    IOR_HARD_REG_SET (forbidden, pseudo_previous_regs[i]);
-	    retry_global_alloc (i, forbidden);
-	    if (reg_renumber[i] >= 0)
-	      CLEAR_REGNO_REG_SET (&spilled_pseudos, i);
-	  }
-    }
+      if (! flag_ira || ! optimize)
+	{
+	  /* Retry allocating the spilled pseudos.  For each reg,
+	     merge the various reg sets that indicate which hard regs
+	     can't be used, and call retry_global_alloc.  We change
+	     spill_pseudos here to only contain pseudos that did not
+	     get a new hard register.  */
+	  for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
+	    if (reg_old_renumber[i] != reg_renumber[i])
+	      {
+		HARD_REG_SET forbidden;
+		
+		COPY_HARD_REG_SET (forbidden, bad_spill_regs_global);
+		IOR_HARD_REG_SET (forbidden, pseudo_forbidden_regs[i]);
+		IOR_HARD_REG_SET (forbidden, pseudo_previous_regs[i]);
+		retry_global_alloc (i, forbidden);
+		if (reg_renumber[i] >= 0)
+		  CLEAR_REGNO_REG_SET (&spilled_pseudos, i);
+	      }
+	}
+      else
+	{
+	  /* Retry allocating the pseudos spilled in IRA and the
+	     reload.  For each reg, merge the various reg sets that
+	     indicate which hard regs can't be used, and call
+	     ira_reassign_pseudos.  */
+	  unsigned int n;
 
+	  for (n = 0, i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++)
+	    if (reg_old_renumber[i] != reg_renumber[i])
+	      {
+		if (reg_renumber[i] < 0)
+		  temp_pseudo_reg_arr[n++] = i;
+		else
+		  CLEAR_REGNO_REG_SET (&spilled_pseudos, i);
+	      }
+	  if (ira_reassign_pseudos (temp_pseudo_reg_arr, n,
+				    bad_spill_regs_global,
+				    pseudo_forbidden_regs, pseudo_previous_regs,
+				    &spilled_pseudos))
+	    something_changed = 1;
+	  
+	}
+    }
   /* Fix up the register information in the insn chain.
      This involves deleting those of the spilled pseudos which did not get
      a new hard register home from the live_{before,after} sets.  */
@@ -3879,9 +4103,14 @@ finish_spills (int global)
       HARD_REG_SET used_by_pseudos;
       HARD_REG_SET used_by_pseudos2;
 
-      AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos);
-      AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos);
-
+      if (! flag_ira || ! optimize)
+	{
+	  /* Don't do it for IRA because IRA and the reload still can
+	     assign hard registers to the spilled pseudos on next
+	     reload iterations.  */
+	  AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos);
+	  AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos);
+	}
       /* Mark any unallocated hard regs as available for spills.  That
 	 makes inheritance work somewhat better.  */
       if (chain->need_reload)
@@ -3890,20 +4119,18 @@ finish_spills (int global)
 	  REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set);
 	  IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
 
-	  /* Save the old value for the sanity test below.  */
-	  COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs);
-
 	  compute_use_by_pseudos (&used_by_pseudos, &chain->live_throughout);
 	  compute_use_by_pseudos (&used_by_pseudos, &chain->dead_or_set);
+	  /* Value of chain->used_spill_regs from previous iteration
+	     may be not included in the value calculated here because
+	     of possible removing caller-saves insns (see function
+	     delete_caller_save_insns.  */
 	  COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
 	  AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
-
-	  /* Make sure we only enlarge the set.  */
-	  gcc_assert (hard_reg_set_subset_p (used_by_pseudos2,
-					    chain->used_spill_regs));
 	}
     }
 
+  CLEAR_REG_SET (&changed_allocation_pseudos);
   /* Let alter_reg modify the reg rtx's for the modified pseudos.  */
   for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
     {
@@ -3911,7 +4138,9 @@ finish_spills (int global)
       if (reg_old_renumber[i] == regno)
 	continue;
 
-      alter_reg (i, reg_old_renumber[i]);
+      SET_REGNO_REG_SET (&changed_allocation_pseudos, i);
+
+      alter_reg (i, reg_old_renumber[i], false);
       reg_old_renumber[i] = regno;
       if (dump_file)
 	{
@@ -4295,8 +4524,8 @@ reload_as_needed (int live_known)
          be partially clobbered by the call.  */
       else if (CALL_P (insn))
 	{
-	AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
-	AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
+	  AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
+	  AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
 	}
     }
 
@@ -4967,6 +5196,126 @@ reloads_unique_chain_p (int r1, int r2)
   return true;
 }
 
+
+/* The recursive function change all occurrences of WHAT in *WHERE
+   onto REPL.  */
+static void
+substitute (rtx *where, const_rtx what, rtx repl)
+{
+  const char *fmt;
+  int i;
+  enum rtx_code code;
+
+  if (*where == 0)
+    return;
+
+  if (*where == what || rtx_equal_p (*where, what))
+    {
+      *where = repl;
+      return;
+    }
+
+  code = GET_CODE (*where);
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+	{
+	  int j;
+
+	  for (j = XVECLEN (*where, i) - 1; j >= 0; j--)
+	    substitute (&XVECEXP (*where, i, j), what, repl);
+	}
+      else if (fmt[i] == 'e')
+	substitute (&XEXP (*where, i), what, repl);
+    }
+}
+
+/* The function returns TRUE if chain of reload R1 and R2 (in any
+   order) can be evaluated without usage of intermediate register for
+   the reload containing another reload.  It is important to see
+   gen_reload to understand what the function is trying to do.  As an
+   example, let us have reload chain
+
+      r2: const
+      r1: <something> + const
+
+   and reload R2 got reload reg HR.  The function returns true if
+   there is a correct insn HR = HR + <something>.  Otherwise,
+   gen_reload will use intermediate register (and this is the reload
+   reg for R1) to reload <something>.
+
+   We need this function to find a conflict for chain reloads.  In our
+   example, if HR = HR + <something> is incorrect insn, then we cannot
+   use HR as a reload register for R2.  If we do use it then we get a
+   wrong code:
+
+      HR = const
+      HR = <something>
+      HR = HR + HR
+
+*/
+static bool
+gen_reload_chain_without_interm_reg_p (int r1, int r2)
+{
+  bool result;
+  int regno, n, code;
+  rtx out, in, tem, insn;
+  rtx last = get_last_insn ();
+
+  /* Make r2 a component of r1.  */
+  if (reg_mentioned_p (rld[r1].in, rld[r2].in))
+    {
+      n = r1;
+      r1 = r2;
+      r2 = n;
+    }
+  gcc_assert (reg_mentioned_p (rld[r2].in, rld[r1].in));
+  regno = rld[r1].regno >= 0 ? rld[r1].regno : rld[r2].regno;
+  gcc_assert (regno >= 0);
+  out = gen_rtx_REG (rld[r1].mode, regno);
+  in = copy_rtx (rld[r1].in);
+  substitute (&in, rld[r2].in, gen_rtx_REG (rld[r2].mode, regno));
+
+  /* If IN is a paradoxical SUBREG, remove it and try to put the
+     opposite SUBREG on OUT.  Likewise for a paradoxical SUBREG on OUT.  */
+  if (GET_CODE (in) == SUBREG
+      && (GET_MODE_SIZE (GET_MODE (in))
+	  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+      && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
+    in = SUBREG_REG (in), out = tem;
+
+  if (GET_CODE (in) == PLUS
+      && (REG_P (XEXP (in, 0))
+	  || GET_CODE (XEXP (in, 0)) == SUBREG
+	  || MEM_P (XEXP (in, 0)))
+      && (REG_P (XEXP (in, 1))
+	  || GET_CODE (XEXP (in, 1)) == SUBREG
+	  || CONSTANT_P (XEXP (in, 1))
+	  || MEM_P (XEXP (in, 1))))
+    {
+      insn = emit_insn (gen_rtx_SET (VOIDmode, out, in));
+      code = recog_memoized (insn);
+      result = false;
+
+      if (code >= 0)
+	{
+	  extract_insn (insn);
+	  /* We want constrain operands to treat this insn strictly in
+	     its validity determination, i.e., the way it would after
+	     reload has completed.  */
+	  result = constrain_operands (1);
+	}
+      
+      delete_insns_since (last);
+      return result;
+    }
+  
+  /* It looks like other cases in gen_reload are not possible for
+     chain reloads or do need an intermediate hard registers.  */
+  return true;
+}
+
 /* Return 1 if the reloads denoted by R1 and R2 cannot share a register.
    Return 0 otherwise.
 
@@ -5016,7 +5365,8 @@ reloads_conflict (int r1, int r2)
     case RELOAD_FOR_OPERAND_ADDRESS:
       return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN
 	      || (r2_type == RELOAD_FOR_OPERAND_ADDRESS
-		  && !reloads_unique_chain_p (r1, r2)));
+		  && (!reloads_unique_chain_p (r1, r2)
+		      || !gen_reload_chain_without_interm_reg_p (r1, r2))));
 
     case RELOAD_FOR_OPADDR_ADDR:
       return (r2_type == RELOAD_FOR_INPUT
@@ -6724,7 +7074,10 @@ emit_input_reload_insns (struct insn_cha
 		  && REG_N_SETS (REGNO (old)) == 1)
 		{
 		  reg_renumber[REGNO (old)] = REGNO (reloadreg);
-		  alter_reg (REGNO (old), -1);
+		  if (flag_ira && optimize)
+		    /* Inform IRA about the change.  */
+		    ira_mark_allocation_change (REGNO (old));
+		  alter_reg (REGNO (old), -1, false);
 		}
 	      special = 1;
 	    }
@@ -8161,7 +8514,7 @@ delete_output_reload (rtx insn, int j, i
     n_occurrences += count_occurrences (PATTERN (insn),
 					eliminate_regs (substed, 0,
 							NULL_RTX), 0);
-  for (i1 = reg_equiv_alt_mem_list [REGNO (reg)]; i1; i1 = XEXP (i1, 1))
+  for (i1 = reg_equiv_alt_mem_list[REGNO (reg)]; i1; i1 = XEXP (i1, 1))
     {
       gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed));
       n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0);
@@ -8262,7 +8615,10 @@ delete_output_reload (rtx insn, int j, i
 
       /* For the debugging info, say the pseudo lives in this reload reg.  */
       reg_renumber[REGNO (reg)] = REGNO (new_reload_reg);
-      alter_reg (REGNO (reg), -1);
+      if (flag_ira && optimize)
+	/* Inform IRA about the change.  */
+	ira_mark_allocation_change (REGNO (reg));
+      alter_reg (REGNO (reg), -1, false);
     }
   else
     {
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/s390/s390.h ./config/s390/s390.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/s390/s390.h	2008-08-21 21:16:18.000000000 -0400
+++ ./config/s390/s390.h	2008-08-22 21:58:42.000000000 -0400
@@ -478,6 +478,30 @@ enum reg_class
   { 0xffffffff, 0x0000003f },	/* ALL_REGS */		\
 }
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES						     \
+{									     \
+  GENERAL_REGS, FP_REGS, CC_REGS, ACCESS_REGS, LIM_REG_CLASSES		     \
+}
+
+/* In some case register allocation order is not enough for IRA to
+   generate a good code.  The following macro (if defined) increases
+   cost of REGNO for a pseudo approximately by pseudo usage frequency
+   multiplied by the macro value.
+
+   We avoid usage of BASE_REGNUM by nonzero macro value because the
+   reload can decide not to use the hard register because some
+   constant was forced to be in memory.  */
+#define IRA_HARD_REGNO_ADD_COST_MULTIPLIER(regno)	\
+  (regno == BASE_REGNUM ? 0.0 : 0.5)
+
 /* Register -> class mapping.  */
 extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
 #define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO])
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/sparc/sparc.h ./config/sparc/sparc.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/sparc/sparc.h	2008-08-21 21:16:20.000000000 -0400
+++ ./config/sparc/sparc.h	2008-08-22 18:09:36.000000000 -0400
@@ -1078,6 +1078,19 @@ enum reg_class { NO_REGS, FPCC_REGS, I64
    {-1, -1, -1, 0x20},	/* GENERAL_OR_EXTRA_FP_REGS */	\
    {-1, -1, -1, 0x3f}}	/* ALL_REGS */
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES						     \
+{									     \
+  GENERAL_REGS, EXTRA_FP_REGS, FPCC_REGS, LIM_REG_CLASSES		     \
+}
+
 /* Defines invalid mode changes.  Borrowed from pa64-regs.h.
 
    SImode loads to floating-point registers are not zero-extended.
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/i386/i386.h ./config/i386/i386.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/i386/i386.h	2008-08-21 21:16:23.000000000 -0400
+++ ./config/i386/i386.h	2008-08-22 21:58:50.000000000 -0400
@@ -1274,6 +1274,19 @@ enum reg_class
 { 0xffffffff,0x1fffff }							\
 }
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES						     \
+{									     \
+  GENERAL_REGS, FLOAT_REGS, MMX_REGS, SSE_REGS, LIM_REG_CLASSES		     \
+}
+
 /* The same information, inverted:
    Return the class number of the smallest class containing
    reg number REGNO.  This could be a conditional expression
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/ia64/ia64.h ./config/ia64/ia64.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/ia64/ia64.h	2008-08-21 21:16:29.000000000 -0400
+++ ./config/ia64/ia64.h	2008-08-22 18:09:44.000000000 -0400
@@ -800,6 +800,19 @@ enum reg_class
     0xFFFFFFFF, 0xFFFFFFFF, 0x3FFF },			\
 }
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES						     \
+{									     \
+  PR_REGS, BR_REGS, AR_M_REGS, AR_I_REGS, GR_REGS, FR_REGS, LIM_REG_CLASSES  \
+}
+
 /* A C expression whose value is a register class containing hard register
    REGNO.  In general there is more than one such class; choose a class which
    is "minimal", meaning that no smaller class also contains the register.  */
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/rs6000/rs6000.h ./config/rs6000/rs6000.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/rs6000/rs6000.h	2008-08-21 21:16:34.000000000 -0400
+++ ./config/rs6000/rs6000.h	2008-08-22 21:59:08.000000000 -0400
@@ -1128,6 +1128,22 @@ enum reg_class
   { 0xffffffff, 0xffffffff, 0xffffffff, 0x0003ffff }  /* ALL_REGS */	     \
 }
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES						     \
+{									     \
+  GENERAL_REGS, SPECIAL_REGS, FLOAT_REGS, ALTIVEC_REGS,			     \
+  /*VRSAVE_REGS,*/ VSCR_REGS, SPE_ACC_REGS, SPEFSCR_REGS,		     \
+  /* MQ_REGS, LINK_REGS, CTR_REGS, */					     \
+  CR_REGS, XER_REGS, LIM_REG_CLASSES					     \
+}
+
 /* The same information, inverted:
    Return the class number of the smallest class containing
    reg number REGNO.  This could be a conditional expression
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/arm/arm.h ./config/arm/arm.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/arm/arm.h	2008-08-21 21:16:37.000000000 -0400
+++ ./config/arm/arm.h	2008-08-22 21:59:13.000000000 -0400
@@ -1185,6 +1185,20 @@ enum reg_class
    or could index an array.  */
 #define REGNO_REG_CLASS(REGNO)  arm_regno_class (REGNO)
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES						     \
+{									     \
+  GENERAL_REGS, FPA_REGS, CIRRUS_REGS, VFP_REGS, IWMMXT_GR_REGS, IWMMXT_REGS,\
+  LIM_REG_CLASSES							     \
+}
+
 /* FPA registers can't do subreg as all values are reformatted to internal
    precision.  VFP registers may only be accessed in the mode they
    were set.  */
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/alpha/alpha.h ./config/alpha/alpha.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/alpha/alpha.h	2008-08-21 21:16:17.000000000 -0400
+++ ./config/alpha/alpha.h	2008-08-22 21:58:36.000000000 -0400
@@ -553,6 +553,19 @@ enum reg_class {
   {0x00000000, 0x7fffffff},	/* FLOAT_REGS */	\
   {0xffffffff, 0xffffffff} }
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES						     \
+{									     \
+  GENERAL_REGS, FLOAT_REGS, LIM_REG_CLASSES				     \
+}
+
 /* The same information, inverted:
    Return the class number of the smallest class containing
    reg number REGNO.  This could be a conditional expression
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/avr/avr.h ./config/avr/avr.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/avr/avr.h	2008-08-21 21:16:25.000000000 -0400
+++ ./config/avr/avr.h	2008-08-22 21:58:59.000000000 -0400
@@ -291,6 +291,19 @@ enum reg_class {
 
 #define REGNO_REG_CLASS(R) avr_regno_reg_class(R)
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES               \
+{                                       \
+  GENERAL_REGS, LIM_REG_CLASSES         \
+}
+
 #define BASE_REG_CLASS (reload_completed ? BASE_POINTER_REGS : POINTER_REGS)
 
 #define INDEX_REG_CLASS NO_REGS
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/spu/spu.h ./config/spu/spu.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/spu/spu.h	2008-08-21 21:16:19.000000000 -0400
+++ ./config/spu/spu.h	2008-08-22 21:58:46.000000000 -0400
@@ -196,6 +196,9 @@ enum reg_class { 
    LIM_REG_CLASSES 
 };
 
+/* SPU is simple, it really only has one class of registers.  */
+#define IRA_COVER_CLASSES { GENERAL_REGS, LIM_REG_CLASSES }
+
 #define N_REG_CLASSES (int) LIM_REG_CLASSES
 
 #define REG_CLASS_NAMES \
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/bfin/bfin.h ./config/bfin/bfin.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/bfin/bfin.h	2008-08-21 21:16:42.000000000 -0400
+++ ./config/bfin/bfin.h	2008-08-22 18:09:56.000000000 -0400
@@ -711,6 +711,19 @@ enum reg_class
  : (REGNO) >= REG_RETS ? PROLOGUE_REGS			\
  : NO_REGS)
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES				\
+{							\
+    MOST_REGS, AREGS, CCREGS, LIM_REG_CLASSES		\
+}
+
 /* When defined, the compiler allows registers explicitly used in the
    rtl to be used as spill registers but prevents the compiler from
    extending the lifetime of these registers. */
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/sh/sh.h ./config/sh/sh.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/sh/sh.h	2008-08-21 21:16:25.000000000 -0400
+++ ./config/sh/sh.h	2008-08-22 18:09:41.000000000 -0400
@@ -1499,6 +1499,20 @@ enum reg_class
 extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
 #define REGNO_REG_CLASS(REGNO) regno_reg_class[(REGNO)]
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES						     \
+{									     \
+  GENERAL_REGS, FP_REGS, PR_REGS, T_REGS, MAC_REGS, TARGET_REGS,  	     \
+  LIM_REG_CLASSES							     \
+}
+
 /* When defined, the compiler allows registers explicitly used in the
    rtl to be used as spill registers but prevents the compiler from
    extending the lifetime of these registers.  */
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/sh/sh.md ./config/sh/sh.md
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/sh/sh.md	2008-08-21 21:16:25.000000000 -0400
+++ ./config/sh/sh.md	2008-08-22 18:09:41.000000000 -0400
@@ -1143,7 +1143,7 @@
    (set (match_dup 4) (match_dup 5))]
   "
 {
-  rtx set1, set2;
+  rtx set1, set2, insn2;
   rtx replacements[4];
 
   /* We want to replace occurrences of operands[0] with operands[1] and
@@ -1173,7 +1173,10 @@
   extract_insn (emit_insn (set1));
   if (! constrain_operands (1))
     goto failure;
-  extract_insn (emit (set2));
+  insn2 = emit (set2);
+  if (GET_CODE (insn2) == BARRIER)
+    goto failure;
+  extract_insn (insn2);
   if (! constrain_operands (1))
     {
       rtx tmp;
diff -r -x .svn -up /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/mn10300/mn10300.h ./config/mn10300/mn10300.h
--- /home/cygnus/vmakarov/build/trunk/gcc/gcc/config/mn10300/mn10300.h	2008-08-21 21:16:28.000000000 -0400
+++ ./config/mn10300/mn10300.h	2008-08-22 18:09:43.000000000 -0400
@@ -295,6 +295,19 @@ enum reg_class {
  { 0xffffffff, 0x3ffff } /* ALL_REGS 	*/	\
 }
 
+/* The following macro defines cover classes for Integrated Register
+   Allocator.  Cover classes is a set of non-intersected register
+   classes covering all hard registers used for register allocation
+   purpose.  Any move between two registers of a cover class should be
+   cheaper than load or store of the registers.  The macro value is
+   array of register classes with LIM_REG_CLASSES used as the end
+   marker.  */
+
+#define IRA_COVER_CLASSES                                                    \
+{                                                                            \
+  GENERAL_REGS, FP_REGS, LIM_REG_CLASSES \
+}
+
 /* The same information, inverted:
    Return the class number of the smallest class containing
    reg number REGNO.  This could be a conditional expression

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