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]

[ira] patch for speeding IRA up


 The following patch contains a lot of work since my last patch:
better debug info output, improving generated code, some bug and gcc
testsuite degradation fixes.  But the majority of the work is to speed
up IRA.  The work on speeding IRA up will be continued.

Vlad

2007-12-17 Vladimir Makarov <vmakarov@redhat.com>

	* common.opt (fira-assign-after-call-split, fira-biased-coloring,
	fira-split-around-calls): Remove.
	(fdump-simple-rtl, fira-verbose): New options.
	(fira, fira-coalesce): Initiate by 0.

* opts.c (common_handle_option): Process flag_ira_verbose.

* flags.h (flag_ira_verbose): New external definition.

	* toplev.h (flag_ira_assign_after_call_split,
	flag_ira_biased_coloring, flag_ira_split_around_calls):  Remove.

	* toplev.c (flag_ira_verbose): New external declaration.
	(finalize): Call finish_ira_once.

* print-rtl.c (flag_simple): Rename to flag_dump_simple_rtl.

	* doc/invoke.texi (-fno-ira-assign-after-call-split,
	-fira-biased-coloring, -fno-ira-split-around-calls):  Remove.
	(-fdump-simple-rtl, -fira-verbose): New options.

	* caller-save.c (insert_restore, insert_save): Use
	adjust_address_nv instead of adjust_address.  Check the mode by
	reg_save_code.

* ira-call.c: Remove file.

* ira-lives.c: New file.

	* Makefile.in (ira-live.o): Add
	(ira-call.o): Remove.
	(IRA_INT_H): Add alloc-pool.h.

* ira.h (finish_ira_once): New external definition.

	* ira-int.h (internal_flag_ira_verbose, alloc_pool allocno_pool,
	copy_pool, allocno_live_range_pool, ira_loop_tree_height,
	max_point, start_point_ranges, finish_point_ranges,
	prohibited_mode_move_regs, important_class_nums,
	ira_curr_regno_allocno_map, allocno_set_words): New external
	definitions.
	(loop_tree_node_t, allocno_live_range_t): New typedefs.  Use them
	everywhere.
	(ira_loop_tree_node): Rename to loop_tree_node.
	(loop_tree_node): New member level.
	(allocno_live_range): New structure.
	(allocno): New members nrefs, live_ranges,
	total_conflict_hard_regs, conflict_allocnos_num,
	total_conflict_allocnos_num, mem_optimized_dest,
	mem_optimized_dest_p, total_no_stack_reg_p.  Remove members
	conflict_allocno_vec_active_size and original_memory_cost.  Rename
	member curr_hard_reg_costs to updated_hard_reg_costs.
	(ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM,
	ALLOCNO_TOTAL_CONFLICT_HARD_REGS, ALLOCNO_CONFLICT_ALLOCNOS_NUM,
	ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM, ALLOCNO_NREFS,
	ALLOCNO_MEM_OPTIMIZED_DEST, ALLOCNO_MEM_OPTIMIZED_DEST_P,
	ALLOCNO_TOTAL_NO_STACK_REG_P, ALLOCNO_LIVE_RANGES): New access
	macros.
	(ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE,
	ALLOCNO_ORIGINAL_MEMORY_COST): Remove.
	(ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS): Rename to
	ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS.
	(allocno_copy): New member loop_tree_node.
	(INT_BITS, INT_TYPE, EXECUTE_IF_SET_IN_ALLOCNO_SET): Move from
	ira-conflicts.c.
	(SET_ALLOCNO_SET_BIT, CLEAR_ALLOCNO_SET_BIT,
	TEST_ALLOCNO_SET_BIT): New macros.
	(ira_reallocate, allocno_conflict_index, add_allocno_conflict,
	create_allocno_live_range, finish_allocno_live_range,
	add_allocno_copy_to_list, swap_allocno_copy_ends_if_necessary,
	remove_allocno_copy_from_list, add_allocno_copy, ira_flattening,
	finish_ira_costs_once, rebuild_start_finish_chains,
	print_live_range_list, debug_live_range_list,
	debug_allocno_live_ranges, debug_live_ranges,
	create_allocno_live_ranges, finish_allocno_live_ranges,
	allocno_conflict_p, loop_edge_freq): New external function
	definitions.
	(hard_reg_in_set_p, original_regno_call_crossed_p,
	ira_max_regno_before, ira_max_regno_call_before): Remove.
	(traverse_loop_tree): Add new parameter type.
	(create_copy): Ditto.
	(debug_conflicts, ira_emit, add_allocno_copy): Add parameter.
	(debug_ira_call_data, split_around_calls, get_around_calls_regno):
	Remove.
	
	* ira.c (setup_prohibited_mode_move_regs): New function.
	(internal_flag_ira_verbose, allocno_pool, copy_pool,
	allocno_live_range_pool, important_class_nums): New external
	variables.
	(IRA_NO_OBSTACK): Uncomment it.
	(ira_reallocate): New function.
	(setup_cover_classes): Set up important_class_nums.
	(finish_ira_once): New function.
	(prohibited_mode_move_regs,
	prohibited_mode_move_regs_initialized_p): New global variables.
	(setup_prohibited_mode_move_regs): New function.
	(setup_reg_renumber): Remove parameters.
	(setup_allocno_assignment_from_reg_renumber): Rename to
	setup_allocno_assignment_flags.  Set up ALLOCNO_ASSIGNED_P.
	(calculate_allocation_cost): Use ALLOCNO_UPDATED_MEMORY_COST.
	(ira_max_regno_before, ira_max_regno_call_before): Remove.
	(ira): Set up internal_flag_ira_verbose.  Call
	setup_prohibited_mode_move_regs.  Create and destroy allocno,
	copy, and live range pools.  Remove original_regno_call_crossed_p.
	Report major passes.  Use argument for ira_emit.  Call
	ira_flattening and df_analyze.  Remove live range splitting around
	calls.
	
	* ira-build.c (setup_loop_tree_level, rebuild_regno_allocno_maps,
	expand_calls, compress_calls, allocno_conflict_index,
	add_to_allocno_conflict_vec, propagate_info_to_cap,
	copy_allocno_live_range, copy_allocno_live_range_list,
	finish_allocno, finish_copy,
	propagate_info_to_loop_tree_node_caps, merge_ranges,
	common_loop_tree_node_dominator, check_and_add_conflicts,
	add_conflict_with_underlying_allocnos, ira_flattening): New
	functions.
	(check_coalesced_allocnos): Remove.
	(ira_loop_tree_height): New external variable.
	(form_loop_tree): Call setup_loop_tree_level.
	(initiate_calls): Allocate a bit more.  (create_allocno): Use
	pool_alloc.  Set up ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM,
	ALLOCNO_TOTAL_CONFLICT_HARD_REGS, ALLOCNO_NREFS,
	ALLOCNO_TOTAL_NO_STACK_REG_P, ALLOCNO_MEM_OPTIMIZED_DEST,
	ALLOCNO_MEM_OPTIMIZED_DEST_P, ALLOCNO_UPDATED_MEMORY_COST, and
	ALLOCNO_LIVE_RANGES.  Rename
	ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE,
	ALLOCNO_CURR_HARD_REG_COSTS, and
	ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS to
	ALLOCNO_CONFLICT_ALLOCNOS_NUM, ALLOCNO_UPDATED_HARD_REG_COSTS, and
	ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS.
	(add_allocno_conflict): Make it external.  Use
	add_to_allocno_conflict_vec.
	(create_cap_allocno): Move part of code to propagate_info_to_cap.
	(finish_allocnos): Use finish_allocno.
	(add_allocno_copy_to_list, remove_allocno_copy_from_list,
	swap_allocno_copy_ends_if_necessary, add_allocno_copy): Move from
	ira-conflicts.c.  Make them external.
	(create_copy): Use pool_alloc.  Add parameter loop_tree_node.
	(finish_copies): Use finish_copy.
	(ira_curr_regno_allocno_map): New external variable.
	(traverse_loop_tree): Add parameter bb_first_p.
	(create_insn_allocnos): Update ALLOCNO_NREFS.
	(create_loop_tree_node_allocnos): Traverse loop tree nodes with
	BBs first.  Update ALLOCNO_NREFS.
	(create_loop_tree_node_caps): Move part of code to
	propagate_info_to_loop_tree_node_cap.
	(regno_top_level_allocno_map): New global variable.
	(ira_build): Create caps before build conflicts.  Call
	create_allocno_live_ranges.  Propagate info to caps.  Report
	statistics.
	(ira_destroy): Call finish_allocno_live_ranges.

	* ira-conflicts.c (set_allocno_live, clear_allocno_live,
	record_regno_conflict, mark_reg_store, mark_reg_clobber,
	mark_reg_conflicts, mark_reg_death): Remove.
	(add_insn_allocno_copies, add_copies): New functions.
	(add_allocno_copy_to_list, remove_allocno_copy_from_list,
	swap_allocno_copy_ends_if_necessary, add_allocno_copy): Remove.
	(add_allocno_copies): Rename to add_insn_allocno_copies.  Use
	ira_curr_regno_allocno_map and add_insn_allocno_copies.
	(single_reg_class, single_reg_operand_class,
	process_single_reg_class_operands, process_bb_node_for_conflicts):
	Remove.
	(INT_BITS, INT_TYPE, EXECUTE_IF_SET_IN_ALLOCNO_SET): Move to
	ira-int.h.
	(allocnos_live_bitmap, SET_ALLOCNO_CONFLICT_ROW,
	CLEAR_ALLOCNO_CONFLICT_ROW, TEST_ALLOCNO_CONFLICT_ROW): Remove.
	(SET_ALLOCNO_LIVE, CLEAR_ALLOCNO_LIVE, TEST_ALLOCNO_LIVE):
	Use {SET, CLEAR, TEST}_ALLOCNO_SET_BIT.
	(allocno_row_words, hard_regs_live, curr_bb_node,
	curr_regno_allocno_map, curr_reg_pressure): Remove.
	(CONFLICTP): Rename to CONFLICT_P.
	(regs_set): Remove.
	(propagate_allocno_info): Use ALLOCNO_TOTAL_CONFLICT_HARD_REGS.
	Set up ALLOCNO_CALLS_CROSSED_START.
	(allocno_conflict_p): New function.
	(allocno_reg_conflict_p): Use allocno_conflict_p.
	(build_allocno_conflict_vects): Divide original and propagated
	conflicts.
	(print_hard_reg_set): New function.
	(print_conflicts): Use print_hard_reg_set.  Set up mark for the
	start of propagated conflicts.
	(debug_conflicts): Add parameter.
	(ira_build_conflicts): Call add_copies.  Set up
	ALLOCNO_TOTAL_CONFLICT_HARD_REGS.

	* ira-costs.c (struct costs): Make cost allocated dynamically.
	(struct_costs_size, temp_cots, op_costs, this_op_costs): New
	variables.
	(costs): Rename to total_costs.
	(COSTS_OF_ALLOCNO): New macro.
	(curr_regno_allocno_map): Remove.  Use ira_curr_regno_allocno_map
	instead.
	(record_reg_classes): Check NO_REGS in allocno_pref.
	(record_address_regs): Use COSTS_OF_ALLOCNO.
	(scan_one_insn): Ditto.
	(print_costs): Ditto.
	(find_allocno_class_costs): Ditto.  Pass additional argument to
	traverse_loop_tree.  Set up NO_REGS if memory is cheaper.
	(setup_allocno_cover_class_and_costs): Use
	ALLOCNO_UPDATED_MEMORY_COST instead of
	ALLOCNO_ORIGINAL_MEMORY_COST, ALLOCNO_UPDATED_HARD_REG_COSTS
	instead of ALLOCNO_CURR_HARD_REG_COSTS, and
	ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS instead of
	ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS.  Pass additional argument to
	traverse_loop_tree.
	(init_ira_costs_once): Allocate init_cost, op_costs,
	this_op_costs, temp_costs.
	(finish_ira_costs_once): New function.
	
	* ira-color.c: Use ALLOCNO_UPDATED_MEMORY_COST instead of
	ALLOCNO_ORIGINAL_MEMORY_COST, ALLOCNO_UPDATED_HARD_REG_COSTS
	instead of ALLOCNO_CURR_HARD_REG_COSTS, and
	ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS instead of
	ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS.  Use
	ALLOCNO_TOTAL_CONFLICT_HARD_REGS instead of
	ALLOCNO_CONFLICT_HARD_REGS.
	(processed_allocno_bitmap): Rename into
	processed_coalesced_allocno_bitmap.
	(allocno_cost_compare_func): Use ALLOCNO_UPDATED_MEMORY_COST
	instead of ALLOCNO_MEMORY_COST.
	(assign_hard_reg): Remove biased coloring.
	(add_allocno_to_ordered_bucket): Check cover class first.
	(loop_edge_freq): Make it external.
	(setup_allocno_left_conflicts_num): Check that conflicting
	allocnos of one class.
	(allocno_conflict_p): Rename to coalesced_allocno_conflict_p.
	(color_pass): Check pressure in the loop (not in subloops) for
	mixed algorithm.
	(allocno_priorities): New variable.
	(start_allocno_priorities, finish_allocno_priorities): New
	functions.
	(allocno_priority_compare_func): Use allocno_priorities.
	(priority_coloring): Call start_allocno_priorities and
	finish_allocno_priorities.
	(do_coloring): Pass additional argument to traverse_loop_tree.
	
	* ira-emit.c (struct move): Add member insn.
	(create_move): Initialize member insn.
	(generate_edge_moves): Set up ALLOCNO_MEM_OPTIMIZED_DEST and
	ALLOCNO_MEM_OPTIMIZED_DEST_P.
	(change_loop): Check prohibited_mode_move_regs.
	(curr_jump_map, can_move_through_p): Remove.
	(unify_moves): Don't move through jump.
	(modify_move_list): Set up attributes for new allocno used for
	breaking dependency loops.
	(emit_move_list): Set up insn codes.
	(update_costs, add_range_and_copies_from_move_list,
	add_ranges_and_copies): New functions.
	(ira_emit): Add a parameter.  Call add_ranges_and_copies.
	

Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 129968)
+++ doc/invoke.texi	(working copy)
@@ -274,6 +274,7 @@ Objective-C and Objective-C++ Dialects}.
 -fdbg-cnt-list -fdbg-cnt=@var{counter-value-list} @gol
 -fdump-noaddr -fdump-unnumbered  -fdump-translation-unit@r{[}-@var{n}@r{]} @gol
 -fdump-class-hierarchy@r{[}-@var{n}@r{]} @gol
+-fdump-simple-rtl @gol
 -fdump-ipa-all -fdump-ipa-cgraph @gol
 -fdump-tree-all @gol
 -fdump-tree-original@r{[}-@var{n}@r{]}  @gol
@@ -329,11 +330,10 @@ Objective-C and Objective-C++ Dialects}.
 -fcrossjumping  -fif-conversion  -fif-conversion2 @gol
 -finline-functions  -finline-functions-called-once @gol
 -finline-limit=@var{n} -fira -fira-algorithm=@var{algorithm} @gol
--fno-ira-assign-after-call-split @gol
--fira-biased-coloring -fira-coalesce -fira-ipra -fno-ira-move-spills @gol
+-fira-coalesce -fira-ipra -fno-ira-move-spills @gol
 -fira-propagate-cost @gol
 -fno-ira-share-spill-slots -fno-ira-share-save-slots @gol
--fno-ira-split-around-calls @gol
+-fira-verbose=@var{n} @gol
 -fkeep-inline-functions -fkeep-static-consts @gol
 -fmerge-constants  -fmerge-all-constants @gol
 -fmodulo-sched -fmodulo-sched-allow-regmoves -fno-branch-count-reg @gol
@@ -4578,6 +4578,11 @@ numbers and address output.  This makes 
 use diff on debugging dumps for compiler invocations with different
 options, in particular with and without @option{-g}.
 
+@item -fdump-simple-rtl
+@opindex fdump-simple-rtl
+When doing debugging dumps (see @option{-d} option above), suppress
+output of flags, modes, etc.  This makes rtl dumps more compact.
+
 @item -fdump-translation-unit @r{(C++ only)}
 @itemx -fdump-translation-unit-@var{options} @r{(C++ only)}
 @opindex fdump-translation-unit
@@ -5541,19 +5546,6 @@ decent code and the smallest size code, 
 fastest one, and the mixed algorithm can give the best result in some
 cases.
 
-@item -fno-ira-assign-after-call-split
-@opindex fno-ira-assign-after-call-split
-Switch off additional assignment after splitting pseudos around calls.
-After splitting pseudos there is a chance that spilled pseudos
-conflicting with the new pseudos living through calls gets a hard
-register.
-
-@item -fira-biased-coloring
-@opindex fira-biased-coloring
-Use biased coloring for the integrated register allocator for possible
-improvement of the generated code.  It makes register allocator
-slower.
-
 @item -fira-coalescing
 @opindex fira-coalescing
 Do optimistic register coalescing.  This option might be profitable for
@@ -5588,11 +5580,11 @@ Switch off sharing stack slots allocated
 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 -fno-ira-split-around-calls
-@opindex fno-ira-split-around-calls
-Switch off splitting pseudos around calls before the reload.  By
-default save restore insns are generated by splitting pseudos around
-the calls in the integrated register allocator instead of the reload.
+@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
Index: ira-conflicts.c
===================================================================
--- ira-conflicts.c	(revision 129968)
+++ ira-conflicts.c	(working copy)
@@ -41,66 +41,26 @@ Software Foundation, 51 Franklin Street,
 /* The file contains code is analogous to one in global but the code
    works on the allocno basis.  */
 
-static void set_allocno_live (allocno_t);
-static void clear_allocno_live (allocno_t);
-static void record_regno_conflict (int);
-static void mark_reg_store (rtx, const_rtx, void *);
-static void mark_reg_clobber (rtx, const_rtx, void *);
-static void mark_reg_conflicts (rtx);
-static void mark_reg_death (rtx);
+static void build_conflict_bit_table (void);
+static void mirror_conflicts (void);
 static int commutative_constraint_p (const char *);
 static int get_dup_num (int, int);
 static rtx get_dup (int, int);
-static void add_allocno_copy_to_list (copy_t);
-static void remove_allocno_copy_from_list (copy_t);
-static void swap_allocno_copy_ends_if_necessary (copy_t);
-static void add_allocno_copies (rtx);
-static enum reg_class single_reg_class (const char *, rtx op, rtx);
-static enum reg_class single_reg_operand_class (int);
-static void process_single_reg_class_operands (int);
-static void process_bb_node_for_conflicts (struct ira_loop_tree_node *);
-static void build_conflict_bit_table (void);
+static void add_insn_allocno_copies (rtx);
+static void add_copies (loop_tree_node_t);
 static void propagate_allocno_info (allocno_t);
 static void propagate_info (void);
-static void mirror_conflicts (void);
 static void remove_conflict_allocno_copies (void);
 static void build_allocno_conflict_vects (void);
-static void propagate_modified_regnos (struct ira_loop_tree_node *);
-static void print_conflicts (FILE *);
-
-/* The number of bits in each element of `conflicts' and what
-   type that element has.  We use the largest integer format on the
-   host machine.  */
-#define INT_BITS HOST_BITS_PER_WIDE_INT
-#define INT_TYPE HOST_WIDE_INT
-
-/* Bit mask for allocnos live at current point in the scan.  */
-static INT_TYPE *allocnos_live;
-
-/* The same as previous but as bitmap.  */
-static bitmap allocnos_live_bitmap;
-
-/* Set, clear or test bit number I in R, a bit vector indexed by
-   allocno number.  */
-#define SET_ALLOCNO_CONFLICT_ROW(R, I)				\
-  ((R)[(unsigned) (I) / INT_BITS]				\
-   |= ((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
-
-#define CLEAR_ALLOCNO_CONFLICT_ROW(R, I)				\
-  ((R) [(unsigned) (I) / INT_BITS]				\
-   &= ~((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
-
-#define TEST_ALLOCNO_CONFLICT_ROW(R, I)				\
-  ((R) [(unsigned) (I) / INT_BITS]				\
-   & ((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
+static void propagate_modified_regnos (loop_tree_node_t);
+static void print_hard_reg_set (FILE *, const char *, HARD_REG_SET);
+static void print_conflicts (FILE *, int);
 
 /* Set, clear or test bit number I in `allocnos_live',
    a bit vector indexed by allocno number.  */
-#define SET_ALLOCNO_LIVE(I) SET_ALLOCNO_CONFLICT_ROW (allocnos_live, I)
-
-#define CLEAR_ALLOCNO_LIVE(I) CLEAR_ALLOCNO_CONFLICT_ROW (allocnos_live, I)
-
-#define TEST_ALLOCNO_LIVE(I) TEST_ALLOCNO_CONFLICT_ROW (allocnos_live, I)
+#define SET_ALLOCNO_LIVE(I) SET_ALLOCNO_SET_BIT (allocnos_live, I)
+#define CLEAR_ALLOCNO_LIVE(I) CLEAR_ALLOCNO_SET_BIT (allocnos_live, I)
+#define TEST_ALLOCNO_LIVE(I) TEST_ALLOCNO_SET_BIT (allocnos_live, I)
 
 /* allocnos_num by allocnos_num array of bits, recording whether two
    allocno's conflict (can't go in the same hardware register).
@@ -108,265 +68,84 @@ static bitmap allocnos_live_bitmap;
    `conflicts' is symmetric after the call to mirror_conflicts.  */
 static INT_TYPE *conflicts;
 
-/* Number of ints required to hold allocnos_num bits.  This is the
-   length of a row in `conflicts'.  */
-static int allocno_row_words;
-
 /* Two macros to test 1 in an element of `conflicts'.  */
-#define CONFLICTP(I, J) \
- (conflicts[(I) * allocno_row_words + (unsigned) (J) / INT_BITS]	\
+#define CONFLICT_P(I, J)						\
+ (conflicts[(I) * allocno_set_words + (unsigned) (J) / INT_BITS]	\
   & ((INT_TYPE) 1 << ((unsigned) (J) % INT_BITS)))
 
-/* For each allocno set in ALLOCNO_SET, set ALLOCNO to that allocno, and
-   execute CODE.  */
-#define EXECUTE_IF_SET_IN_ALLOCNO_SET(ALLOCNO_SET, ALLOCNO, CODE)		\
-do {									\
-  int i_;								\
-  int allocno_;								\
-  INT_TYPE *p_ = (ALLOCNO_SET);						\
-									\
-  for (i_ = allocno_row_words - 1, allocno_ = 0; i_ >= 0;			\
-       i_--, allocno_ += INT_BITS)					\
-    {									\
-      unsigned INT_TYPE word_ = (unsigned INT_TYPE) *p_++;		\
-									\
-      for ((ALLOCNO) = allocno_; word_; word_ >>= 1, (ALLOCNO)++)		\
-	{								\
-	  if (word_ & 1)						\
-	    {CODE;}							\
-	}								\
-    }									\
-} while (0)
-
-
-/* Set of hard regs (except eliminable ones) currently live (during
-   scan of all insns).  */
-static HARD_REG_SET hard_regs_live;
-
-/* Loop tree node corresponding to the current basic block.  */
-static struct ira_loop_tree_node *curr_bb_node;
-
-/* Current map regno -> allocno.  */
-static allocno_t *curr_regno_allocno_map;
-
-/* The current pressure for the current basic block.  */
-static int curr_reg_pressure [N_REG_CLASSES];
-
-/* The function marks allocno A as currently living.  */
-static void
-set_allocno_live (allocno_t a)
-{
-  enum reg_class cover_class;
-
-  if (TEST_ALLOCNO_LIVE (ALLOCNO_NUM (a)))
-    return;
-  SET_ALLOCNO_LIVE (ALLOCNO_NUM (a));
-  bitmap_set_bit (allocnos_live_bitmap, ALLOCNO_NUM (a));
-  cover_class = ALLOCNO_COVER_CLASS (a);
-  curr_reg_pressure [cover_class]
-    += reg_class_nregs [cover_class] [ALLOCNO_MODE (a)];
-  if (curr_bb_node->reg_pressure [cover_class]
-      < curr_reg_pressure [cover_class])
-    curr_bb_node->reg_pressure [cover_class]
-      = curr_reg_pressure [cover_class];
-}
-
-/* The function marks allocno A as currently not living.  */
-static void
-clear_allocno_live (allocno_t a)
-{
-  enum reg_class cover_class;
-
-  if (bitmap_bit_p (allocnos_live_bitmap, ALLOCNO_NUM (a)))
-    {
-      cover_class = ALLOCNO_COVER_CLASS (a);
-      curr_reg_pressure [cover_class]
-	-= reg_class_nregs [cover_class] [ALLOCNO_MODE (a)];
-      ira_assert (curr_reg_pressure [cover_class] >= 0);
-    }
-  CLEAR_ALLOCNO_LIVE (ALLOCNO_NUM (a));
-  bitmap_clear_bit (allocnos_live_bitmap, ALLOCNO_NUM (a));
-}
-
-/* Record all regs that are set in any one insn.  Communication from
-   mark_reg_{store,clobber} and build_conflict_bit_table.  */
-static VEC(rtx, heap) *regs_set;
-
-/* Record a conflict between hard register REGNO or allocno
-   corresponding to pseudo-register REGNO and everything currently
-   live.  */
-static void
-record_regno_conflict (int regno)
-{
-  int j;
-
-  if (regno < FIRST_PSEUDO_REGISTER)
-    {
-      /* When a hard register becomes live, record conflicts with live
-	 allocno regs.  */
-      EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, j,
-        {
-	  SET_HARD_REG_BIT (ALLOCNO_CONFLICT_HARD_REGS (allocnos [j]), regno);
-	});
-    }
-  else
-    {
-      /* When a pseudo-register becomes live, record conflicts first
-	 with hard regs, then with other allocnos.  */
-      allocno_t a = curr_regno_allocno_map [regno];
-      int pn, pn_prod;
-
-      ira_assert (a != NULL || REG_N_REFS (regno) == 0);
-      if (a == NULL)
-	return;
-      pn = ALLOCNO_NUM (a);
-      pn_prod = pn * allocno_row_words;
-      IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), hard_regs_live);
-      for (j = allocno_row_words - 1; j >= 0; j--)
-	conflicts [pn_prod + j] |= allocnos_live [j];
-      /* Don't set up conflict for the allocno with itself.  */
-      CLEAR_ALLOCNO_CONFLICT_ROW (conflicts + pn_prod, pn);
-    }
-}
-
-/* Handle the case where REG is set by the insn being scanned, during
-   the scan to accumulate conflicts.  Store a 1 in hard_regs_live or
-   allocnos_live for this register or the corresponding allocno, record
-   how many consecutive hardware registers it actually needs, and
-   record a conflict with all other allocnos already live.
-
-   Note that even if REG does not remain alive after this insn, we
-   must mark it here as live, to ensure a conflict between REG and any
-   other allocnos set in this insn that really do live.  This is
-   because those other allocnos could be considered after this.
+/* Bit mask for allocnos live at current point in the scan.  */
+static INT_TYPE *allocnos_live;
 
-   REG might actually be something other than a register; if so, we do
-   nothing.
+
 
-   SETTER is 0 if this register was modified by an auto-increment
-   (i.e., a REG_INC note was found for it).  */
+/* The function builds allocno conflict table by processing allocno
+   live ranges.  */
 static void
-mark_reg_store (rtx reg, const_rtx setter ATTRIBUTE_UNUSED,
-		void *data ATTRIBUTE_UNUSED)
+build_conflict_bit_table (void)
 {
-  int regno;
-
-  if (GET_CODE (reg) == SUBREG)
-    reg = SUBREG_REG (reg);
+  int i, j, pn, pn_prod;
+  allocno_live_range_t r;
 
-  if (! REG_P (reg))
-    return;
-
-  VEC_safe_push (rtx, heap, regs_set, reg);
-
-  regno = REGNO (reg);
-
-  if (regno >= FIRST_PSEUDO_REGISTER)
-    {
-      allocno_t a = curr_regno_allocno_map [regno];
-
-      ira_assert (a != NULL || REG_N_REFS (regno) == 0);
-      if (a != NULL)
-	set_allocno_live (a);
-      record_regno_conflict (regno);
-    }
-  else if (! TEST_HARD_REG_BIT (no_alloc_regs, regno))
+  allocno_set_words = (allocnos_num + INT_BITS - 1) / INT_BITS;
+  allocnos_live = ira_allocate (sizeof (INT_TYPE) * allocno_set_words);
+  memset (allocnos_live, 0, sizeof (INT_TYPE) * allocno_set_words);
+  conflicts = ira_allocate (sizeof (INT_TYPE)
+			    * allocnos_num * allocno_set_words);
+  memset (conflicts, 0, sizeof (INT_TYPE) * allocnos_num * allocno_set_words);
+  for (i = 0; i < max_point; i++)
     {
-      int last = regno + hard_regno_nregs [regno] [GET_MODE (reg)];
-      enum reg_class cover_class;
-
-      while (regno < last)
+      for (r = start_point_ranges [i]; r != NULL; r = r->start_next)
 	{
-	  record_regno_conflict (regno);
-	  if (! TEST_HARD_REG_BIT (eliminable_regset, regno)
-	      && ! TEST_HARD_REG_BIT (hard_regs_live, regno))
-	    {
-	      cover_class = class_translate [REGNO_REG_CLASS (regno)];
-	      curr_reg_pressure [cover_class]++;
-	      SET_HARD_REG_BIT (hard_regs_live, regno);
-	      if (curr_bb_node->reg_pressure [cover_class]
-		  < curr_reg_pressure [cover_class])
-		curr_bb_node->reg_pressure [cover_class]
-		  = curr_reg_pressure [cover_class];
-	    }
-	  regno++;
+	  pn = ALLOCNO_NUM (r->allocno);
+	  SET_ALLOCNO_LIVE (pn);
+	  pn_prod = pn * allocno_set_words;
+	  for (j = allocno_set_words - 1; j >= 0; j--)
+	    conflicts [pn_prod + j] |= allocnos_live [j];
+	  /* Don't set up conflict for the allocno with itself.  */
+	  CLEAR_ALLOCNO_SET_BIT (conflicts + pn_prod, pn);
 	}
+	  
+      for (r = finish_point_ranges [i]; r != NULL; r = r->finish_next)
+	CLEAR_ALLOCNO_LIVE (ALLOCNO_NUM (r->allocno));
     }
 }
 
-/* Like mark_reg_store except notice just CLOBBERs; ignore SETs.  */
+/* If CONFLICT_P (i, j) is TRUE, make sure CONFLICT_P (j, i) is also TRUE.  */
 static void
-mark_reg_clobber (rtx reg, const_rtx setter, void *data)
-{
-  if (GET_CODE (setter) == CLOBBER)
-    mark_reg_store (reg, setter, data);
-}
-
-/* Record that REG (or the corresponding allocno) has conflicts with
-   all the allocno currently live.  Do not mark REG (or the allocno)
-   itself as live.  */
-static void
-mark_reg_conflicts (rtx reg)
+mirror_conflicts (void)
 {
-  int regno;
-
-  if (GET_CODE (reg) == SUBREG)
-    reg = SUBREG_REG (reg);
-
-  if (! REG_P (reg))
-    return;
-
-  regno = REGNO (reg);
+  int i, j;
+  unsigned INT_TYPE mask;
+  int rw = allocno_set_words;
+  int rwb = rw * INT_BITS;
+  INT_TYPE *p = conflicts;
+  INT_TYPE *q0 = conflicts;
+  INT_TYPE *q1, *q2;
 
-  if (regno >= FIRST_PSEUDO_REGISTER)
-    record_regno_conflict (regno);
-  else if (! TEST_HARD_REG_BIT (no_alloc_regs, regno))
+  for (i = allocnos_num - 1, mask = 1; i >= 0; i--, mask <<= 1)
     {
-      int last = regno + hard_regno_nregs [regno] [GET_MODE (reg)];
-
-      while (regno < last)
+      if (! mask)
 	{
-	  record_regno_conflict (regno);
-	  regno++;
+	  mask = 1;
+	  q0++;
 	}
-    }
-}
-
-/* Mark REG (or the corresponding allocno) as being dead (following the
-   insn being scanned now).  Store a 0 in hard_regs_live or
-   allocnos_live for this register.  */
-static void
-mark_reg_death (rtx reg)
-{
-  int regno = REGNO (reg);
-
-  if (regno >= FIRST_PSEUDO_REGISTER)
-    {
-      allocno_t a = curr_regno_allocno_map [regno];
-
-      ira_assert (a != NULL || REG_N_REFS (regno) == 0);
-      if (a != NULL)
-	clear_allocno_live (a);
-    }
-  else if (! TEST_HARD_REG_BIT (no_alloc_regs, regno))
-    {
-      int last = regno + hard_regno_nregs [regno] [GET_MODE (reg)];
-      enum reg_class cover_class;
-
-      while (regno < last)
+      for (j = allocno_set_words - 1, q1 = q0; j >= 0; j--, q1 += rwb)
 	{
-	  if (TEST_HARD_REG_BIT (hard_regs_live, regno))
+	  unsigned INT_TYPE word;
+
+	  for (word = (unsigned INT_TYPE) *p++, q2 = q1;
+	       word;
+	       word >>= 1, q2 += rw)
 	    {
-	      cover_class = class_translate [REGNO_REG_CLASS (regno)];
-	      curr_reg_pressure [cover_class]--;
-	      ira_assert (curr_reg_pressure [cover_class] >= 0);
-	      CLEAR_HARD_REG_BIT (hard_regs_live, regno);
+	      if (word & 1)
+		*q2 |= mask;
 	    }
-	  regno++;
 	}
     }
 }
 
+
+
 /* The function returns nonzero, if the operand constraint STR is
    commutative.  */
 static int
@@ -405,7 +184,7 @@ get_dup_num (int op_num, int use_commut_
   int curr_alt, c, original, dup;
   int ignore_p, commut_op_used_p;
   const char *str;
-  rtx op, equiv_const = NULL_RTX; /* ??? */
+  rtx op, equiv_const = NULL_RTX;
 
   if (op_num < 0 || recog_data.n_alternatives == 0)
     return -1;
@@ -579,120 +358,11 @@ get_dup (int op_num, int use_commut_op_p
     return recog_data.operand [n];
 }
 
-/* The function attaches copy CP to allocnos involved into the copy.  */
-static void
-add_allocno_copy_to_list (copy_t cp)
-{
-  allocno_t first = cp->first, second = cp->second;
-
-  cp->prev_first_allocno_copy = NULL;
-  cp->prev_second_allocno_copy = NULL;
-  cp->next_first_allocno_copy = ALLOCNO_COPIES (first);
-  if (cp->next_first_allocno_copy != NULL)
-    {
-      if (cp->next_first_allocno_copy->first == first)
-	cp->next_first_allocno_copy->prev_first_allocno_copy = cp;
-      else
-	cp->next_first_allocno_copy->prev_second_allocno_copy = cp;
-    }
-  cp->next_second_allocno_copy = ALLOCNO_COPIES (second);
-  if (cp->next_second_allocno_copy != NULL)
-    {
-      if (cp->next_second_allocno_copy->second == second)
-	cp->next_second_allocno_copy->prev_second_allocno_copy = cp;
-      else
-	cp->next_second_allocno_copy->prev_first_allocno_copy = cp;
-    }
-  ALLOCNO_COPIES (first) = cp;
-  ALLOCNO_COPIES (second) = cp;
-}
-
-/* The function detaches copy CP from allocnos involved into the copy.  */
-static void
-remove_allocno_copy_from_list (copy_t cp)
-{
-  allocno_t first = cp->first, second = cp->second;
-  copy_t prev, next;
-
-  next = cp->next_first_allocno_copy;
-  prev = cp->prev_first_allocno_copy;
-  if (prev == NULL)
-    ALLOCNO_COPIES (first) = next;
-  else if (prev->first == first)
-    prev->next_first_allocno_copy = next;
-  else
-    prev->next_second_allocno_copy = next;
-  if (next != NULL)
-    {
-      if (next->first == first)
-	next->prev_first_allocno_copy = prev;
-      else
-	next->prev_second_allocno_copy = prev;
-    }
-  cp->prev_first_allocno_copy = cp->next_first_allocno_copy = NULL;
-
-  next = cp->next_second_allocno_copy;
-  prev = cp->prev_second_allocno_copy;
-  if (prev == NULL)
-    ALLOCNO_COPIES (second) = next;
-  else if (prev->second == second)
-    prev->next_second_allocno_copy = next;
-  else
-    prev->next_first_allocno_copy = next;
-  if (next != NULL)
-    {
-      if (next->second == second)
-	next->prev_second_allocno_copy = prev;
-      else
-	next->prev_first_allocno_copy = prev;
-    }
-  cp->prev_second_allocno_copy = cp->next_second_allocno_copy = NULL;
-}
-
-/* The function makes copy CP a canonical copy where number of the
-   first allocno is less than the second one.  */
-static void
-swap_allocno_copy_ends_if_necessary (copy_t cp)
-{
-  allocno_t temp;
-  copy_t temp_cp;
-
-  if (ALLOCNO_NUM (cp->first) <= ALLOCNO_NUM (cp->second))
-    return;
-
-  temp = cp->first;
-  cp->first = cp->second;
-  cp->second = temp;
-
-  temp_cp = cp->prev_first_allocno_copy;
-  cp->prev_first_allocno_copy = cp->prev_second_allocno_copy;
-  cp->prev_second_allocno_copy = temp_cp;
-
-  temp_cp = cp->next_first_allocno_copy;
-  cp->next_first_allocno_copy = cp->next_second_allocno_copy;
-  cp->next_second_allocno_copy = temp_cp;
-}
-
-/* The function creates and returns new copy of allocnos FIRST and
-   SECOND with frequency FREQ corresponding to move insn INSN (if
-   any).  */
-copy_t
-add_allocno_copy (allocno_t first, allocno_t second, int freq, rtx insn)
-{
-  copy_t cp;
-
-  cp = create_copy (first, second, freq, insn);
-  ira_assert (first != NULL && second != NULL);
-  add_allocno_copy_to_list (cp);
-  swap_allocno_copy_ends_if_necessary (cp);
-  return cp;
-}
-
 /* The function processes INSN and create allocno copies if
    necessary.  For example, it might be because INSN is a
    pseudo-register move or INSN is two operand insn.  */
 static void
-add_allocno_copies (rtx insn)
+add_insn_allocno_copies (rtx insn)
 {
   rtx set, operand, dup;
   const char *str;
@@ -719,12 +389,12 @@ add_allocno_copies (rtx insn)
 	      if (HARD_REGISTER_P (SET_SRC (set)))
 		return;
 	      hard_regno = REGNO (SET_DEST (set));
-	      a = curr_regno_allocno_map [REGNO (SET_SRC (set))];
+	      a = ira_curr_regno_allocno_map [REGNO (SET_SRC (set))];
 	    }
 	  else
 	    {
 	      hard_regno = REGNO (SET_SRC (set));
-	      a = curr_regno_allocno_map [REGNO (SET_DEST (set))];
+	      a = ira_curr_regno_allocno_map [REGNO (SET_DEST (set))];
 	    }
 	  class = REGNO_REG_CLASS (hard_regno);
 	  mode = ALLOCNO_MODE (a);
@@ -747,9 +417,10 @@ add_allocno_copies (rtx insn)
 	}
       else
 	{
-	  cp = add_allocno_copy (curr_regno_allocno_map [REGNO (SET_DEST (set))],
-				 curr_regno_allocno_map [REGNO (SET_SRC (set))],
-				 freq, insn);
+	  cp = add_allocno_copy
+	       (ira_curr_regno_allocno_map [REGNO (SET_DEST (set))],
+		ira_curr_regno_allocno_map [REGNO (SET_SRC (set))],
+		freq, insn, ira_curr_loop_tree_node);
 	  bitmap_set_bit (ira_curr_loop_tree_node->local_copies, cp->num); 
 	}
     }
@@ -778,12 +449,12 @@ add_allocno_copies (rtx insn)
 			    if (HARD_REGISTER_P (dup))
 			      continue;
 			    hard_regno = REGNO (operand);
-			    a = curr_regno_allocno_map [REGNO (dup)];
+			    a = ira_curr_regno_allocno_map [REGNO (dup)];
 			  }
 			else
 			  {
 			    hard_regno = REGNO (dup);
-			    a = curr_regno_allocno_map [REGNO (operand)];
+			    a = ira_curr_regno_allocno_map [REGNO (operand)];
 			  }
 			class = REGNO_REG_CLASS (hard_regno);
 			mode = ALLOCNO_MODE (a);
@@ -809,9 +480,9 @@ add_allocno_copies (rtx insn)
 		      {
 			bound_p = TRUE;
 			cp = add_allocno_copy
-			     (curr_regno_allocno_map [REGNO (dup)],
-			      curr_regno_allocno_map [REGNO (operand)],
-			      freq, NULL_RTX);
+			     (ira_curr_regno_allocno_map [REGNO (dup)],
+			      ira_curr_regno_allocno_map [REGNO (operand)],
+			      freq, NULL_RTX, ira_curr_loop_tree_node);
 			bitmap_set_bit
 			  (ira_curr_loop_tree_node->local_copies, cp->num);
 		      }
@@ -837,12 +508,12 @@ add_allocno_copies (rtx insn)
 			    if (HARD_REGISTER_P (dup))
 			      continue;
 			    hard_regno = REGNO (operand);
-			    a = curr_regno_allocno_map [REGNO (dup)];
+			    a = ira_curr_regno_allocno_map [REGNO (dup)];
 			  }
 			else
 			  {
 			    hard_regno = REGNO (dup);
-			    a = curr_regno_allocno_map [REGNO (operand)];
+			    a = ira_curr_regno_allocno_map [REGNO (operand)];
 			  }
 			class = REGNO_REG_CLASS (hard_regno);
 			mode = ALLOCNO_MODE (a);
@@ -866,9 +537,10 @@ add_allocno_copies (rtx insn)
 		    else
 		      {
 			cp = add_allocno_copy
-			     (curr_regno_allocno_map [REGNO (dup)],
-			      curr_regno_allocno_map [REGNO (operand)],
-			      (freq < 8 ? 1 : freq / 8), NULL_RTX);
+			     (ira_curr_regno_allocno_map [REGNO (dup)],
+			      ira_curr_regno_allocno_map [REGNO (operand)],
+			      (freq < 8 ? 1 : freq / 8), NULL_RTX,
+			      ira_curr_loop_tree_node);
 			bitmap_set_bit
 			  (ira_curr_loop_tree_node->local_copies, cp->num);
 		      }
@@ -878,448 +550,20 @@ add_allocno_copies (rtx insn)
     }
 }
 
-/* The function checks that CONSTRAINTS permits to use only one hard
-   register.  If it is so, the function returns the class of the hard
-   register.  Otherwise it returns NO_REGS.
-
-   EQUIV_COSNT ??? */
-static enum reg_class
-single_reg_class (const char *constraints, rtx op, rtx equiv_const)
-{
-  int ignore_p;
-  enum reg_class cl, next_cl;
-  int c;
-
-  cl = NO_REGS;
-  for (ignore_p = FALSE;
-       (c = *constraints);
-       constraints += CONSTRAINT_LEN (c, constraints))
-    if (c == '#')
-      ignore_p = TRUE;
-    else if (c == ',')
-      ignore_p = FALSE;
-    else if (! ignore_p)
-      switch (c)
-	{
-	case ' ':
-	case '\t':
-	case '=':
-	case '+':
-	case '*':
-	case '&':
-	case '%':
-	case '!':
-	case '?':
-	  break;
-	case 'i':
-	  if (CONSTANT_P (op)
-	      || (equiv_const != NULL_RTX && CONSTANT_P (equiv_const)))
-	    return NO_REGS;
-	  break;
-
-	case 'n':
-	  if (GET_CODE (op) == CONST_INT
-	      || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
-	      || (equiv_const != NULL_RTX
-		  && (GET_CODE (equiv_const) == CONST_INT
-		      || (GET_CODE (equiv_const) == CONST_DOUBLE
-			  && GET_MODE (equiv_const) == VOIDmode))))
-	    return NO_REGS;
-	  break;
-	  
-	case 's':
-	  if ((CONSTANT_P (op) && GET_CODE (op) != CONST_INT
-	       && (GET_CODE (op) != CONST_DOUBLE || GET_MODE (op) != VOIDmode))
-	      || (equiv_const != NULL_RTX
-		  && CONSTANT_P (equiv_const)
-		  && GET_CODE (equiv_const) != CONST_INT
-		  && (GET_CODE (equiv_const) != CONST_DOUBLE
-		      || GET_MODE (equiv_const) != VOIDmode)))
-	    return NO_REGS;
-	  break;
-	  
-	case 'I':
-	case 'J':
-	case 'K':
-	case 'L':
-	case 'M':
-	case 'N':
-	case 'O':
-	case 'P':
-	  if ((GET_CODE (op) == CONST_INT
-	       && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, constraints))
-	      || (equiv_const != NULL_RTX
-		  && GET_CODE (equiv_const) == CONST_INT
-		  && CONST_OK_FOR_CONSTRAINT_P (INTVAL (equiv_const),
-						c, constraints)))
-	    return NO_REGS;
-	  break;
-	  
-	case 'E':
-	case 'F':
-	  if (GET_CODE (op) == CONST_DOUBLE
-	      || (GET_CODE (op) == CONST_VECTOR
-		  && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT)
-	      || (equiv_const != NULL_RTX
-		  && (GET_CODE (equiv_const) == CONST_DOUBLE
-		      || (GET_CODE (equiv_const) == CONST_VECTOR
-			  && (GET_MODE_CLASS (GET_MODE (equiv_const))
-			      == MODE_VECTOR_FLOAT)))))
-	    return NO_REGS;
-	  break;
-	  
-	case 'G':
-	case 'H':
-	  if ((GET_CODE (op) == CONST_DOUBLE
-	       && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, constraints))
-	      || (equiv_const != NULL_RTX
-		  && GET_CODE (equiv_const) == CONST_DOUBLE
-		  && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (equiv_const,
-						       c, constraints)))
-	    return NO_REGS;
-	  /* ??? what about memory */
-	case 'r':
-	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-	case 'h': case 'j': case 'k': case 'l':
-	case 'q': case 't': case 'u':
-	case 'v': case 'w': case 'x': case 'y': case 'z':
-	case 'A': case 'B': case 'C': case 'D':
-	case 'Q': case 'R': case 'S': case 'T': case 'U':
-	case 'W': case 'Y': case 'Z':
-	  next_cl = (c == 'r'
-		     ? GENERAL_REGS
-		     : REG_CLASS_FROM_CONSTRAINT (c, constraints));
-	  if ((cl != NO_REGS && next_cl != cl)
-	      || available_class_regs [next_cl] > 1)
-	    return NO_REGS;
-	  cl = next_cl;
-	  break;
-	  
-	case '0': case '1': case '2': case '3': case '4':
-	case '5': case '6': case '7': case '8': case '9':
-	  next_cl
-	    = single_reg_class (recog_data.constraints [c - '0'],
-				recog_data.operand [c - '0'], NULL_RTX);
-	  if ((cl != NO_REGS && next_cl != cl) || next_cl == NO_REGS
-	      || available_class_regs [next_cl] > 1)
-	    return NO_REGS;
-	  cl = next_cl;
-	  break;
-	  
-	default:
-	  return NO_REGS;
-	}
-  return cl;
-}
-
-/* The function checks that operand OP_NUM of the current insn can use
-   only one hard register.  If it is so, the function returns the
-   class of the hard register.  Otherwise it returns NO_REGS.  */
-static enum reg_class
-single_reg_operand_class (int op_num)
-{
-  if (op_num < 0 || recog_data.n_alternatives == 0)
-    return NO_REGS;
-  return single_reg_class (recog_data.constraints [op_num],
-			   recog_data.operand [op_num], NULL_RTX);
-}
-
-/* The function processes input (if IN_P) or output operands to find
-   allocno which can use only one hard register and makes other
-   currently living allocnos conflicting with the hard register.  */
-static void
-process_single_reg_class_operands (int in_p)
-{
-  int i, regno, px;
-  enum reg_class cl, cover_class;
-  rtx operand;
-  allocno_t operand_a, a;
-
-  for (i = 0; i < recog_data.n_operands; i++)
-    {
-      operand = recog_data.operand [i];
-      if (in_p && recog_data.operand_type [i] != OP_IN
-	  && recog_data.operand_type [i] != OP_INOUT)
-	continue;
-      if (! in_p && recog_data.operand_type [i] != OP_OUT
-	  && recog_data.operand_type [i] != OP_INOUT)
-	continue;
-      cl = single_reg_operand_class (i);
-      if (cl == NO_REGS)
-	continue;
-
-      operand_a = NULL;
-
-      if (GET_CODE (operand) == SUBREG)
-	operand = SUBREG_REG (operand);
-      
-      if (REG_P (operand)
-	  && (regno = REGNO (operand)) >= FIRST_PSEUDO_REGISTER)
-	{
-	  enum machine_mode mode;
-	  enum reg_class cover_class;
-
-	  operand_a = curr_regno_allocno_map [regno];
-	  mode = ALLOCNO_MODE (operand_a);
-	  cover_class = ALLOCNO_MODE (operand_a);
-	  if (class_subset_p [cl] [cover_class]
-	      && (reg_class_size [cl]
-		  <= (unsigned) CLASS_MAX_NREGS (cl, mode)))
-	    ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a)
-	      [class_hard_reg_index [cover_class] [class_hard_regs [cl] [0]]]
-	      -= (in_p
-		  ? register_move_cost [mode] [cover_class] [cl]
-		  : register_move_cost [mode] [cl] [cover_class]);
-	}
-
-      EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, px,
-        {
-	  a = allocnos [px];
-	  cover_class = ALLOCNO_COVER_CLASS (a);
-	  if (a != operand_a)
-	    /* We could increase costs of A instead of making it
-	       conflicting with the hard register.  But it works worse
-	       because it will be spilled in reload in anyway.  */
-	    IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a),
-			      reg_class_contents [cl]);
-	});
-    }
-}
-
-/* The function processes insns of the basic block given by its
-   LOOP_TREE_NODE to update allocno conflict table.  */
+/* The function adds copies originated from bb given by
+   LOOP_TREE_NODE.  */
 static void
-process_bb_node_for_conflicts (struct ira_loop_tree_node *loop_tree_node)
+add_copies (loop_tree_node_t loop_tree_node)
 {
-  int i, index;
-  unsigned int j;
   basic_block bb;
   rtx insn;
-  edge e;
-  edge_iterator ei;
-  bitmap_iterator bi;
-  bitmap reg_live_in;
-  int px = 0;
 
   bb = loop_tree_node->bb;
-  if (bb != NULL)
-    {
-      for (i = 0; i < reg_class_cover_size; i++)
-	curr_reg_pressure [reg_class_cover [i]] = 0;
-      curr_bb_node = loop_tree_node;
-      curr_regno_allocno_map = ira_curr_loop_tree_node->regno_allocno_map;
-      reg_live_in = DF_LR_IN (bb);
-      memset (allocnos_live, 0, allocno_row_words * sizeof (INT_TYPE));
-      REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_in);
-      AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
-      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-	if (TEST_HARD_REG_BIT (hard_regs_live, i))
-	  {
-	    enum reg_class cover_class;
-	    
-	    cover_class = class_translate [REGNO_REG_CLASS (i)];
-	    curr_reg_pressure [cover_class]++;
-	    if (curr_bb_node->reg_pressure [cover_class]
-		< curr_reg_pressure [cover_class])
-	      curr_bb_node->reg_pressure [cover_class]
-		= curr_reg_pressure [cover_class];
-	  }
-      bitmap_clear (allocnos_live_bitmap);
-      EXECUTE_IF_SET_IN_BITMAP (reg_live_in, FIRST_PSEUDO_REGISTER, j, bi)
-	{
-	  allocno_t a = curr_regno_allocno_map [j];
-	  
-	  ira_assert (a != NULL || REG_N_REFS (j) == 0);
-	  if (a == NULL)
-	    continue;
-	  set_allocno_live (a);
-	  record_regno_conflict (j);
-	}
-      
-#ifdef EH_RETURN_DATA_REGNO
-      if (bb_has_eh_pred (bb))
-	{
-	  for (j = 0; ; ++j)
-	    {
-	      unsigned int regno = EH_RETURN_DATA_REGNO (j);
-	      
-	      if (regno == INVALID_REGNUM)
-		break;
-	      record_regno_conflict (regno);
-	    }
-	}
-#endif
-      
-      /* Allocnos can't go in stack regs at the start of a basic block
-	 that is reached by an abnormal edge. Likewise for call
-	 clobbered regs, because caller-save, fixup_abnormal_edges and
-	 possibly the table driven EH machinery are not quite ready to
-	 handle such allocnos live across such edges.  */
-      FOR_EACH_EDGE (e, ei, bb->preds)
-	if (e->flags & EDGE_ABNORMAL)
-	  break;
-      
-      if (e != NULL)
-	{
-#ifdef STACK_REGS
-	  EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, px,
-	    {
-	      ALLOCNO_NO_STACK_REG_P (allocnos [px]) = TRUE;
-	    });
-	  for (px = FIRST_STACK_REG; px <= LAST_STACK_REG; px++)
-	    record_regno_conflict (px);
-#endif
-	  /* No need to record conflicts for call clobbered regs if we
-	     have nonlocal labels around, as we don't ever try to
-	     allocate such regs in this case.  */
-	  if (! current_function_has_nonlocal_label)
-	    for (px = 0; px < FIRST_PSEUDO_REGISTER; px++)
-	      if (call_used_regs [px])
-		record_regno_conflict (px);
-	}
-  
-      /* Scan the code of this basic block, noting which allocnos and
-	 hard regs are born or die.  When one is born, record a
-	 conflict with all others currently live.  */
-      FOR_BB_INSNS (bb, insn)
-	{
-	  rtx link;
-	  
-	  if (! INSN_P (insn))
-	    continue;
-	  
-	  /* Check regs_set is an empty set.  */
-	  gcc_assert (VEC_empty (rtx, regs_set));
-      
-	  /* Mark any allocnos clobbered by INSN as live, so they
-	     conflict with the inputs.  */
-	  note_stores (PATTERN (insn), mark_reg_clobber, NULL);
-	  
-	  extract_insn (insn);
-	  process_single_reg_class_operands (TRUE);
-	  
-	  /* Mark any allocnos dead after INSN as dead now.  */
-	  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-	    if (REG_NOTE_KIND (link) == REG_DEAD)
-	      mark_reg_death (XEXP (link, 0));
-	  
-	  if (CALL_P (insn))
-	    {
-	      HARD_REG_SET clobbered_regs;
-	      
-	      get_call_invalidated_used_regs (insn, &clobbered_regs, FALSE);
-	      IOR_HARD_REG_SET (cfun->emit->call_used_regs, clobbered_regs);
-	      EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
-	        {
-		  int freq;
-		  allocno_t a = allocnos [i];
-		  
-		  freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
-		  if (freq == 0)
-		    freq = 1;
-		  ALLOCNO_CALL_FREQ (a) += freq;
-		  index = add_regno_call (ALLOCNO_REGNO (a), insn);
-		  if (ALLOCNO_CALLS_CROSSED_START (a) < 0)
-		    ALLOCNO_CALLS_CROSSED_START (a) = index;
-		  ALLOCNO_CALLS_CROSSED_NUM (a)++;
-		  /* Don't allocate allocnos that cross calls, if this
-		     function receives a nonlocal goto.  */
-		  if (current_function_has_nonlocal_label)
-		    SET_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a));
-		});
-	    }
-	  
-	  /* Mark any allocnos set in INSN as live, and mark them as
-	     conflicting with all other live allocnos.  Clobbers are
-	     processed again, so they conflict with the allocnos that
-	     are set.  */
-	  note_stores (PATTERN (insn), mark_reg_store, NULL);
-	  
-#ifdef AUTO_INC_DEC
-	  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-	    if (REG_NOTE_KIND (link) == REG_INC)
-	      mark_reg_store (XEXP (link, 0), NULL_RTX, NULL);
-#endif
-	  
-	  /* If INSN has multiple outputs, then any allocno that dies
-	     here and is used inside of an output must conflict with
-	     the other outputs.
-	     
-	     It is unsafe to use !single_set here since it will ignore
-	     an unused output.  Just because an output is unused does
-	     not mean the compiler can assume the side effect will not
-	     occur.  Consider if ALLOCNO appears in the address of an
-	     output and we reload the output.  If we allocate ALLOCNO
-	     to the same hard register as an unused output we could
-	     set the hard register before the output reload insn.  */
-	  if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
-	    for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-	      if (REG_NOTE_KIND (link) == REG_DEAD)
-		{
-		  int i;
-		  int used_in_output = 0;
-		  rtx reg = XEXP (link, 0);
-		  
-		  for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-		    {
-		      rtx set = XVECEXP (PATTERN (insn), 0, i);
-		      
-		      if (GET_CODE (set) == SET
-			  && ! REG_P (SET_DEST (set))
-			  && ! rtx_equal_p (reg, SET_DEST (set))
-			  && reg_overlap_mentioned_p (reg, SET_DEST (set)))
-			used_in_output = 1;
-		    }
-		  if (used_in_output)
-		    mark_reg_conflicts (reg);
-		}
-	  
-	  process_single_reg_class_operands (FALSE);
-	  
-	  /* Mark any allocnos set in INSN and then never used.  */
-	  while (! VEC_empty (rtx, regs_set))
-	    {
-	      rtx reg = VEC_pop (rtx, regs_set);
-	      rtx note = find_regno_note (insn, REG_UNUSED, REGNO (reg));
-
-	      if (note)
-		mark_reg_death (XEXP (note, 0));
-	    }
-	  add_allocno_copies (insn);
-	}
-    }
-  /* Propagate register pressure: */
-  if (loop_tree_node != ira_loop_tree_root)
-    for (i = 0; i < reg_class_cover_size; i++)
-      {
-	enum reg_class cover_class;
-
-	cover_class = reg_class_cover [i];
-	if (loop_tree_node->reg_pressure [cover_class]
-	    > loop_tree_node->father->reg_pressure [cover_class])
-	  loop_tree_node->father->reg_pressure [cover_class]
-	    = loop_tree_node->reg_pressure [cover_class];
-      }
-}
-
-/* The function builds allocno conflict table by traversing all basic
-   blocks and their insns.  */
-static void
-build_conflict_bit_table (void)
-{
-  allocno_row_words = (allocnos_num + INT_BITS - 1) / INT_BITS;
-  conflicts = ira_allocate (sizeof (INT_TYPE)
-			    * allocnos_num * allocno_row_words);
-  memset (conflicts, 0, sizeof (INT_TYPE) * allocnos_num * allocno_row_words);
-  allocnos_live = ira_allocate (sizeof (INT_TYPE) * allocno_row_words);
-  allocnos_live_bitmap = ira_allocate_bitmap ();
-  /* Make a vector that mark_reg_{store,clobber} will store in.  */
-  if (!regs_set)
-    regs_set = VEC_alloc (rtx, heap, 10);
-  traverse_loop_tree (ira_loop_tree_root, NULL, process_bb_node_for_conflicts);
-  /* Clean up.  */
-  ira_free_bitmap (allocnos_live_bitmap);
-  ira_free (allocnos_live);
+  if (bb == NULL)
+    return;
+  FOR_BB_INSNS (bb, insn)
+    if (INSN_P (insn))
+      add_insn_allocno_copies (insn);
 }
 
 /* The function propagates info about allocno A to the corresponding
@@ -1329,9 +573,9 @@ build_conflict_bit_table (void)
 static void
 propagate_allocno_info (allocno_t a)
 {
-  int regno, j, pn, father_pn, another_father_pn;
+  int regno;
   allocno_t father_a, another_a, another_father_a;
-  struct ira_loop_tree_node *father;
+  loop_tree_node_t father;
   copy_t cp, next_cp;
 
   regno = ALLOCNO_REGNO (a);
@@ -1340,26 +584,15 @@ propagate_allocno_info (allocno_t a)
     {
       ALLOCNO_CALL_FREQ (father_a) += ALLOCNO_CALL_FREQ (a);
 #ifdef STACK_REGS
-      if (ALLOCNO_NO_STACK_REG_P (a))
-	ALLOCNO_NO_STACK_REG_P (father_a) = TRUE;
+      if (ALLOCNO_TOTAL_NO_STACK_REG_P (a))
+	ALLOCNO_TOTAL_NO_STACK_REG_P (father_a) = TRUE;
 #endif
-      IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (father_a),
-			ALLOCNO_CONFLICT_HARD_REGS (a));
-      pn = ALLOCNO_NUM (a);
-      EXECUTE_IF_SET_IN_ALLOCNO_SET (conflicts + pn * allocno_row_words, j,
-        {
-	  another_a = allocnos [j];
-	  if ((another_father_a = (father->regno_allocno_map
-				   [ALLOCNO_REGNO (another_a)])) == NULL)
-	    continue;
-	  father_pn = ALLOCNO_NUM (father_a);
-	  another_father_pn = ALLOCNO_NUM (another_father_a);
-	  SET_ALLOCNO_CONFLICT_ROW
-	    (conflicts + father_pn * allocno_row_words, another_father_pn);
-	  SET_ALLOCNO_CONFLICT_ROW
-	    (conflicts + another_father_pn * allocno_row_words, father_pn);
-	});
-      if (ALLOCNO_CALLS_CROSSED_START (father_a) < 0)
+      IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (father_a),
+			ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
+      if (ALLOCNO_CALLS_CROSSED_START (father_a) < 0
+	  || (ALLOCNO_CALLS_CROSSED_START (a) >= 0
+	      && (ALLOCNO_CALLS_CROSSED_START (father_a)
+		  > ALLOCNO_CALLS_CROSSED_START (a))))
 	ALLOCNO_CALLS_CROSSED_START (father_a)
 	  = ALLOCNO_CALLS_CROSSED_START (a);
       ALLOCNO_CALLS_CROSSED_NUM (father_a) += ALLOCNO_CALLS_CROSSED_NUM (a);
@@ -1379,8 +612,8 @@ propagate_allocno_info (allocno_t a)
 	    gcc_unreachable ();
 	  if ((another_father_a = (father->regno_allocno_map
 				   [ALLOCNO_REGNO (another_a)])) != NULL)
-	    add_allocno_copy
-	      (father_a, another_father_a, cp->freq, cp->move_insn);
+	    add_allocno_copy (father_a, another_father_a, cp->freq,
+			      cp->move_insn, cp->loop_tree_node);
 	}
     }
 }
@@ -1400,59 +633,48 @@ propagate_info (void)
       propagate_allocno_info (a);
 }
 
-/* If CONFLICTP (i, j) is TRUE, make sure CONFLICTP (j, i) is also TRUE.  */
-static void
-mirror_conflicts (void)
+/* The function returns TRUE if allocnos A1 and A2 conflict.  It
+   checks intersection of the corresponding live ranges for this.  */
+int
+allocno_conflict_p (allocno_t a1, allocno_t a2)
 {
-  int i, j;
-  unsigned INT_TYPE mask;
-  int rw = allocno_row_words;
-  int rwb = rw * INT_BITS;
-  INT_TYPE *p = conflicts;
-  INT_TYPE *q0 = conflicts;
-  INT_TYPE *q1, *q2;
+  allocno_live_range_t r1, r2;
 
-  for (i = allocnos_num - 1, mask = 1; i >= 0; i--, mask <<= 1)
+  if (a1 == a2)
+    return FALSE;
+  if (ALLOCNO_REG (a1) != NULL && ALLOCNO_REG (a2) != NULL
+      && (ORIGINAL_REGNO (ALLOCNO_REG (a1))
+	  == ORIGINAL_REGNO (ALLOCNO_REG (a2))))
+    return FALSE;
+  for (r1 = ALLOCNO_LIVE_RANGES (a1), r2 = ALLOCNO_LIVE_RANGES (a2);
+       r1 != NULL && r2 != NULL;)
     {
-      if (! mask)
-	{
-	  mask = 1;
-	  q0++;
-	}
-      for (j = allocno_row_words - 1, q1 = q0; j >= 0; j--, q1 += rwb)
-	{
-	  unsigned INT_TYPE word;
-
-	  for (word = (unsigned INT_TYPE) *p++, q2 = q1;
-	       word;
-	       word >>= 1, q2 += rw)
-	    {
-	      if (word & 1)
-		*q2 |= mask;
-	    }
-	}
+      if ((r2->start <= r1->start && r1->start <= r2->finish)
+	  || (r1->start <= r2->start && r2->start <= r1->finish))
+	return TRUE;
+      if (r1->start > r2->finish)
+	r1 = r1->next;
+      else
+	r2 = r2->next;
     }
+  return FALSE;
 }
 
 /* The function returns TRUE if pseudo-registers REGNO1 and REGNO2
-   conflict.  The function is called from reload.  */
+   conflict.  It should be used when there is only one region.  */
 int
 allocno_reg_conflict_p (int regno1, int regno2)
 {
-  int p_no1, p_no2;
+  allocno_t a1, a2;
 
   ira_assert (regno1 >= FIRST_PSEUDO_REGISTER
 	      && regno2 >= FIRST_PSEUDO_REGISTER);
   /* Reg info caclulated by dataflow infrastructure can be different
      from one calculated by regclass.  */
-  if (curr_regno_allocno_map [regno1] == NULL
-      || curr_regno_allocno_map [regno2] == NULL)
+  if ((a1 = ira_loop_tree_root->regno_allocno_map [regno1]) == NULL
+      || (a2 = ira_loop_tree_root->regno_allocno_map [regno2]) == NULL)
     return FALSE;
-  p_no1 = ALLOCNO_NUM (curr_regno_allocno_map [regno1]);
-  p_no2 = ALLOCNO_NUM (curr_regno_allocno_map [regno2]);
-  ira_assert (p_no1 >= 0 && p_no1 < allocnos_num
-	      && p_no2 >= 0 && p_no2 < allocnos_num);
-  return CONFLICTP (p_no1, p_no2) != 0;
+  return allocno_conflict_p (a1, a2);
 }
 
 /* Remove copies involving conflicting allocnos.  */
@@ -1481,7 +703,7 @@ remove_conflict_allocno_copies (void)
   for (i = VARRAY_ACTIVE_SIZE (conflict_allocno_copy_varray) - 1; i >= 0; i--)
     {
       cp = VARRAY_GENERIC_PTR (conflict_allocno_copy_varray, i);
-      if (CONFLICTP (ALLOCNO_NUM (cp->first), ALLOCNO_NUM (cp->second)))
+      if (CONFLICT_P (ALLOCNO_NUM (cp->first), ALLOCNO_NUM (cp->second)))
 	remove_allocno_copy_from_list (cp);
     }
   VARRAY_FREE (conflict_allocno_copy_varray);
@@ -1492,25 +714,89 @@ remove_conflict_allocno_copies (void)
 static void
 build_allocno_conflict_vects (void)
 {
-  int i, j, px;
-  allocno_t a, *conflict_allocnos, *vec;
+  int i, j, level, px, another_father_pn, conflict_allocnos_num;
+  int *level_init_p;
+  enum reg_class cover_class;
+  loop_tree_node_t father;
+  allocno_t a, father_a, another_a, another_father_a, *conflict_allocnos, *vec;
+  INT_TYPE *accumulated_conflicts, *allocno_conflicts, *propagate_conflicts;
 
   conflict_allocnos = ira_allocate (sizeof (allocno_t) * allocnos_num);
-  for (i = 0; i < allocnos_num; i++)
-    {
-      a = allocnos [i];
-      ira_assert (i == ALLOCNO_NUM (a));
-      px = 0;
-      EXECUTE_IF_SET_IN_ALLOCNO_SET (conflicts + i * allocno_row_words, j,
-				    {
-				      conflict_allocnos [px++] = allocnos [j];
-				    });
-      allocate_allocno_conflicts (a, px);
-      vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
-      memcpy (vec, conflict_allocnos, sizeof (allocno_t) * px);
-      vec [px] = NULL;
-      ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE (a) = px;
-    }
+  level_init_p = ira_allocate (ira_loop_tree_height * sizeof (int));
+  memset (level_init_p, 0, ira_loop_tree_height * sizeof (int));
+  accumulated_conflicts
+    = ira_allocate (ira_loop_tree_height
+		    * allocno_set_words * sizeof (INT_TYPE));
+  for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+    for (a = regno_allocno_map [i];
+	 a != NULL;
+	 a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
+      {
+	cover_class = ALLOCNO_COVER_CLASS (a);
+	level = ALLOCNO_LOOP_TREE_NODE (a)->level;
+	allocno_conflicts = conflicts + ALLOCNO_NUM (a) * allocno_set_words;
+	px = 0;
+	EXECUTE_IF_SET_IN_ALLOCNO_SET (allocno_conflicts, j,
+	  {
+	    another_a = allocnos [j];
+	    if (cover_class == ALLOCNO_COVER_CLASS (another_a))
+	      conflict_allocnos [px++] = another_a;
+	  });
+	conflict_allocnos_num = px;
+	if (! level_init_p [level])
+	  propagate_conflicts = allocno_conflicts;
+	else
+	  {
+	    propagate_conflicts
+	      = accumulated_conflicts + level * allocno_set_words;
+	    EXECUTE_IF_SET_IN_ALLOCNO_SET (propagate_conflicts, j,
+	      {
+		another_a = allocnos [j];
+		ira_assert (cover_class == ALLOCNO_COVER_CLASS (another_a));
+		if (! TEST_ALLOCNO_SET_BIT (allocno_conflicts, j))
+		  conflict_allocnos [px++] = another_a;
+	      });
+	    for (j = 0; j < allocno_set_words; j++)
+	      propagate_conflicts [j] |= allocno_conflicts [j];
+	  }
+	allocate_allocno_conflicts (a, px);
+	vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
+	memcpy (vec, conflict_allocnos, sizeof (allocno_t) * px);
+	vec [px] = NULL;
+	ALLOCNO_CONFLICT_ALLOCNOS_NUM (a) = conflict_allocnos_num;
+	ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM (a) = px;
+	level_init_p [level] = FALSE;
+	if ((father = ALLOCNO_LOOP_TREE_NODE (a)->father) == NULL
+	    || (father_a = father->regno_allocno_map [i]) == NULL)
+	  continue;
+	level--;
+	ira_assert (level == ALLOCNO_LOOP_TREE_NODE (father_a)->level
+		    && cover_class == ALLOCNO_COVER_CLASS (father_a));
+	if (! level_init_p [level])
+	  {
+	    level_init_p [level] = TRUE;
+	    memset (accumulated_conflicts + level * allocno_set_words, 0,
+		    allocno_set_words * sizeof (INT_TYPE));
+	  }
+	EXECUTE_IF_SET_IN_ALLOCNO_SET (propagate_conflicts, j,
+	  {
+	    another_a = allocnos [j];
+	    if ((another_father_a = (father->regno_allocno_map
+				     [ALLOCNO_REGNO (another_a)])) == NULL)
+	      continue;
+	    another_father_pn = ALLOCNO_NUM (another_father_a);
+	    if (another_father_pn < 0)
+	      continue;
+	    ira_assert (ALLOCNO_COVER_CLASS (another_a)
+			== ALLOCNO_COVER_CLASS (another_father_a));
+	    if (cover_class == ALLOCNO_COVER_CLASS (another_a))
+	      SET_ALLOCNO_SET_BIT
+		(accumulated_conflicts + allocno_set_words * level,
+		 another_father_pn);
+	  });
+      }
+  ira_free (accumulated_conflicts);
+  ira_free (level_init_p);
   ira_free (conflict_allocnos);
 }
 
@@ -1519,7 +805,7 @@ build_allocno_conflict_vects (void)
 /* The function propagates information about allocnos modified inside
    the loops.  */
 static void
-propagate_modified_regnos (struct ira_loop_tree_node *loop_tree_node)
+propagate_modified_regnos (loop_tree_node_t loop_tree_node)
 {
   if (loop_tree_node->bb != NULL || loop_tree_node == ira_loop_tree_root)
     return;
@@ -1529,52 +815,94 @@ propagate_modified_regnos (struct ira_lo
 
 
 
-/* The function outputs information about allocno conflicts to FILE.  */
+/* The function prints hard reg set SET with TITLE to FILE.  */
 static void
-print_conflicts (FILE *file)
+print_hard_reg_set (FILE *file, const char *title, HARD_REG_SET set)
+{
+  int i, start;
+
+  fprintf (file, title);
+  for (start = -1, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      if (TEST_HARD_REG_BIT (set, i))
+	{
+	  if (i == 0 || ! TEST_HARD_REG_BIT (set, i - 1))
+	    start = i;
+	}
+      if (start >= 0
+	  && (i == FIRST_PSEUDO_REGISTER - 1 || ! TEST_HARD_REG_BIT (set, i)))
+	{
+	  if (start == i - 1)
+	    fprintf (file, " %d", start);
+	  else if (start == i - 2)
+	    fprintf (file, " %d %d", start, start + 1);
+	  else
+	    fprintf (file, " %d-%d", start, i - 1);
+	  start = -1;
+	}
+    }
+  fprintf (file, "\n");
+}
+
+/* The function outputs information about allocno or regno (if REG_P)
+   conflicts to FILE.  */
+static void
+print_conflicts (FILE *file, int reg_p)
 {
   int i;
 
   for (i = 0; i < allocnos_num; i++)
     {
       int j;
-      allocno_t a;
+      allocno_t a, conflict_a, *allocno_vec;
       basic_block bb;
 
       a = allocnos [i];
-      fprintf (file, ";; a%d(r%d,", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
-      if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
-	fprintf (file, "b%d", bb->index);
+      if (reg_p)
+	fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
       else
-	fprintf (file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
-      fprintf (file, ") conflicts:");
-      for (j = 0; j < allocnos_num; j++)
-	if (CONFLICTP (j, i))
+	{
+	  fprintf (file, ";; a%d(r%d,", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
+	  if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
+	    fprintf (file, "b%d", bb->index);
+	  else
+	    fprintf (file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
+	  fprintf (file, ")");
+	}
+      fprintf (file, " conflicts:");
+      allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
+      if (allocno_vec != NULL)
+	for (j = 0; (conflict_a = allocno_vec [j]) != NULL; j++)
 	  {
-	    fprintf (file, " a%d(r%d,",
-		     ALLOCNO_NUM (allocnos [j]), ALLOCNO_REGNO (allocnos [j]));
-	    if ((bb = ALLOCNO_LOOP_TREE_NODE (allocnos [j])->bb) != NULL)
-	      fprintf (file, "b%d)", bb->index);
+	    if (reg_p)
+	      fprintf (file, " r%d,", ALLOCNO_REGNO (conflict_a));
 	    else
-	      fprintf (file, "l%d)",
-		       ALLOCNO_LOOP_TREE_NODE (allocnos [j])->loop->num);
+	      {
+		fprintf (file, " a%d(r%d,", ALLOCNO_NUM (conflict_a),
+			 ALLOCNO_REGNO (conflict_a));
+		if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
+		  fprintf (file, "b%d)", bb->index);
+		else
+		  fprintf (file, "l%d)",
+			   ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
+	      }
+	    if (j + 1 == ALLOCNO_CONFLICT_ALLOCNOS_NUM (a))
+	      fprintf (file, "*");
 	  }
-      fprintf (file, "\n;;     conflict hard regs:");
-      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
-	if (TEST_HARD_REG_BIT (ALLOCNO_CONFLICT_HARD_REGS (a), j))
-	  fprintf (file, " %d", j);
-      fprintf (file, "\n");
-
+      print_hard_reg_set (file, "\n;;     total conflict hard regs:",
+			  ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
+      print_hard_reg_set (file, ";;     conflict hard regs:",
+			  ALLOCNO_CONFLICT_HARD_REGS (a));
     }
   fprintf (file, "\n");
 }
 
-/* The function outputs information about allocno conflicts to
-   stderr.  */
+/* The function outputs information about allocno or regno (if REG_P)
+   conflicts to stderr.  */
 void
-debug_conflicts (void)
+debug_conflicts (int reg_p)
 {
-  print_conflicts (stderr);
+  print_conflicts (stderr, reg_p);
 }
 
 
@@ -1588,6 +916,7 @@ ira_build_conflicts (void)
 
   build_conflict_bit_table ();
   mirror_conflicts ();
+  traverse_loop_tree (FALSE, ira_loop_tree_root, NULL, add_copies);
   if (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
       || flag_ira_algorithm == IRA_ALGORITHM_MIXED)
     propagate_info ();
@@ -1597,23 +926,27 @@ ira_build_conflicts (void)
   for (i = 0; i < allocnos_num; i++)
     {
       a = allocnos [i];
-      if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+      if (ALLOCNO_CALLS_CROSSED_NUM (a) == 0)
+	continue;
+      if (! flag_caller_saves)
 	{
-	  if (! flag_caller_saves
-	      || (flag_ira_split_around_calls
-		  && ((ira_max_regno_before > ALLOCNO_REGNO (a)
-		       && (reg_equiv_const [ALLOCNO_REGNO (a)]
-			   || reg_equiv_invariant_p [ALLOCNO_REGNO (a)]))
-		      || (ira_max_regno_before <= ALLOCNO_REGNO (a)
-			  && ALLOCNO_REGNO (a) < ira_max_regno_call_before))))
+	  IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a),
+			    call_used_reg_set);
+	  if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
 	    IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a),
 			      call_used_reg_set);
-          else
+	}
+      else
+	{
+	  IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a),
+			    no_caller_save_reg_set);
+	  if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
 	    IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a),
 			      no_caller_save_reg_set);
 	}
-    }  
-  traverse_loop_tree (ira_loop_tree_root, NULL, propagate_modified_regnos);
-  if (ira_dump_file != NULL)
-    print_conflicts (ira_dump_file);
+    }
+  traverse_loop_tree (FALSE, ira_loop_tree_root, NULL,
+		      propagate_modified_regnos);
+  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+    print_conflicts (ira_dump_file, FALSE);
 }
Index: flags.h
===================================================================
--- flags.h	(revision 129968)
+++ flags.h	(working copy)
@@ -231,6 +231,8 @@ enum ira_algorithm {
 
 extern enum ira_algorithm flag_ira_algorithm;
 
+extern unsigned int flag_ira_verbose;
+
 
 /* Other basic status info about current function.  */
 
Index: toplev.c
===================================================================
--- toplev.c	(revision 129968)
+++ toplev.c	(working copy)
@@ -308,6 +308,10 @@ enum tls_model flag_tls_default = TLS_MO
 
 enum ira_algorithm flag_ira_algorithm = IRA_ALGORITHM_REGIONAL;
 
+/* 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.  */
 
@@ -2198,6 +2202,8 @@ finalize (void)
 
   finish_optimization_passes ();
 
+  finish_ira_once ();
+
   if (mem_report)
     dump_memory_report (true);
 
Index: toplev.h
===================================================================
--- toplev.h	(revision 129968)
+++ toplev.h	(working copy)
@@ -136,15 +136,12 @@ extern int flag_unswitch_loops;
 extern int flag_cprop_registers;
 extern int time_report;
 extern int flag_ira;
-extern int flag_ira_assign_after_call_split;
-extern int flag_ira_biased_coloring;
 extern int flag_ira_coalesce;
 extern int flag_ira_ipra;
 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;
-extern int flag_ira_split_around_calls;
 
 /* Things to do with target switches.  */
 extern void print_version (FILE *, const char *);
Index: caller-save.c
===================================================================
--- caller-save.c	(revision 129968)
+++ caller-save.c	(working copy)
@@ -1524,8 +1524,9 @@ insert_restore (struct insn_chain *chain
   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);
+      && 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);
   pat = gen_rtx_SET (VOIDmode,
@@ -1596,8 +1597,9 @@ insert_save (struct insn_chain *chain, i
   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);
+      && 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);
   pat = gen_rtx_SET (VOIDmode, mem,
Index: ira-int.h
===================================================================
--- ira-int.h	(revision 129968)
+++ ira-int.h	(working copy)
@@ -22,6 +22,7 @@ Software Foundation, 51 Franklin Street,
 
 #include "cfgloop.h"
 #include "ira.h"
+#include "alloc-pool.h"
 
 #ifdef ENABLE_CHECKING
 #define ENABLE_IRA_CHECKING
@@ -46,10 +47,18 @@ Software Foundation, 51 Franklin Street,
 /* All natural loops.  */
 extern struct loops ira_loops;
 
+/* The flag value used internally.  */
+extern int internal_flag_ira_verbose;
+
 /* Dump file of the allocator if it is not NULL.  */
 extern FILE *ira_dump_file;
 
-/* Allocno and copy of allocnos.  */
+/* Pools for allocnos, copies, allocno live ranges.  */
+extern alloc_pool allocno_pool, copy_pool, allocno_live_range_pool;
+
+/* Allocno live range, allocno, and copy of allocnos.  */
+typedef struct loop_tree_node *loop_tree_node_t;
+typedef struct allocno_live_range *allocno_live_range_t;
 typedef struct allocno *allocno_t;
 typedef struct allocno_copy *copy_t;
 
@@ -59,17 +68,20 @@ typedef struct allocno_copy *copy_t;
    part of the tree from cfgloop.h).  We also use the nodes for
    storing additional information about basic blocks/loops for the
    register allocation.  */
-struct ira_loop_tree_node
+struct loop_tree_node
 {
   /* The node represents basic block if inner == NULL.  */
   basic_block bb;    /* NULL for loop.  */
   struct loop *loop; /* NULL for BB.  */
   /* The next node on the same tree level.  */
-  struct ira_loop_tree_node *next;
+  loop_tree_node_t next;
   /* The first node immediately inside the node.  */
-  struct ira_loop_tree_node *inner;
+  loop_tree_node_t inner;
   /* The node containing given node.  */
-  struct ira_loop_tree_node *father;
+  loop_tree_node_t father;
+
+  /* Loop level in range [0, ira_loop_tree_height).  */
+  int level;
 
   /* Allocnos in loop corresponding to regnos.  If it is NULL the loop
      is not included in the loop tree (e.g. it has abnormal enter/exit
@@ -94,17 +106,20 @@ struct ira_loop_tree_node
 };
 
 /* The root of the loop tree corresponding to the all function.  */
-extern struct ira_loop_tree_node *ira_loop_tree_root;
+extern loop_tree_node_t ira_loop_tree_root;
+
+/* Height of the loop tree.  */
+extern int ira_loop_tree_height;
 
 /* All basic block data are referred through the following array.  We
    can not use member `aux' for this because it is used for insertion
    of insns on edges.  */
-extern struct ira_loop_tree_node *ira_bb_nodes;
+extern loop_tree_node_t ira_bb_nodes;
 
 /* Two access macros to the basic block data.  */
 #if defined ENABLE_IRA_CHECKING && (GCC_VERSION >= 2007)
 #define IRA_BB_NODE_BY_INDEX(index) __extension__			\
-(({ struct ira_loop_tree_node *const _node = (&ira_bb_nodes [index]);	\
+(({ loop_tree_node_t _node = (&ira_bb_nodes [index]);	\
      if (_node->inner != NULL || _node->loop != NULL || _node->bb == NULL)\
        {								\
          fprintf (stderr,						\
@@ -120,12 +135,12 @@ extern struct ira_loop_tree_node *ira_bb
 #define IRA_BB_NODE(bb) IRA_BB_NODE_BY_INDEX ((bb)->index)
 
 /* All loop data are referred through the following array.  */
-extern struct ira_loop_tree_node *ira_loop_nodes;
+extern loop_tree_node_t ira_loop_nodes;
 
 /* Two access macros to the loop data.  */
 #if defined ENABLE_IRA_CHECKING && (GCC_VERSION >= 2007)
 #define IRA_LOOP_NODE_BY_INDEX(index) __extension__			\
-(({ struct ira_loop_tree_node *const _node = (&ira_loop_nodes [index]);\
+(({ loop_tree_node_t const _node = (&ira_loop_nodes [index]);\
      if (_node->inner == NULL || _node->bb != NULL || _node->loop == NULL)\
        {								\
          fprintf (stderr,						\
@@ -142,53 +157,119 @@ extern struct ira_loop_tree_node *ira_lo
 
 
 
-/* Node representing allocnos (register allocation entity).  */
+/* The structure describes program points where a given allocno
+   lives.  */
+struct allocno_live_range
+{
+  /* Allocno whose live range is described by given structure.  */
+  allocno_t allocno;
+  /* Program point range.  */
+  int start, finish;
+  /* Next structure describing program points where the allocno
+     lives.  */
+  allocno_live_range_t next;
+  /* Pointer to structures with the same start/finish.  */
+  allocno_live_range_t start_next, finish_next;
+};
+
+/* Program points are enumerated by number from range
+   0..MAX_POINT-1.  */
+extern int max_point;
+
+/* Arrays of size MAX_POINT mapping a program point to the allocno
+   live ranges with given start/finish point.  */
+extern allocno_live_range_t *start_point_ranges, *finish_point_ranges;
+
+/* Node representing allocnos (allocation entity).  */
 struct allocno
 {
   /* The allocno order number starting with 0.  */
   int num;
   /* Regno for allocno or cap.  */
   int regno;
+  /* Mode of the allocno.  */
+  enum machine_mode mode;
   /* Final rtx representation of the allocno.  */
   rtx reg;
+  /* Hard register assigned to given allocno.  Negative value means
+     that memory was allocated to the allocno.  */
+  int hard_regno;
   /* Allocnos with the same regno are linked by the following member.
-     allocnos corresponding to inner loops are first in the list.  */
+     Allocnos corresponding to inner loops are first in the list
+     (depth-first tarverse).  */
   allocno_t next_regno_allocno;
   /* There may be different allocnos with the same regno.  They are
      bound to a loop tree node.  */
-  struct ira_loop_tree_node *loop_tree_node;
+  loop_tree_node_t loop_tree_node;
+  /* Accumulated usage references of the allocno.  */
+  int nrefs;
+  /* Accumulated frequency of usage of the allocno.  */
+  int freq;
+  /* Register class which should be used for allocation for given
+     allocno.  NO_REGS means that we should use memory.  */
+  enum reg_class cover_class;
+  /* The biggest register class with minimal cost usage for given
+     allocno.  */
+  enum reg_class best_class;
+  /* Minimal accumulated cost of usage register of the cover class for
+     the allocno.  */
+  int cover_class_cost;
+  /* Minimal accumulated, and updated costs of memory for the
+     allocno.  */
+  int memory_cost, updated_memory_cost;
+  /* Copies to other non-conflicting allocnos.  The copies can
+     represent move insn or potential move insn usually because of two
+     operand constraints.  */
+  copy_t allocno_copies;
   /* It is a allocno (cap) representing given allocno on upper loop tree
      level.  */
   allocno_t cap;
   /* It is a link to allocno (cap) on lower loop level represented by
      given cap.  Null if it is not a cap.  */
   allocno_t cap_member;
-  /* Vector of conflicting allocnos with NULL end marker.  */
+  /* Coalesced allocnos form a cyclic list.  One allocno given by
+     FIRST_COALESCED_ALLOCNO represents all coalesced allocnos.  The
+     list is chained by NEXT_COALESCED_ALLOCNO.  */
+  allocno_t first_coalesced_allocno;
+  allocno_t next_coalesced_allocno;
+  /* Pointer to structures describing at what program point the
+     allocno lives.  We always maintain the condition that *ranges in
+     the list are not intersected and ordered by decreasing their
+     program points*.  */
+  allocno_live_range_t live_ranges;
+  /* Vector of conflicting allocnos with NULL end marker (first
+     initial and then accumulated conflict allocnos).  Only allocnos
+     with the same cover class are in the vector.  */
   allocno_t *conflict_allocno_vec;
-  /* Allocated and current size (both without NULL marker) of the
+  /* Allocated size of the previous array.  */
+  int conflict_allocno_vec_size;
+  /* Numbers of initial and total (with) accumulated conflicts in the
      previous array.  */
-  int conflict_allocno_vec_size, conflict_allocno_vec_active_size;
-  /* Hard registers conflicting with this allocno and as a consequences
-     can not be assigned to the allocno.  */
-  HARD_REG_SET conflict_hard_regs;
-  /* Frequency of usage of the allocno.  */
-  int freq;
-  /* Hard register assigned to given allocno.  Negative value means
-     that memory was allocated to the allocno.  */
-  int hard_regno;
-  /* Frequency of calls which given allocno intersects.  */
+  int conflict_allocnos_num, total_conflict_allocnos_num;
+  /* Initial and accumulated hard registers conflicting with this
+     allocno and as a consequences can not be assigned to the
+     allocno.  */
+  HARD_REG_SET conflict_hard_regs, total_conflict_hard_regs;
+  /* Accumulated frequency of calls which given allocno
+     intersects.  */
   int call_freq;
   /* Start index of calls intersected by the allocno in
      regno_calls [regno].  */
   int calls_crossed_start;
-  /* Length of the previous array (number of the intersected
-     calls).  */
+  /* Length of the previous array (number of the intersected calls).  */
   int calls_crossed_num;
+  /* Non NULL if we remove restoring value from given allocno to
+     MEM_OPTIMIZED_DEST at the end of loop because the value is not
+     changed in loop.  */
+  allocno_t mem_optimized_dest;
+  /* TRUE if the allocno was a destination of removed move at the end
+     of loop because the value is not changed in loop.  */
+  unsigned int mem_optimized_dest_p : 1;
 
 #ifdef STACK_REGS
   /* Set to TRUE if allocno can't be allocated in the stack
      register.  */
-  unsigned int no_stack_reg_p : 1;
+  unsigned int no_stack_reg_p : 1, total_no_stack_reg_p : 1;
 #endif
   /* TRUE value means than the allocno was not removed from the
      conflicting graph during colouring.  */
@@ -199,35 +280,20 @@ struct allocno
   /* TRUE if it is put on the stack to make other allocnos
      colorable.  */
   unsigned int may_be_spilled_p : 1;
-  /* Mode of the allocno.  */
-  ENUM_BITFIELD(machine_mode) mode : 8;
-  /* Copies to other non-conflicting allocnos.  The copies can
-     represent move insn or potential move insn usually because of two
-     operand constraints.  */
-  copy_t allocno_copies;
-  /* Array of additional costs (initial and current during coloring)
-     for hard regno of allocno cover class.  If given allocno represents
-     a set of allocnos the current costs represents costs of the all
-     set.  */
-  int *hard_reg_costs, *curr_hard_reg_costs;
-  /* Array of decreasing costs (initial and current during coloring)
-     for conflicting allocnos for hard regno of the allocno cover class.
-     The member values can be NULL if all costs are the same.  If
-     given allocno represents a set of allocnos the current costs
-     represents costs of the all set.  */
-  int *conflict_hard_reg_costs, *curr_conflict_hard_reg_costs;
+  /* Array of additional costs (accumulated and the one updated during
+     coloring) for hard regno of allocno cover class.  If given
+     allocno represents a set of allocnos the current costs represents
+     costs of the all set.  */
+  int *hard_reg_costs, *updated_hard_reg_costs;
+  /* Array of decreasing costs (accumulated and the one updated during
+     coloring) for conflicting allocnos for hard regno of the allocno
+     cover class.  The member values can be NULL if all costs are the
+     same.  If given allocno represents a set of allocnos the current
+     costs represents costs of the all set.  */
+  int *conflict_hard_reg_costs, *updated_conflict_hard_reg_costs;
   /* Number of allocnos with TRUE in_graph_p value and conflicting with
      given allocno.  */
   int left_conflicts_num;
-  /* Register class which should be used for allocation for given
-     allocno.  NO_REGS means that we should use memory.  */
-  enum reg_class cover_class;
-  /* The biggest register class with minimal cost usage for given
-     allocno.  */
-  enum reg_class best_class;
-  /* Minimal cost of usage register of the cover class and memory for
-     the allocno.  */
-  int cover_class_cost, memory_cost, original_memory_cost;
   /* Number of hard register of the allocno cover class really
      availiable for the allocno allocation.  */
   int available_regs_num;
@@ -237,66 +303,69 @@ struct allocno
   allocno_t prev_bucket_allocno;
   /* Used for temporary purposes.  */
   int temp;
-  /* Coalesced allocnos form a cyclic list.  One allocno given by
-     FIRST_COALESCED_ALLOCNO represents all coalesced allocnos.  The
-     list is chained by NEXT_COALESCED_ALLOCNO.  */
-  allocno_t first_coalesced_allocno;
-  allocno_t next_coalesced_allocno;
 };
 
 /* All members of the allocno node should be accessed only through the
    following macros.  */
-#define ALLOCNO_NUM(P) ((P)->num)
-#define ALLOCNO_REGNO(P) ((P)->regno)
-#define ALLOCNO_REG(P) ((P)->reg)
-#define ALLOCNO_NEXT_REGNO_ALLOCNO(P) ((P)->next_regno_allocno)
-#define ALLOCNO_LOOP_TREE_NODE(P) ((P)->loop_tree_node)
-#define ALLOCNO_CAP(P) ((P)->cap)
-#define ALLOCNO_CAP_MEMBER(P) ((P)->cap_member)
-#define ALLOCNO_CONFLICT_ALLOCNO_VEC(P) ((P)->conflict_allocno_vec)
-#define ALLOCNO_CONFLICT_ALLOCNO_VEC_SIZE(P) ((P)->conflict_allocno_vec_size)
-#define ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE(P) \
-  ((P)->conflict_allocno_vec_active_size)
-#define ALLOCNO_CONFLICT_HARD_REGS(P) ((P)->conflict_hard_regs)
-#define ALLOCNO_FREQ(P) ((P)->freq)
-#define ALLOCNO_HARD_REGNO(P) ((P)->hard_regno)
-#define ALLOCNO_CALL_FREQ(P) ((P)->call_freq)
-#define ALLOCNO_CALLS_CROSSED_START(P) ((P)->calls_crossed_start)
-#define ALLOCNO_CALLS_CROSSED_NUM(P) ((P)->calls_crossed_num)
+#define ALLOCNO_NUM(A) ((A)->num)
+#define ALLOCNO_REGNO(A) ((A)->regno)
+#define ALLOCNO_REG(A) ((A)->reg)
+#define ALLOCNO_NEXT_REGNO_ALLOCNO(A) ((A)->next_regno_allocno)
+#define ALLOCNO_LOOP_TREE_NODE(A) ((A)->loop_tree_node)
+#define ALLOCNO_CAP(A) ((A)->cap)
+#define ALLOCNO_CAP_MEMBER(A) ((A)->cap_member)
+#define ALLOCNO_CONFLICT_ALLOCNO_VEC(A) ((A)->conflict_allocno_vec)
+#define ALLOCNO_CONFLICT_ALLOCNO_VEC_SIZE(A) ((A)->conflict_allocno_vec_size)
+#define ALLOCNO_CONFLICT_ALLOCNOS_NUM(A) ((A)->conflict_allocnos_num)
+#define ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM(A) \
+  ((A)->total_conflict_allocnos_num)
+#define ALLOCNO_CONFLICT_HARD_REGS(A) ((A)->conflict_hard_regs)
+#define ALLOCNO_TOTAL_CONFLICT_HARD_REGS(A) ((A)->total_conflict_hard_regs)
+#define ALLOCNO_NREFS(A) ((A)->nrefs)
+#define ALLOCNO_FREQ(A) ((A)->freq)
+#define ALLOCNO_HARD_REGNO(A) ((A)->hard_regno)
+#define ALLOCNO_CALL_FREQ(A) ((A)->call_freq)
+#define ALLOCNO_CALLS_CROSSED_START(A) ((A)->calls_crossed_start)
+#define ALLOCNO_CALLS_CROSSED_NUM(A) ((A)->calls_crossed_num)
+#define ALLOCNO_MEM_OPTIMIZED_DEST(A) ((A)->mem_optimized_dest)
+#define ALLOCNO_MEM_OPTIMIZED_DEST_P(A) ((A)->mem_optimized_dest_p)
 #ifdef STACK_REGS
-#define ALLOCNO_NO_STACK_REG_P(P) ((P)->no_stack_reg_p)
+#define ALLOCNO_NO_STACK_REG_P(A) ((A)->no_stack_reg_p)
+#define ALLOCNO_TOTAL_NO_STACK_REG_P(A) ((A)->total_no_stack_reg_p)
 #endif
-#define ALLOCNO_IN_GRAPH_P(P) ((P)->in_graph_p)
-#define ALLOCNO_ASSIGNED_P(P) ((P)->assigned_p)
-#define ALLOCNO_MAY_BE_SPILLED_P(P) ((P)->may_be_spilled_p)
-#define ALLOCNO_MODE(P) ((P)->mode)
-#define ALLOCNO_COPIES(P) ((P)->allocno_copies)
-#define ALLOCNO_HARD_REG_COSTS(P) ((P)->hard_reg_costs)
-#define ALLOCNO_CURR_HARD_REG_COSTS(P) ((P)->curr_hard_reg_costs)
-#define ALLOCNO_CONFLICT_HARD_REG_COSTS(P) ((P)->conflict_hard_reg_costs)
-#define ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS(P) \
-  ((P)->curr_conflict_hard_reg_costs)
-#define ALLOCNO_LEFT_CONFLICTS_NUM(P) ((P)->left_conflicts_num)
-#define ALLOCNO_BEST_CLASS(P) ((P)->best_class)
-#define ALLOCNO_COVER_CLASS(P) ((P)->cover_class)
-#define ALLOCNO_COVER_CLASS_COST(P) ((P)->cover_class_cost)
-#define ALLOCNO_MEMORY_COST(P) ((P)->memory_cost)
-#define ALLOCNO_ORIGINAL_MEMORY_COST(P) ((P)->original_memory_cost)
-#define ALLOCNO_AVAILABLE_REGS_NUM(P) ((P)->available_regs_num)
-#define ALLOCNO_NEXT_BUCKET_ALLOCNO(P) ((P)->next_bucket_allocno)
-#define ALLOCNO_PREV_BUCKET_ALLOCNO(P) ((P)->prev_bucket_allocno)
-#define ALLOCNO_TEMP(P) ((P)->temp)
-#define ALLOCNO_FIRST_COALESCED_ALLOCNO(P) ((P)->first_coalesced_allocno)
-#define ALLOCNO_NEXT_COALESCED_ALLOCNO(P) ((P)->next_coalesced_allocno)
+#define ALLOCNO_IN_GRAPH_P(A) ((A)->in_graph_p)
+#define ALLOCNO_ASSIGNED_P(A) ((A)->assigned_p)
+#define ALLOCNO_MAY_BE_SPILLED_P(A) ((A)->may_be_spilled_p)
+#define ALLOCNO_MODE(A) ((A)->mode)
+#define ALLOCNO_COPIES(A) ((A)->allocno_copies)
+#define ALLOCNO_HARD_REG_COSTS(A) ((A)->hard_reg_costs)
+#define ALLOCNO_UPDATED_HARD_REG_COSTS(A) ((A)->updated_hard_reg_costs)
+#define ALLOCNO_CONFLICT_HARD_REG_COSTS(A) \
+  ((A)->conflict_hard_reg_costs)
+#define ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS(A) \
+  ((A)->updated_conflict_hard_reg_costs)
+#define ALLOCNO_LEFT_CONFLICTS_NUM(A) ((A)->left_conflicts_num)
+#define ALLOCNO_BEST_CLASS(A) ((A)->best_class)
+#define ALLOCNO_COVER_CLASS(A) ((A)->cover_class)
+#define ALLOCNO_COVER_CLASS_COST(A) ((A)->cover_class_cost)
+#define ALLOCNO_MEMORY_COST(A) ((A)->memory_cost)
+#define ALLOCNO_UPDATED_MEMORY_COST(A) ((A)->updated_memory_cost)
+#define ALLOCNO_AVAILABLE_REGS_NUM(A) ((A)->available_regs_num)
+#define ALLOCNO_NEXT_BUCKET_ALLOCNO(A) ((A)->next_bucket_allocno)
+#define ALLOCNO_PREV_BUCKET_ALLOCNO(A) ((A)->prev_bucket_allocno)
+#define ALLOCNO_TEMP(A) ((A)->temp)
+#define ALLOCNO_FIRST_COALESCED_ALLOCNO(A) ((A)->first_coalesced_allocno)
+#define ALLOCNO_NEXT_COALESCED_ALLOCNO(A) ((A)->next_coalesced_allocno)
+#define ALLOCNO_LIVE_RANGES(A) ((A)->live_ranges)
 
-/* Map regno -> allocno for the current loop tree node.  */
+/* Map regno -> allocnos.  */
 extern allocno_t *regno_allocno_map;
 
-/* Array of references to all allocnos.  The order number of the allocno
-   corresponds to the index in the array.  */
+/* Array of references to all allocnos.  The order number of the
+   allocno corresponds to the index in the array.  */
 extern allocno_t *allocnos;
 
-/* Size of the previous array.  */
+/* Sizes of the previous array.  */
 extern int allocnos_num;
 
 /* The following structure represents a copy of given allocno to
@@ -320,6 +389,8 @@ struct allocno_copy
   /* Copies with the same allocno as SECOND are linked by the two
      following members.  */
   copy_t prev_second_allocno_copy, next_second_allocno_copy;
+  /* Region from which given copy is originated.  */
+  loop_tree_node_t loop_tree_node;
 };
 
 /* Array of references to copies.  The order number of the copy
@@ -365,6 +436,47 @@ extern int reg_class_nregs [N_REG_CLASSE
 /* Maximal value of the previous array elements.  */
 extern int max_nregs;
 
+/* The number of bits in each element of `allocnos_live' and what
+   type that element has.  We use the largest integer format on the
+   host machine.  */
+#define INT_BITS HOST_BITS_PER_WIDE_INT
+#define INT_TYPE HOST_WIDE_INT
+
+/* Set, clear or test bit number I in R, a bit vector indexed by
+   allocno number.  */
+#define SET_ALLOCNO_SET_BIT(R, I)				\
+  ((R)[(unsigned) (I) / INT_BITS]				\
+   |= ((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
+
+#define CLEAR_ALLOCNO_SET_BIT(R, I)				\
+  ((R) [(unsigned) (I) / INT_BITS]				\
+   &= ~((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
+
+#define TEST_ALLOCNO_SET_BIT(R, I)				\
+  ((R) [(unsigned) (I) / INT_BITS]				\
+   & ((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
+
+/* For each allocno set in ALLOCNO_SET, set ALLOCNO to that
+   allocno, and execute CODE.  */
+#define EXECUTE_IF_SET_IN_ALLOCNO_SET(ALLOCNO_SET, ALLOCNO, CODE)	\
+do {									\
+  int i_;								\
+  int allocno_;								\
+  INT_TYPE *p_ = (ALLOCNO_SET);						\
+									\
+  for (i_ = allocno_set_words - 1, allocno_ = 0; i_ >= 0;		\
+       i_--, allocno_ += INT_BITS)					\
+    {									\
+      unsigned INT_TYPE word_ = (unsigned INT_TYPE) *p_++;		\
+									\
+      for ((ALLOCNO) = allocno_; word_; word_ >>= 1, (ALLOCNO)++)	\
+	{								\
+	  if (word_ & 1)						\
+	    {CODE;}							\
+	}								\
+    }									\
+} while (0)
+
 /* ira.c: */
 
 /* Hard regsets whose all bits are correspondingly zero or one.  */
@@ -414,6 +526,11 @@ extern int available_class_regs [N_REG_C
 extern HARD_REG_SET prohibited_class_mode_regs
                     [N_REG_CLASSES] [NUM_MACHINE_MODES];
 
+/* Array whose values are hard regset of hard registers for which
+   move of the hard register in given mode into itself is
+   prohibited.  */
+extern HARD_REG_SET prohibited_mode_move_regs [NUM_MACHINE_MODES];
+
 /* Number of cover classes.  */
 extern int reg_class_cover_size;
 
@@ -424,22 +541,26 @@ extern enum reg_class reg_class_cover [N
 /* The value is number of elements in the subsequent array.  */
 extern int important_classes_num;
 
-/* The array containing classes which are subclasses of a cover
-   class.  */
+/* The array containing classes which are subclasses of cover
+   classes.  */
 extern enum reg_class important_classes [N_REG_CLASSES];
 
+/* The array containing order numbers of important classes (they are
+   subclasses of cover classes).  */
+extern enum reg_class important_class_nums [N_REG_CLASSES];
+
 /* Map of register classes to corresponding cover class containing the
    given class.  */
 extern enum reg_class class_translate [N_REG_CLASSES];
 
 extern void set_non_alloc_regs (int);
 extern void *ira_allocate (size_t);
+extern void *ira_reallocate (void *, size_t);
 extern void ira_free (void *addr);
 extern bitmap ira_allocate_bitmap (void);
 extern void ira_free_bitmap (bitmap);
 extern regset ira_allocate_regset (void);
 extern void ira_free_regset (regset);
-extern int hard_reg_in_set_p (int, enum machine_mode, HARD_REG_SET);
 extern int hard_reg_not_in_set_p (int, enum machine_mode, HARD_REG_SET);
 extern void print_disposition (FILE *);
 extern void debug_disposition (void);
@@ -451,48 +572,66 @@ extern int *reg_equiv_invariant_p;
 /* Regno equivalent constants.  */
 extern rtx *reg_equiv_const;
 
-extern char *original_regno_call_crossed_p;
-extern int ira_max_regno_before;
-extern int ira_max_regno_call_before;
-
 /* ira-build.c */
 
 /* The current loop tree node.  */
-extern struct ira_loop_tree_node *ira_curr_loop_tree_node;
+extern loop_tree_node_t ira_curr_loop_tree_node;
+extern allocno_t *ira_curr_regno_allocno_map;
 extern VEC(rtx, heap) **regno_calls;
 
 extern int add_regno_call (int, rtx);
 
-extern void traverse_loop_tree (struct ira_loop_tree_node *,
-				void (*) (struct ira_loop_tree_node *),
-				void (*) (struct ira_loop_tree_node *));
-extern allocno_t create_allocno (int, int, struct ira_loop_tree_node *);
+extern void traverse_loop_tree (int, loop_tree_node_t,
+				void (*) (loop_tree_node_t),
+				void (*) (loop_tree_node_t));
+extern allocno_t create_allocno (int, int, loop_tree_node_t);
 extern void allocate_allocno_conflicts (allocno_t, int);
+extern int allocno_conflict_index (allocno_t, allocno_t);
+extern void add_allocno_conflict (allocno_t, allocno_t);
 extern void print_expanded_allocno (allocno_t);
-extern copy_t create_copy (allocno_t, allocno_t, int, rtx);
+extern allocno_live_range_t create_allocno_live_range (allocno_t, int, int,
+						       allocno_live_range_t);
+extern void finish_allocno_live_range (allocno_live_range_t);
+extern copy_t create_copy (allocno_t, allocno_t, int, rtx, loop_tree_node_t);
+extern void add_allocno_copy_to_list (copy_t);
+extern void swap_allocno_copy_ends_if_necessary (copy_t);
+extern void remove_allocno_copy_from_list (copy_t);
+extern copy_t add_allocno_copy (allocno_t, allocno_t, int, rtx,
+				loop_tree_node_t);
 
+extern void ira_flattening (int, int);
 extern int ira_build (int);
 extern void ira_destroy (void);
 
 /* ira-costs.c */
 extern void init_ira_costs_once (void);
+extern void finish_ira_costs_once (void);
 extern void ira_costs (void);
 extern void tune_allocno_costs_and_cover_classes (void);
 
+/* ira-lives.c */
+
+/* Number of ints required to hold allocnos_num bits.  */
+extern int allocno_set_words;
+
+extern void rebuild_start_finish_chains (void);
+extern void print_live_range_list (FILE *, allocno_live_range_t);
+extern void debug_live_range_list (allocno_live_range_t);
+extern void debug_allocno_live_ranges (allocno_t);
+extern void debug_live_ranges (void);
+extern void create_allocno_live_ranges (void);
+extern void finish_allocno_live_ranges (void);
+
 /* ira-conflicts.c */
-extern copy_t add_allocno_copy (allocno_t, allocno_t, int, rtx);
+extern int allocno_conflict_p (allocno_t, allocno_t);
 extern int allocno_reg_conflict_p (int, int);
-extern void debug_conflicts (void);
+extern void debug_conflicts (int);
 extern void ira_build_conflicts (void);
 
 /* ira-color.c */
+extern int loop_edge_freq (loop_tree_node_t, int, int);
 extern void reassign_conflict_allocnos (int, int);
 extern void ira_color (void);
 
 /* ira-emit.c */
-extern void ira_emit (void);
-
-/* ira-call.c */
-extern void debug_ira_call_data (void);
-extern int split_around_calls (void);
-extern int get_around_calls_regno (int);
+extern void ira_emit (int);
Index: ira-color.c
===================================================================
--- ira-color.c	(revision 129968)
+++ ira-color.c	(working copy)
@@ -41,7 +41,7 @@ Software Foundation, 51 Franklin Street,
 #include "df.h"
 #include "ira-int.h"
 
-/* We use optimistic colouring with optional biased colouring.  */
+/* We use optimistic colouring.  */
 
 static void update_copy_costs (allocno_t, int);
 static int assign_hard_reg (allocno_t, int);
@@ -53,19 +53,24 @@ static void push_allocno_to_stack (alloc
 static void remove_allocno_from_bucket_and_push (allocno_t, int);
 static void push_only_colorable (void);
 static void push_allocno_to_spill (allocno_t);
-static int loop_edge_freq (struct ira_loop_tree_node *, int, int);
 static int calculate_allocno_spill_cost (allocno_t);
 static void push_allocnos_to_stack (void);
 static void pop_allocnos_from_stack (void);
 static void setup_allocno_available_regs_num (allocno_t);
 static void setup_allocno_left_conflicts_num (allocno_t);
 static void put_allocno_into_bucket (allocno_t);
+static int copy_freq_compare_func (const void *, const void *);
+static void merge_allocnos (allocno_t, allocno_t);
+static int coalesced_allocno_conflict_p (allocno_t, allocno_t);
+static void coalesce_allocnos (void);
 static void color_allocnos (void);
 
-static void print_loop_title (struct ira_loop_tree_node *);
-static void color_pass (struct ira_loop_tree_node *);
+static void print_loop_title (loop_tree_node_t);
+static void color_pass (loop_tree_node_t);
 static int allocno_priority_compare_func (const void *, const void *);
+static void finish_allocno_priorities (void);
 static void priority_coloring (void);
+static void start_allocno_priorities (allocno_t *, int);
 static void do_coloring (void);
 
 static void move_spill_restore (void);
@@ -79,8 +84,9 @@ static bitmap coloring_allocno_bitmap;
    allocnos.  */
 static bitmap consideration_allocno_bitmap;
 
-/* ??? */
-static bitmap processed_allocno_bitmap;
+/* Bitmap used to prevent a repeated allocno processing because of
+   coalescing.  */
+static bitmap processed_coalesced_allocno_bitmap;
 
 /* All allocnos sorted accoring their priorities.  */
 static allocno_t *sorted_allocnos;
@@ -136,8 +142,8 @@ update_copy_costs (allocno_t allocno, in
 	        [ALLOCNO_COVER_CLASS (another_allocno)] [class]);
       if (decr_p)
 	cost = -cost;
-      ALLOCNO_CURR_HARD_REG_COSTS (another_allocno) [i] += cp->freq * cost;
-      ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (another_allocno) [i]
+      ALLOCNO_UPDATED_HARD_REG_COSTS (another_allocno) [i] += cp->freq * cost;
+      ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno) [i]
 	+= cp->freq * cost;
     }
 }
@@ -148,12 +154,12 @@ static int
 allocno_cost_compare_func (const void *v1p, const void *v2p)
 {
   allocno_t p1 = *(const allocno_t *) v1p, p2 = *(const allocno_t *) v2p;
-  int cost1, cost2;
+  int c1, c2;
 
-  cost1 = ALLOCNO_MEMORY_COST (p1) - ALLOCNO_COVER_CLASS_COST (p1);
-  cost2 = ALLOCNO_MEMORY_COST (p2) - ALLOCNO_COVER_CLASS_COST (p2);
-  if (cost1 - cost2)
-    return cost1 - cost2;
+  c1 = ALLOCNO_UPDATED_MEMORY_COST (p1) - ALLOCNO_COVER_CLASS_COST (p1);
+  c2 = ALLOCNO_UPDATED_MEMORY_COST (p2) - ALLOCNO_COVER_CLASS_COST (p2);
+  if (c1 - c2)
+    return c1 - c2;
 
   /* If regs are equally good, sort by allocnos, so that the results of
      qsort leave nothing to chance.  */
@@ -185,18 +191,18 @@ static varray_type allocno_stack_varray;
 static int
 assign_hard_reg (allocno_t allocno, int retry_p)
 {
-  HARD_REG_SET conflicting_regs, biased_regs;
+  HARD_REG_SET conflicting_regs;
   int i, j, hard_regno, best_hard_regno, class_size;
   int cost, mem_cost, min_cost, full_cost, min_full_cost, add_cost;
-  int costs [FIRST_PSEUDO_REGISTER], *a_costs;
+  int *a_costs;
   int *conflict_costs;
   enum reg_class cover_class, class;
   enum machine_mode mode;
-  allocno_t a, conflict_allocno, conflict_allocno2;
-  allocno_t *allocno_vec, *allocno_vec2;
+  allocno_t a, conflict_allocno;
+  allocno_t *allocno_vec;
   allocno_t another_allocno;
   copy_t cp, next_cp;
-  static int full_costs [FIRST_PSEUDO_REGISTER];
+  static int costs [FIRST_PSEUDO_REGISTER], full_costs [FIRST_PSEUDO_REGISTER];
 #ifdef STACK_REGS
   int no_stack_reg_p;
 #endif
@@ -204,14 +210,15 @@ assign_hard_reg (allocno_t allocno, int 
   ira_assert (! ALLOCNO_ASSIGNED_P (allocno));
   cover_class = ALLOCNO_COVER_CLASS (allocno);
   class_size = class_hard_regs_num [cover_class];
-  CLEAR_HARD_REG_SET (biased_regs);
+  mode = ALLOCNO_MODE (allocno);
   COPY_HARD_REG_SET (conflicting_regs, no_alloc_regs);
+  IOR_HARD_REG_SET (conflicting_regs,
+		    prohibited_class_mode_regs [cover_class] [mode]);
   IOR_COMPL_HARD_REG_SET (conflicting_regs, reg_class_contents [cover_class]);
   best_hard_regno = -1;
-  mode = ALLOCNO_MODE (allocno);
   memset (full_costs, 0, sizeof (int) * class_size);
   mem_cost = 0; 
-  bitmap_clear (processed_allocno_bitmap);
+  bitmap_clear (processed_coalesced_allocno_bitmap);
   memset (costs, 0, sizeof (int) * class_size);
   memset (full_costs, 0, sizeof (int) * class_size);
 #ifdef STACK_REGS
@@ -220,12 +227,13 @@ assign_hard_reg (allocno_t allocno, int 
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
-      mem_cost += ALLOCNO_MEMORY_COST (a);
+      mem_cost += ALLOCNO_UPDATED_MEMORY_COST (a);
       allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
-      IOR_HARD_REG_SET (conflicting_regs, ALLOCNO_CONFLICT_HARD_REGS (a));
-      a_costs = ALLOCNO_CURR_HARD_REG_COSTS (a);
+      IOR_HARD_REG_SET (conflicting_regs,
+			ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
+      a_costs = ALLOCNO_UPDATED_HARD_REG_COSTS (a);
 #ifdef STACK_REGS
-      no_stack_reg_p = no_stack_reg_p || ALLOCNO_NO_STACK_REG_P (a);
+      no_stack_reg_p = no_stack_reg_p || ALLOCNO_TOTAL_NO_STACK_REG_P (a);
 #endif
       for (i = 0; i < class_size; i++)
 	{
@@ -235,15 +243,14 @@ assign_hard_reg (allocno_t allocno, int 
       for (i = 0; (conflict_allocno = allocno_vec [i]) != NULL; i++)
 	/* Reload can give another class so we need to check all
 	   allocnos.  */
-	if (retry_p
-	    || (cover_class == ALLOCNO_COVER_CLASS (conflict_allocno)
-		&& bitmap_bit_p (consideration_allocno_bitmap,
-				 ALLOCNO_NUM (conflict_allocno))))
+	if (retry_p || bitmap_bit_p (consideration_allocno_bitmap,
+				     ALLOCNO_NUM (conflict_allocno)))
 	  {
-	    if (bitmap_bit_p (processed_allocno_bitmap,
+	    ira_assert (cover_class == ALLOCNO_COVER_CLASS (conflict_allocno));
+	    if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
 			      ALLOCNO_NUM (conflict_allocno)))
 	      continue;
-	    bitmap_set_bit (processed_allocno_bitmap,
+	    bitmap_set_bit (processed_coalesced_allocno_bitmap,
 			    ALLOCNO_NUM (conflict_allocno));
 	    if (ALLOCNO_ASSIGNED_P (conflict_allocno))
 	      {
@@ -263,24 +270,11 @@ assign_hard_reg (allocno_t allocno, int 
 	    else if (! ALLOCNO_MAY_BE_SPILLED_P (conflict_allocno))
 	      {
 		conflict_costs
-		  = ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (conflict_allocno);
+		  = ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (conflict_allocno);
 		if (conflict_costs != NULL)
 		  for (j = class_size - 1; j >= 0; j--)
 		    full_costs [j] -= conflict_costs [j];
 	      }
-	    if (retry_p || ! flag_ira_biased_coloring)
-	      continue;
-	    allocno_vec2 = ALLOCNO_CONFLICT_ALLOCNO_VEC (conflict_allocno);
-	    for (j = 0; (conflict_allocno2 = allocno_vec2 [j]) != NULL; j++)
-	      if (cover_class == ALLOCNO_COVER_CLASS (conflict_allocno2)
-		  && ALLOCNO_ASSIGNED_P (conflict_allocno2)
-		  && (hard_regno = ALLOCNO_HARD_REGNO (conflict_allocno2)) >= 0
-		  && (retry_p
-		      || bitmap_bit_p (consideration_allocno_bitmap,
-				       ALLOCNO_NUM (conflict_allocno2))))
-		IOR_HARD_REG_SET (biased_regs,
-				  reg_mode_hard_regset [hard_regno]
-				  [ALLOCNO_MODE (conflict_allocno2)]);
 	  }
       if (a == allocno)
 	break;
@@ -306,7 +300,7 @@ assign_hard_reg (allocno_t allocno, int 
 	      || ALLOCNO_ASSIGNED_P (another_allocno))
 	    continue;
 	  conflict_costs
-	    = ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (another_allocno);
+	    = ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno);
 	  if (conflict_costs != NULL
 	      && ! ALLOCNO_MAY_BE_SPILLED_P (another_allocno))
 	    for (j = class_size - 1; j >= 0; j--)
@@ -328,37 +322,29 @@ assign_hard_reg (allocno_t allocno, int 
 	  && FIRST_STACK_REG <= hard_regno && hard_regno <= LAST_STACK_REG)
 	continue;
 #endif
-      if (TEST_HARD_REG_BIT (prohibited_class_mode_regs
-			     [cover_class] [mode], hard_regno))
+      if (! hard_reg_not_in_set_p (hard_regno, mode, conflicting_regs))
 	continue;
-      if (hard_reg_not_in_set_p (hard_regno, mode, conflicting_regs))
-	{
-	  cost = costs [i];
-	  full_cost = full_costs [i];
-	  if (! allocated_hardreg_p [hard_regno]
-	      && hard_reg_not_in_set_p (hard_regno, mode, call_used_reg_set))
-	    /* We need to save/restore the register in
-	       epilogue/prologue.  Therefore we increase the cost.  */
-	    {
-	      /* ??? If only part is call clobbered.  */
-	      class = REGNO_REG_CLASS (hard_regno);
-	      add_cost = (memory_move_cost [mode] [class] [0]
-			  + memory_move_cost [mode] [class] [1] - 1);
-	      cost += add_cost;
-	      full_cost += add_cost;
-	    }
-	  if (min_cost > cost)
-	    min_cost = cost;
-	  if (min_full_cost > full_cost)
-	    {
-	      min_full_cost = full_cost;
-	      best_hard_regno = hard_regno;
-	      ira_assert (hard_regno >= 0);
-	    }
-	  else if (min_full_cost == full_cost && flag_ira_biased_coloring != 0
-		   && TEST_HARD_REG_BIT (biased_regs, hard_regno)
-		   && ! TEST_HARD_REG_BIT (biased_regs, best_hard_regno))
-	    best_hard_regno = hard_regno;
+      cost = costs [i];
+      full_cost = full_costs [i];
+      if (! allocated_hardreg_p [hard_regno]
+	  && hard_reg_not_in_set_p (hard_regno, mode, call_used_reg_set))
+	/* We need to save/restore the register in epilogue/prologue.
+	   Therefore we increase the cost.  */
+	{
+	  /* ??? If only part is call clobbered.  */
+	  class = REGNO_REG_CLASS (hard_regno);
+	  add_cost = (memory_move_cost [mode] [class] [0]
+		      + memory_move_cost [mode] [class] [1] - 1);
+	  cost += add_cost;
+	  full_cost += add_cost;
+	}
+      if (min_cost > cost)
+	min_cost = cost;
+      if (min_full_cost > full_cost)
+	{
+	  min_full_cost = full_cost;
+	  best_hard_regno = hard_regno;
+	  ira_assert (hard_regno >= 0);
 	}
     }
   if (min_cost > mem_cost)
@@ -382,9 +368,9 @@ assign_hard_reg (allocno_t allocno, int 
 	  ALLOCNO_FIRST_COALESCED_ALLOCNO (a) = a;
 	  ALLOCNO_NEXT_COALESCED_ALLOCNO (a) = a;
 	  VARRAY_PUSH_GENERIC_PTR (allocno_stack_varray, a);
-	  if (ira_dump_file != NULL)
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	    {
-	      fprintf (ira_dump_file, "  Pushing");
+	      fprintf (ira_dump_file, "      Pushing");
 	      print_coalesced_allocno (a);
 	    }
 	}
@@ -470,6 +456,10 @@ add_allocno_to_ordered_bucket (allocno_t
        before != NULL;
        after = before, before = ALLOCNO_NEXT_BUCKET_ALLOCNO (before))
     {
+      if (ALLOCNO_COVER_CLASS (before) < cover_class)
+	continue;
+      if (ALLOCNO_COVER_CLASS (before) > cover_class)
+	break;
       get_coalesced_allocnos_best_class_and_freq
 	(before, &best_class_before, &freq_before);
       if (best_class != best_class_before
@@ -528,20 +518,20 @@ push_allocno_to_stack (allocno_t allocno
   if (cover_class == NO_REGS)
     return;
   size = reg_class_nregs [cover_class] [ALLOCNO_MODE (allocno)];
-  bitmap_clear (processed_allocno_bitmap);
+  bitmap_clear (processed_coalesced_allocno_bitmap);
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
       allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
       for (i = 0; (conflict_allocno = allocno_vec [i]) != NULL; i++)
-	if (cover_class == ALLOCNO_COVER_CLASS (conflict_allocno)
-	    && bitmap_bit_p (coloring_allocno_bitmap,
-			     ALLOCNO_NUM (conflict_allocno)))
+	if (bitmap_bit_p (coloring_allocno_bitmap,
+			  ALLOCNO_NUM (conflict_allocno)))
 	  {
-	    if (bitmap_bit_p (processed_allocno_bitmap,
+	    ira_assert (cover_class == ALLOCNO_COVER_CLASS (conflict_allocno));
+	    if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
 			      ALLOCNO_NUM (conflict_allocno)))
 	      continue;
-	    bitmap_set_bit (processed_allocno_bitmap,
+	    bitmap_set_bit (processed_coalesced_allocno_bitmap,
 			    ALLOCNO_NUM (conflict_allocno));
 	    if (ALLOCNO_IN_GRAPH_P (conflict_allocno)
 		&& ! ALLOCNO_ASSIGNED_P (conflict_allocno))
@@ -584,9 +574,9 @@ remove_allocno_from_bucket_and_push (all
   bucket_ptr = (colorable_p
 		? &colorable_allocno_bucket : &uncolorable_allocno_bucket);
   delete_allocno_from_bucket (allocno, bucket_ptr);
-  if (ira_dump_file != NULL)
+  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
     {
-      fprintf (ira_dump_file, "  Pushing");
+      fprintf (ira_dump_file, "      Pushing");
       print_coalesced_allocno (allocno);
       fprintf (ira_dump_file, "%s\n", colorable_p ? "" : "(potential spill)");
     }
@@ -609,6 +599,7 @@ remove_allocno_from_bucket_and_push (all
 static void
 push_only_colorable (void)
 {
+  /* ??? sort here instead of putting it into ordered bucket.  */
   for (;colorable_allocno_bucket != NULL;)
     remove_allocno_from_bucket_and_push (colorable_allocno_bucket, TRUE);
 }
@@ -620,16 +611,16 @@ push_allocno_to_spill (allocno_t allocno
 {
   delete_allocno_from_bucket (allocno, &uncolorable_allocno_bucket);
   ALLOCNO_MAY_BE_SPILLED_P (allocno) = TRUE;
-  if (ira_dump_file != NULL)
-    fprintf (ira_dump_file, "  Pushing p%d(%d) (potential spill)\n",
+  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "      Pushing p%d(%d) (potential spill)\n",
 	     ALLOCNO_NUM (allocno), ALLOCNO_REGNO (allocno));
   push_allocno_to_stack (allocno);
 }
 
 /* The function returns frequency of exit edges (if EXIT_P) or enter
    from/to the loop given by its LOOP_NODE.  */ 
-static int
-loop_edge_freq (struct ira_loop_tree_node *loop_node, int regno, int exit_p)
+int
+loop_edge_freq (loop_tree_node_t loop_node, int regno, int exit_p)
 {
   int freq, i;
   edge_iterator ei;
@@ -671,10 +662,10 @@ calculate_allocno_spill_cost (allocno_t 
   enum machine_mode mode;
   enum reg_class class;
   allocno_t father_allocno;
-  struct ira_loop_tree_node *father_node, *loop_node;
+  loop_tree_node_t father_node, loop_node;
 
   regno = ALLOCNO_REGNO (a);
-  cost = ALLOCNO_MEMORY_COST (a) - ALLOCNO_COVER_CLASS_COST (a);
+  cost = ALLOCNO_UPDATED_MEMORY_COST (a) - ALLOCNO_COVER_CLASS_COST (a);
   if (ALLOCNO_CAP (a) != NULL)
     return cost;
   loop_node = ALLOCNO_LOOP_TREE_NODE (a);
@@ -838,9 +829,9 @@ pop_allocnos_from_stack (void)
       allocno = VARRAY_TOP_GENERIC_PTR (allocno_stack_varray);
       VARRAY_POP (allocno_stack_varray);
       cover_class = ALLOCNO_COVER_CLASS (allocno);
-      if (ira_dump_file != NULL)
+      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	{
-	  fprintf (ira_dump_file, "  Popping");
+	  fprintf (ira_dump_file, "      Popping");
 	  print_coalesced_allocno (allocno);
 	  fprintf (ira_dump_file, "  -- ");
 	}
@@ -848,18 +839,18 @@ pop_allocnos_from_stack (void)
 	{
 	  ALLOCNO_HARD_REGNO (allocno) = -1;
 	  ALLOCNO_ASSIGNED_P (allocno) = TRUE;
-	  if (ira_dump_file != NULL)
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	    fprintf (ira_dump_file, "assign memory\n");
 	}
       else if (assign_hard_reg (allocno, FALSE))
 	{
-	  if (ira_dump_file != NULL)
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	    fprintf (ira_dump_file, "assign reg %d\n",
 		     ALLOCNO_HARD_REGNO (allocno));
 	}
       else if (ALLOCNO_ASSIGNED_P (allocno))
 	{
-	  if (ira_dump_file != NULL)
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	    fprintf (ira_dump_file, "spill\n");
 	}
       ALLOCNO_IN_GRAPH_P (allocno) = TRUE;
@@ -884,15 +875,15 @@ setup_allocno_available_regs_num (allocn
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
-      IOR_HARD_REG_SET (temp_set, ALLOCNO_CONFLICT_HARD_REGS (a));
+      IOR_HARD_REG_SET (temp_set, ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
       if (a == allocno)
 	break;
     }
   for (n = 0, i = class_hard_regs_num [cover_class] - 1; i >= 0; i--)
     if (TEST_HARD_REG_BIT (temp_set, class_hard_regs [cover_class] [i]))
       n++;
-  if (n > 0 && ira_dump_file != NULL)
-    fprintf (ira_dump_file, "reg %d of %s has %d regs less\n",
+  if (internal_flag_ira_verbose > 2 && n > 0 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "    Reg %d of %s has %d regs less\n",
 	     ALLOCNO_REGNO (allocno), reg_class_names [cover_class], n);
   ALLOCNO_AVAILABLE_REGS_NUM (allocno) -= n;
 }
@@ -911,9 +902,9 @@ setup_allocno_left_conflicts_num (allocn
   hard_regs_num = class_hard_regs_num [cover_class];
   if (hard_regs_num != 0)
     {
-      memcpy (ALLOCNO_CURR_HARD_REG_COSTS (allocno),
+      memcpy (ALLOCNO_UPDATED_HARD_REG_COSTS (allocno),
 	      ALLOCNO_HARD_REG_COSTS (allocno), sizeof (int) * hard_regs_num);
-      memcpy (ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (allocno),
+      memcpy (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (allocno),
 	      ALLOCNO_CONFLICT_HARD_REG_COSTS (allocno),
 	      sizeof (int) * hard_regs_num);
     }
@@ -922,7 +913,7 @@ setup_allocno_left_conflicts_num (allocn
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
-      IOR_HARD_REG_SET (temp_set, ALLOCNO_CONFLICT_HARD_REGS (a));
+      IOR_HARD_REG_SET (temp_set, ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
       if (a == allocno)
 	break;
     }
@@ -942,21 +933,22 @@ setup_allocno_left_conflicts_num (allocn
 	  }
       }
   CLEAR_HARD_REG_SET (temp_set);
-  bitmap_clear (processed_allocno_bitmap);
+  bitmap_clear (processed_coalesced_allocno_bitmap);
   if (cover_class != NO_REGS)
     for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);;
 	 a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
       {
 	allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
 	for (i = 0; (conflict_allocno = allocno_vec [i]) != NULL; i++)
-	  if (cover_class == ALLOCNO_COVER_CLASS (conflict_allocno)
-	      && bitmap_bit_p (consideration_allocno_bitmap,
-			       ALLOCNO_NUM (conflict_allocno)))
+	  if (bitmap_bit_p (consideration_allocno_bitmap,
+			    ALLOCNO_NUM (conflict_allocno)))
 	    {
-	      if (bitmap_bit_p (processed_allocno_bitmap,
+	      ira_assert (cover_class
+			  == ALLOCNO_COVER_CLASS (conflict_allocno));
+	      if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
 				ALLOCNO_NUM (conflict_allocno)))
 		continue;
-	      bitmap_set_bit (processed_allocno_bitmap,
+	      bitmap_set_bit (processed_coalesced_allocno_bitmap,
 			      ALLOCNO_NUM (conflict_allocno));
 	      if (! ALLOCNO_ASSIGNED_P (conflict_allocno))
 		conflict_allocnos_size
@@ -998,9 +990,9 @@ put_allocno_into_bucket (allocno_t alloc
   hard_regs_num = class_hard_regs_num [cover_class];
   if (hard_regs_num != 0)
     {
-      memcpy (ALLOCNO_CURR_HARD_REG_COSTS (allocno),
+      memcpy (ALLOCNO_UPDATED_HARD_REG_COSTS (allocno),
 	      ALLOCNO_HARD_REG_COSTS (allocno), sizeof (int) * hard_regs_num);
-      memcpy (ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (allocno),
+      memcpy (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (allocno),
 	      ALLOCNO_CONFLICT_HARD_REG_COSTS (allocno),
 	      sizeof (int) * hard_regs_num);
     }
@@ -1042,6 +1034,7 @@ merge_allocnos (allocno_t a1, allocno_t 
 {
   allocno_t a, first, last, next;
 
+  ira_assert (ALLOCNO_MODE (a1) == ALLOCNO_MODE (a2));
   first = ALLOCNO_FIRST_COALESCED_ALLOCNO (a1);
   if (first == ALLOCNO_FIRST_COALESCED_ALLOCNO (a2))
     return;
@@ -1062,16 +1055,16 @@ merge_allocnos (allocno_t a1, allocno_t 
    from two sets of coalesced allocnos given by allocnos A1 and
    A2.  */
 static int
-allocno_conflict_p (allocno_t a1, allocno_t a2)
+coalesced_allocno_conflict_p (allocno_t a1, allocno_t a2)
 {
   allocno_t a, conflict_allocno, *allocno_vec;
   int i;
 
-  bitmap_clear (processed_allocno_bitmap);
+  bitmap_clear (processed_coalesced_allocno_bitmap);
   for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a1);;
        a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a))
     {
-      bitmap_set_bit (processed_allocno_bitmap, ALLOCNO_NUM (a));
+      bitmap_set_bit (processed_coalesced_allocno_bitmap, ALLOCNO_NUM (a));
       if (a == a1)
 	break;
     }
@@ -1080,7 +1073,7 @@ allocno_conflict_p (allocno_t a1, allocn
     {
       allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
       for (i = 0; (conflict_allocno = allocno_vec [i]) != NULL; i++)
-	if (bitmap_bit_p (processed_allocno_bitmap,
+	if (bitmap_bit_p (processed_coalesced_allocno_bitmap,
 			  ALLOCNO_NUM (conflict_allocno)))
 	  return TRUE;
       if (a == a2)
@@ -1116,11 +1109,7 @@ coalesce_allocnos (void)
 	    {
 	      next_cp = cp->next_first_allocno_copy;
 	      if (ALLOCNO_COVER_CLASS (cp->second) == cover_class
-		  && ALLOCNO_MODE (cp->second) == mode
-#if 0
-		  && (1 || cover_class == SSE_REGS || cover_class == MMX_REGS)
-#endif
-		  )
+		  && ALLOCNO_MODE (cp->second) == mode)
 		sorted_copies [cp_num++] = cp;
 	    }
 	  else if (cp->second == a)
@@ -1135,10 +1124,10 @@ coalesce_allocnos (void)
       for (i = 0; i < cp_num; i++)
 	{
 	  cp = sorted_copies [i];
-	  if (! allocno_conflict_p (cp->first, cp->second))
+	  if (! coalesced_allocno_conflict_p (cp->first, cp->second))
 	    {
-	      if (ira_dump_file != NULL)
-		fprintf (stderr, "Coalescing copy %d (freq=%d)\n",
+	      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+		fprintf (ira_dump_file, "      Coalescing copy %d (freq=%d)\n",
 			 cp->num, cp->freq);
 	      merge_allocnos (cp->first, cp->second);
 	      i++;
@@ -1166,7 +1155,7 @@ color_allocnos (void)
   unsigned int i;
   bitmap_iterator bi;
 
-  processed_allocno_bitmap = ira_allocate_bitmap ();
+  processed_coalesced_allocno_bitmap = ira_allocate_bitmap ();
   if (flag_ira_coalesce)
     coalesce_allocnos ();
   /* Put the allocnos into the corresponding buckets.  */
@@ -1185,7 +1174,7 @@ color_allocnos (void)
 	ALLOCNO_FIRST_COALESCED_ALLOCNO (a) = a;
 	ALLOCNO_NEXT_COALESCED_ALLOCNO (a) = a;
       }
-  ira_free_bitmap (processed_allocno_bitmap);
+  ira_free_bitmap (processed_coalesced_allocno_bitmap);
 }
 
 
@@ -1193,7 +1182,7 @@ color_allocnos (void)
 /* The function outputs information about the loop given by its
    LOOP_TREE_NODE. */
 static void
-print_loop_title (struct ira_loop_tree_node *loop_tree_node)
+print_loop_title (loop_tree_node_t loop_tree_node)
 {
   unsigned int j;
   bitmap_iterator bi;
@@ -1232,7 +1221,7 @@ print_loop_title (struct ira_loop_tree_n
    loop (in extreme case it can be all function) given by the
    corresponding LOOP_TREE_NODE.  */
 static void
-color_pass (struct ira_loop_tree_node *loop_tree_node)
+color_pass (loop_tree_node_t loop_tree_node)
 {
   int regno, hard_regno, index = -1;
   int cost, exit_freq, enter_freq;
@@ -1241,11 +1230,11 @@ color_pass (struct ira_loop_tree_node *l
   enum machine_mode mode;
   enum reg_class class;
   allocno_t a, subloop_allocno;
-  struct ira_loop_tree_node *subloop_node;
+  loop_tree_node_t subloop_node;
 
   if (loop_tree_node->loop == NULL)
     return;
-  if (ira_dump_file != NULL)
+  if (internal_flag_ira_verbose > 1 && ira_dump_file != NULL)
     print_loop_title (loop_tree_node);
 
   bitmap_copy (coloring_allocno_bitmap, loop_tree_node->mentioned_allocnos);
@@ -1284,7 +1273,7 @@ color_pass (struct ira_loop_tree_node *l
 	      if (subloop_allocno == NULL)
 		continue;
 	      if ((flag_ira_algorithm == IRA_ALGORITHM_MIXED
-		   && subloop_node->reg_pressure [class]
+		   && loop_tree_node->reg_pressure [class]
 		      <= available_class_regs [class]))
 		{
 		  if (! ALLOCNO_ASSIGNED_P (subloop_allocno))
@@ -1311,7 +1300,7 @@ color_pass (struct ira_loop_tree_node *l
 		}
 	      else if (hard_regno < 0)
 		{
-		  ALLOCNO_MEMORY_COST (subloop_allocno)
+		  ALLOCNO_UPDATED_MEMORY_COST (subloop_allocno)
 		    -= ((memory_move_cost [mode] [class] [1] * enter_freq)
 			+ (memory_move_cost [mode] [class] [0] * exit_freq));
 		}
@@ -1322,7 +1311,7 @@ color_pass (struct ira_loop_tree_node *l
 		  ALLOCNO_HARD_REG_COSTS (subloop_allocno) [index] -= cost;
 		  ALLOCNO_CONFLICT_HARD_REG_COSTS (subloop_allocno) [index]
 		    -= cost;
-		  ALLOCNO_MEMORY_COST (subloop_allocno)
+		  ALLOCNO_UPDATED_MEMORY_COST (subloop_allocno)
 		    += (memory_move_cost [mode] [class] [0] * enter_freq
 			+ memory_move_cost [mode] [class] [1] * exit_freq);
 		  if (ALLOCNO_COVER_CLASS_COST (subloop_allocno)
@@ -1334,7 +1323,7 @@ color_pass (struct ira_loop_tree_node *l
 	  else
 	    {
 	      if ((flag_ira_algorithm == IRA_ALGORITHM_MIXED
-		   && subloop_node->reg_pressure [class]
+		   && loop_tree_node->reg_pressure [class]
 		      <= available_class_regs [class]))
 		{
 		  subloop_allocno = ALLOCNO_CAP_MEMBER (a);
@@ -1356,7 +1345,7 @@ color_pass (struct ira_loop_tree_node *l
 		  ALLOCNO_HARD_REG_COSTS (subloop_allocno) [index] -= cost;
 		  ALLOCNO_CONFLICT_HARD_REG_COSTS (subloop_allocno) [index]
 		    -= cost;
-		  ALLOCNO_MEMORY_COST (subloop_allocno)
+		  ALLOCNO_UPDATED_MEMORY_COST (subloop_allocno)
 		    += (memory_move_cost [mode] [class] [0] * enter_freq
 			+ memory_move_cost [mode] [class] [1] * exit_freq);
 		  if (ALLOCNO_COVER_CLASS_COST (subloop_allocno)
@@ -1368,35 +1357,60 @@ color_pass (struct ira_loop_tree_node *l
 	}
 }
 
+/* Map: allocno number -> allocno prioirity.  */
+static int *allocno_priorities;
+
+/* Allocate array ALLOCNO_PRIORITIES and set up priorities for N allocnos in
+   array CONSIDERATION_ALLOCNOS.  */
+static void
+start_allocno_priorities (allocno_t *consideration_allocnos, int n)
+{
+  int i, length;
+  allocno_t a;
+  allocno_live_range_t r;
+
+  allocno_priorities = ira_allocate (sizeof (int) * allocnos_num);
+  for (i = 0; i < n; i++)
+    {
+      a = consideration_allocnos [i];
+      for (length = 0, r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = r->next)
+	length += r->finish - r->start + 1;
+      if (length == 0)
+	{
+	  allocno_priorities [ALLOCNO_NUM (a)] = 0;
+	  continue;
+	}
+      ira_assert (length > 0 && ALLOCNO_NREFS (a) > 0);
+      allocno_priorities [ALLOCNO_NUM (a)]
+	= (((double) (floor_log2 (ALLOCNO_NREFS (a)) * ALLOCNO_FREQ (a))
+	    / length)
+	   * (10000 / REG_FREQ_MAX) * PSEUDO_REGNO_SIZE (ALLOCNO_REGNO (a)));
+    }
+}
+
 /* The function is used to sort allocnos according to their priorities
    which are calculated analogous to ones in file `global.c'.  */
 static int
 allocno_priority_compare_func (const void *v1p, const void *v2p)
 {
-  allocno_t p1 = *(const allocno_t *) v1p, p2 = *(const allocno_t *) v2p;
+  allocno_t a1 = *(const allocno_t *) v1p, a2 = *(const allocno_t *) v2p;
   int pri1, pri2;
 
-#if 0
-  pri1 = (((double) (floor_log2 (REG_N_REFS (ALLOCNO_REGNO (p1)))
-		     * ALLOCNO_FREQ (p1))
-	   / REG_LIVE_LENGTH (ALLOCNO_REGNO (p1)))
-	  * (10000 / REG_FREQ_MAX) * PSEUDO_REGNO_SIZE (ALLOCNO_REGNO (p1)));
-  pri2 = (((double) (floor_log2 (REG_N_REFS (ALLOCNO_REGNO (p2)))
-		     * ALLOCNO_FREQ (p2))
-	   / REG_LIVE_LENGTH (ALLOCNO_REGNO (p2)))
-	  * (10000 / REG_FREQ_MAX) * PSEUDO_REGNO_SIZE (ALLOCNO_REGNO (p2)));
-#else
-  pri1 = (ALLOCNO_FREQ (p1) * (10000 / REG_FREQ_MAX)
-	  * PSEUDO_REGNO_SIZE (ALLOCNO_REGNO (p1)));
-  pri2 = (ALLOCNO_FREQ (p2) * (10000 / REG_FREQ_MAX)
-	  * PSEUDO_REGNO_SIZE (ALLOCNO_REGNO (p2)));
-#endif
+  pri1 = allocno_priorities [ALLOCNO_NUM (a1)];
+  pri2 = allocno_priorities [ALLOCNO_NUM (a2)];
   if (pri2 - pri1)
     return pri2 - pri1;
 
   /* If regs are equally good, sort by allocnos, so that the results of
      qsort leave nothing to chance.  */
-  return ALLOCNO_NUM (p1) - ALLOCNO_NUM (p2);
+  return ALLOCNO_NUM (a1) - ALLOCNO_NUM (a2);
+}
+
+/* Free ALLOCATE_PRIORITIES.  */
+static void
+finish_allocno_priorities (void)
+{
+  ira_free (allocno_priorities);
 }
 
 /* The function implements Chow's prioity-based coloring.  */
@@ -1406,7 +1420,7 @@ priority_coloring (void)
   int i, hard_regs_num;
   allocno_t a;
 
-  processed_allocno_bitmap = ira_allocate_bitmap ();
+  processed_coalesced_allocno_bitmap = ira_allocate_bitmap ();
   memcpy (sorted_allocnos, allocnos, allocnos_num * sizeof (allocno_t));
   for (i = 0; i < allocnos_num; i++)
     {
@@ -1415,38 +1429,40 @@ priority_coloring (void)
       hard_regs_num = class_hard_regs_num [ALLOCNO_COVER_CLASS (a)];
       if (hard_regs_num == 0)
 	continue;
-      memcpy (ALLOCNO_CURR_HARD_REG_COSTS (a),
+      memcpy (ALLOCNO_UPDATED_HARD_REG_COSTS (a),
 	      ALLOCNO_HARD_REG_COSTS (a), sizeof (int) * hard_regs_num);
-      memcpy (ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (a),
+      memcpy (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a),
 	      ALLOCNO_CONFLICT_HARD_REG_COSTS (a),
 	      sizeof (int) * hard_regs_num);
     }
   bitmap_copy (consideration_allocno_bitmap, coloring_allocno_bitmap);
+  start_allocno_priorities (sorted_allocnos, allocnos_num);
   qsort (sorted_allocnos, allocnos_num, sizeof (allocno_t),
 	 allocno_priority_compare_func);
+  finish_allocno_priorities ();
   for (i = 0; i < allocnos_num; i++)
     {
       a = sorted_allocnos [i];
-      if (ira_dump_file != NULL)
+      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	{
-	  fprintf (ira_dump_file, "  ");
+	  fprintf (ira_dump_file, "      ");
 	  print_expanded_allocno (a);
 	  fprintf (ira_dump_file, "  -- ");
 	}
       if (assign_hard_reg (a, FALSE))
 	{
-	  if (ira_dump_file != NULL)
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	    fprintf (ira_dump_file, "assign reg %d\n",
 		     ALLOCNO_HARD_REGNO (a));
 	}
       else
 	{
-	  if (ira_dump_file != NULL)
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	    fprintf (ira_dump_file, "spill\n");
 	}
       ALLOCNO_IN_GRAPH_P (a) = TRUE;
     }
-  ira_free_bitmap (processed_allocno_bitmap);
+  ira_free_bitmap (processed_coalesced_allocno_bitmap);
 }
 
 /* The function initialized common data for cloring and calls
@@ -1462,13 +1478,13 @@ do_coloring (void)
     priority_coloring ();
   else
     {
-      if (ira_dump_file != NULL)
+      if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
 	fprintf (ira_dump_file, "\n**** Allocnos coloring:\n\n");
       
-      traverse_loop_tree (ira_loop_tree_root, color_pass, NULL);
+      traverse_loop_tree (FALSE, ira_loop_tree_root, color_pass, NULL);
     }
 
-  if (ira_dump_file != NULL)
+  if (internal_flag_ira_verbose > 1 && ira_dump_file != NULL)
     print_disposition (ira_dump_file);
 
   ira_free_bitmap (consideration_allocno_bitmap);
@@ -1489,12 +1505,12 @@ move_spill_restore (void)
   enum machine_mode mode;
   enum reg_class class;
   allocno_t a, father_allocno, subloop_allocno;
-  struct ira_loop_tree_node *father, *loop_node, *subloop_node;
+  loop_tree_node_t father, loop_node, subloop_node;
 
   for (;;)
     {
       changed_p = FALSE;
-      if (ira_dump_file != NULL)
+      if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
 	fprintf (ira_dump_file, "New iteration of spill/restore move\n");
       for (i = 0; i < allocnos_num; i++)
 	{
@@ -1509,8 +1525,7 @@ move_spill_restore (void)
 	  class = ALLOCNO_COVER_CLASS (a);
 	  index = class_hard_reg_index [class] [hard_regno];
 	  ira_assert (index >= 0);
-	  cost = (ALLOCNO_ORIGINAL_MEMORY_COST (a)
-		  - ALLOCNO_HARD_REG_COSTS (a) [index]);
+	  cost = ALLOCNO_MEMORY_COST (a) - ALLOCNO_HARD_REG_COSTS (a) [index];
 	  for (subloop_node = loop_node->inner;
 	       subloop_node != NULL;
 	       subloop_node = subloop_node->next)
@@ -1520,7 +1535,7 @@ move_spill_restore (void)
 	      subloop_allocno = subloop_node->regno_allocno_map [regno];
 	      if (subloop_allocno == NULL)
 		continue;
-	      cost -= (ALLOCNO_ORIGINAL_MEMORY_COST (subloop_allocno)
+	      cost -= (ALLOCNO_MEMORY_COST (subloop_allocno)
 		       - ALLOCNO_HARD_REG_COSTS (subloop_allocno) [index]);
 	      exit_freq = loop_edge_freq (subloop_node, regno, TRUE);
 	      enter_freq = loop_edge_freq (subloop_node, regno, FALSE);
@@ -1556,10 +1571,14 @@ move_spill_restore (void)
 	  if (cost < 0)
 	    {
 	      ALLOCNO_HARD_REGNO (a) = -1;
-	      if (ira_dump_file != NULL)
-		fprintf (ira_dump_file,
-			 "Moving spill/restore for a%dr%d up from loop %d - profit %d\n",
-			 ALLOCNO_NUM (a), regno, loop_node->loop->num, -cost);
+	      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+		{
+		  fprintf
+		    (ira_dump_file,
+		     "      Moving spill/restore for a%dr%d up from loop %d",
+		     ALLOCNO_NUM (a), regno, loop_node->loop->num);
+		  fprintf (ira_dump_file, " - profit %d\n", -cost);
+		}
 	      changed_p = TRUE;
 	    }
 	}
@@ -1589,12 +1608,10 @@ setup_curr_costs (allocno_t a)
   if (hard_regs_num == 0)
     return;
   mode = ALLOCNO_MODE (a);
-  memcpy (ALLOCNO_CURR_HARD_REG_COSTS (a),
-	  ALLOCNO_HARD_REG_COSTS (a),
-	  sizeof (int) * hard_regs_num);
-  memcpy (ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (a),
-	  ALLOCNO_CONFLICT_HARD_REG_COSTS (a),
-	  sizeof (int) * hard_regs_num);
+  memcpy (ALLOCNO_UPDATED_HARD_REG_COSTS (a),
+	  ALLOCNO_HARD_REG_COSTS (a), sizeof (int) * hard_regs_num);
+  memcpy (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a),
+	  ALLOCNO_CONFLICT_HARD_REG_COSTS (a), sizeof (int) * hard_regs_num);
   for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp)
     {
       if (cp->first == a)
@@ -1619,8 +1636,8 @@ setup_curr_costs (allocno_t a)
       cost = (cp->first == a
 	      ? register_move_cost [mode] [class] [cover_class]
 	      : register_move_cost [mode] [cover_class] [class]);
-      ALLOCNO_CURR_HARD_REG_COSTS (a) [i] -= cp->freq * cost;
-      ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (a) [i] -= cp->freq * cost;
+      ALLOCNO_UPDATED_HARD_REG_COSTS (a) [i] -= cp->freq * cost;
+      ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) [i] -= cp->freq * cost;
     }
 }
 
@@ -1655,14 +1672,14 @@ reassign_conflict_allocnos (int start_re
 	    }
 	  bitmap_set_bit (allocnos_to_color, ALLOCNO_NUM (a));
 	}
-      if (ALLOCNO_REGNO (a) < start_regno)
+      if (ALLOCNO_REGNO (a) < start_regno
+	  || (cover_class = ALLOCNO_COVER_CLASS (a)) == NO_REGS)
 	continue;
       allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
       for (j = 0; (conflict_a = allocno_vec [j]) != NULL; j++)
 	{
-	  if ((cover_class = ALLOCNO_COVER_CLASS (conflict_a)) == NO_REGS
-	      || (no_call_cross_p
-		  && ALLOCNO_CALLS_CROSSED_NUM (conflict_a) != 0)
+	  ira_assert (cover_class == ALLOCNO_COVER_CLASS (conflict_a));
+	  if ((no_call_cross_p  && ALLOCNO_CALLS_CROSSED_NUM (conflict_a) != 0)
 	      || bitmap_bit_p (allocnos_to_color, ALLOCNO_NUM (conflict_a)))
 	    continue;
 	  bitmap_set_bit (allocnos_to_color, ALLOCNO_NUM (conflict_a));
@@ -1671,8 +1688,12 @@ reassign_conflict_allocnos (int start_re
     }
   ira_free_bitmap (allocnos_to_color);
   if (allocnos_to_color_num > 1)
-    qsort (sorted_allocnos, allocnos_to_color_num, sizeof (allocno_t),
-	   allocno_priority_compare_func);
+    {
+      start_allocno_priorities (sorted_allocnos, allocnos_to_color_num);
+      qsort (sorted_allocnos, allocnos_to_color_num, sizeof (allocno_t),
+	     allocno_priority_compare_func);
+      finish_allocno_priorities ();
+    }
   for (i = 0; i < allocnos_to_color_num; i++)
     {
       a = sorted_allocnos [i];
@@ -1684,10 +1705,11 @@ reassign_conflict_allocnos (int start_re
       a = sorted_allocnos [i];
       if (assign_hard_reg (a, TRUE))
 	{
-	  if (ira_dump_file != NULL)
-	    fprintf (ira_dump_file,
-		     "after call opt: assign hard reg %d to reg %d\n",
-		     ALLOCNO_HARD_REGNO (a), ALLOCNO_REGNO (a));
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	    fprintf
+	      (ira_dump_file,
+	       "      Secondary allocation: assign hard reg %d to reg %d\n",
+	       ALLOCNO_HARD_REGNO (a), ALLOCNO_REGNO (a));
 	}
     }
   ira_free (sorted_allocnos);
@@ -1709,7 +1731,7 @@ mark_allocation_change (int regno)
   if ((old_hard_regno = ALLOCNO_HARD_REGNO (a)) == hard_regno)
     return;
   if (old_hard_regno < 0)
-    cost = -ALLOCNO_MEMORY_COST (a);
+    cost = -ALLOCNO_UPDATED_MEMORY_COST (a);
   else
     {
       ira_assert (class_hard_reg_index [cover_class] [old_hard_regno] >= 0);
@@ -1720,7 +1742,7 @@ mark_allocation_change (int regno)
   overall_cost -= cost;
   ALLOCNO_HARD_REGNO (a) = hard_regno;
   if (hard_regno < 0)
-    cost += ALLOCNO_MEMORY_COST (a);
+    cost += ALLOCNO_UPDATED_MEMORY_COST (a);
   else if (class_hard_reg_index [cover_class] [hard_regno] >= 0)
     {
       cost += (ALLOCNO_HARD_REG_COSTS (a)
@@ -1746,13 +1768,13 @@ retry_ira_color (int regno, HARD_REG_SET
   a = regno_allocno_map [regno];
   mark_allocation_change (regno);
   ira_assert (reg_renumber [regno] < 0);
-  if (ira_dump_file != NULL)
-    fprintf (ira_dump_file, "spill %d(a%d), cost=%d", regno, ALLOCNO_NUM (a),
-	     ALLOCNO_MEMORY_COST (a) - ALLOCNO_COVER_CLASS_COST (a));
-  IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), forbidden_regs);
-  if ((! flag_caller_saves || flag_ira_split_around_calls)
-      && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
-    IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), call_used_reg_set);
+  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+    fprintf (ira_dump_file,
+	     "      Spill %d(a%d), cost=%d", regno, ALLOCNO_NUM (a),
+	     ALLOCNO_UPDATED_MEMORY_COST (a) - ALLOCNO_COVER_CLASS_COST (a));
+  IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), forbidden_regs);
+  if (! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+    IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), call_used_reg_set);
   ALLOCNO_ASSIGNED_P (a) = FALSE;
   cover_class = ALLOCNO_COVER_CLASS (a);
   setup_curr_costs (a);
@@ -1762,15 +1784,14 @@ retry_ira_color (int regno, HARD_REG_SET
   if (hard_regno >= 0)
     {
       ira_assert (class_hard_reg_index [cover_class] [hard_regno] >= 0);
-      overall_cost -= (ALLOCNO_MEMORY_COST (a)
+      overall_cost -= (ALLOCNO_UPDATED_MEMORY_COST (a)
 		       - (ALLOCNO_HARD_REG_COSTS (a)
-			  [class_hard_reg_index
-			   [cover_class] [hard_regno]]));
+			  [class_hard_reg_index [cover_class] [hard_regno]]));
       if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0
 	  && ! hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a),
 				      call_used_reg_set))
 	{
-	  ira_assert (flag_caller_saves && ! flag_ira_split_around_calls);
+	  ira_assert (flag_caller_saves);
 	  caller_save_needed = 1;
 	}
     }
@@ -1779,17 +1800,13 @@ retry_ira_color (int regno, HARD_REG_SET
      the hard register, and mark that register live.  */
   if (reg_renumber[regno] >= 0)
     {
-      if (ira_dump_file != NULL)
+      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
 	fprintf (ira_dump_file, ": reassign to %d", reg_renumber[regno]);
       SET_REGNO (regno_reg_rtx[regno], reg_renumber[regno]);
       mark_home_live (regno);
     }
-  else if (ira_dump_file != NULL && original_regno_call_crossed_p [regno]
-	   && ! flag_caller_saves && flag_ira_split_around_calls
-	   && get_around_calls_regno (regno) >= 0)
-    fprintf (ira_dump_file, "+++spilling %d\n", regno);
 
-  if (ira_dump_file != NULL)
+  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
     fprintf (ira_dump_file, "\n");
 }
 
@@ -1881,9 +1898,9 @@ reuse_stack_slot (int regno, unsigned in
     }
   if (x)
     {
-      if (ira_dump_file)
+      if (internal_flag_ira_verbose > 3 && ira_dump_file)
 	{
-	  fprintf (ira_dump_file, " Assigning %d slot of", regno);
+	  fprintf (ira_dump_file, "      Assigning %d slot of", regno);
 	  EXECUTE_IF_SET_IN_BITMAP (&slot->spilled_regs,
 				    FIRST_PSEUDO_REGISTER, i, bi)
 	    {
@@ -1909,8 +1926,8 @@ mark_new_stack_slot (rtx x, int regno, u
   SET_REGNO_REG_SET (&slot->spilled_regs, regno);
   slot->mem = x;
   slot->width = total_size;
-  if (ira_dump_file)
-    fprintf (ira_dump_file, " Assigning %d a new slot\n", regno);
+  if (internal_flag_ira_verbose > 3 && ira_dump_file)
+    fprintf (ira_dump_file, "      Assigning %d a new slot\n", regno);
 }
 
 
Index: opts.c
===================================================================
--- opts.c	(revision 129968)
+++ opts.c	(working copy)
@@ -1736,6 +1736,10 @@ common_handle_option (size_t scode, cons
 	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;
Index: ira-call.c
===================================================================
--- ira-call.c	(revision 129968)
+++ ira-call.c	(working copy)
@@ -1,1070 +0,0 @@
-/* Splitting ranges around calls for IRA.
-   Copyright (C) 2006, 2007
-   Free Software Foundation, Inc.
-   Contributed by Vladimir Makarov <vmakarov@redhat.com>.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "hard-reg-set.h"
-#include "rtl.h"
-#include "tm_p.h"
-#include "target.h"
-#include "regs.h"
-#include "flags.h"
-#include "basic-block.h"
-#include "toplev.h"
-#include "expr.h"
-#include "params.h"
-#include "reload.h"
-#include "df.h"
-#include "output.h"
-#include "ira-int.h"
-
-/* The file is responsible for splitting the live range of
-   pseudo-registers living through calls which are assigned to
-   call-used hard-registers in two parts: one range (a new
-   pseudo-register is created for this) which lives through the calls
-   and another range (the original pseudo-register is used for the
-   range) lives between the calls.  Memory is assigned to new
-   pseudo-registers.  Move instructions connecting the two live ranges
-   (the original and new pseudo-registers) will be transformed into
-   load/store instructions in the reload pass.
-
-   This file also does global save/restore code redundancy
-   elimination.  It calculates points to put save/restore instructions
-   according the following data flow equations:
-
-   SaveOut(b) = intersect (SaveIn(p) - SaveIgnore(pb))
-                for each p in pred(b)
-
-                    | 0              if depth (b) <= depth (p)
-   SaveIgnore(pb) = | 
-                    | Ref(loop(b))   if depth (b) > depth (p)
-
-   SaveIn(b) = (SaveOut(b) - Kill(b)) U SaveGen(b)
-
-   RestoreIn(b) = intersect (RestoreOut(s) - RestoreIgnore(bs))
-                  for each s in succ(b)
-
-                       | 0           if depth (b) <= depth (s)
-   RestoreIgnore(bs) = |
-                       | Ref(loop(b))if depth (b) > depth (s)
-
-   RestoreOut(b) = (RestoreIn(b) - Kill(b)) U RestoreGen(b)
-
-   Here, Kill(b) is the set of allocnos referenced in basic block b
-   and SaveGen(b) and RestoreGen(b) is the set of allocnos which
-   should be correspondingly saved and restored in basic block b and
-   which are not referenced correspondingly before the last and after
-   the first calls they live through in basic block b.  SaveIn(b),
-   SaveOut(b), RestoreIn(b), RestoreOut(b) are allocnos
-   correspondingly to save and to restore at the start and the end of
-   basic block b.  Save and restore code is not moved to more
-   frequently executed points (inside loops).  The code can be moved
-   through a loop unless it is referenced in the loop (this set of
-   allocnos is denoted by Ref(loop)).
-
-   We should put code to save/restore an allocno on an edge (p,s) if
-   the allocno lives on the edge and the corresponding values of the
-   sets at end of p and at the start of s are different.  In practice,
-   code unification is done: if the save/restore code should be on all
-   outgoing edges or all incoming edges, it is placed at the edge
-   source and destination correspondingly.
-
-   Putting live ranges living through calls into memory means that
-   some conflicting pseudo-registers (such pseudo-registers should not
-   live through calls) assigned to memory have a chance to be assigned
-   to the corresponding call-used hard-register.  It is done by
-   ira-color.c:reassign_conflict_allocnos using simple priority-based
-   colouring for the conflicting pseudo-registers.  The bigger the
-   live range of pseudo-register living through calls, the better such
-   a chance is.  Therefore, we move spill/restore code as far as
-   possible inside basic blocks.
-
-   The implementation of save/restore code generation before the
-   reload pass has several advantages:
-
-     o simpler implementation of sharing stack slots used for spilled
-       pseudos and for saving pseudo values around calls.  Actually,
-       the same code for sharing stack slots allocated for pseudos is
-       used in this case.
-
-     o simpler implementation of moving save/restore code to increase
-       the range of memory pseudo can be stored in.
-
-     o simpler implementation of improving allocation by assigning
-       hard-registers to spilled pseudos which conflict with new
-       pseudos living through calls.
-
-   The disadvantage of such an approach is mainly in the reload pass,
-   whose behavior is hard to predict.  If the reload pass decides that
-   the original pseudos should be spilled, save/restore code will be
-   transformed into a memory-memory move.  To remove such nasty moves,
-   IRA is trying to use the same stack slot for the two pseudos.  It
-   is achieved using a standard preference technique to use the same
-   stack slot for pseudos involved in moves.  A move between pseudos
-   assigned to the same memory could be removed by post-reload
-   optimizations, but it is implemented in the reload pass because, if
-   it is not done earlier, a hard-register would be required for this
-   and most probably a pseudo-register would be spilled by the reload
-   to free the hard-register.
-
-*/
-
-/* ??? TODO: Abnormal edges  */
-/* The following structure contains basic block data flow information
-   used to calculate registers to save restore.  */
-struct bb_info
-{
-  /* Local bb info: */
-  /* Registers mentioned in the BB.  */
-  bitmap kill;
-  /* Registers needed to be saved and this save not killed (see above)
-     by an insn in the BB before that.  */
-  bitmap saveloc;
-  /* Registers needed to be restored and this restore not killed by an
-     insn in the BB after that.  */
-  bitmap restoreloc;
-  /* Global save and restore info.  */
-  bitmap savein, saveout, restorein, restoreout;
-};
-
-/* 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))
-
-/* DF infrastructure data.  */
-static struct df_problem problem;
-static struct dataflow dflow;
-
-/* Basic blocks in postorder.  */
-static int *postorder;
-/* The size of the previous array.  */
-static int n_blocks;
-/* Bitmap of all basic blocks.  */
-static bitmap current_all_blocks;
-
-static rtx *reg_map;
-
-/* Numbers of currently live pseudo-registers.  */
-static bitmap regs_live;
-
-/* Numbers of all registers which should be split around calls.  */
-static bitmap regs_to_save_restore;
-
-/* Bitmap used to collect numbers of referenced regs inside a rtx.  */
-static bitmap referenced_regs;
-
-/* Array of bitmaps for each loop node.  The bitmap contains numbers
-   of registers mentioned int the corresponding loop (and all its
-   subloops).  */
-static bitmap *loop_referenced_regs_array;
-/* The size of the previous array.  */
-static int loop_referenced_regs_array_len;
-
-/* Bitmaps used for saving intermediate results.  */
-static bitmap temp_bitmap;
-static bitmap temp_bitmap2;
-
-/* Set of hard regs (except eliminable ones) currently live (during
-   scan of all insns).  */
-static HARD_REG_SET hard_regs_live;
-
-/* Allocate and initialize data used for splitting allocnos around
-   calls.  */
-static void
-init_ira_call_data (void)
-{
-  int i;
-
-  postorder = ira_allocate (sizeof (int) * last_basic_block);
-  current_all_blocks = ira_allocate_bitmap ();
-
-  n_blocks = post_order_compute (postorder, true, false);
-
-  if (n_blocks != n_basic_blocks)
-    delete_unreachable_blocks ();
-
-  alloc_aux_for_blocks (sizeof (struct bb_info));
-  for (i = 0; i < n_blocks; i++)
-    {
-      struct bb_info *bb_info;
-
-      bitmap_set_bit (current_all_blocks, postorder [i]);
-      bb_info = BB_INFO_BY_INDEX (postorder [i]);
-      bb_info->kill = ira_allocate_bitmap ();
-      bb_info->saveloc = ira_allocate_bitmap ();
-      bb_info->restoreloc = ira_allocate_bitmap ();
-      bb_info->savein = ira_allocate_bitmap ();
-      bb_info->saveout = ira_allocate_bitmap ();
-      bb_info->restorein = ira_allocate_bitmap ();
-      bb_info->restoreout = ira_allocate_bitmap ();
-    }
-
-  loop_referenced_regs_array_len = VEC_length (loop_p, ira_loops.larray);
-  loop_referenced_regs_array
-    = ira_allocate (loop_referenced_regs_array_len * sizeof (bitmap));
-  for (i = 0; i < loop_referenced_regs_array_len; i++)
-    loop_referenced_regs_array [i] = ira_allocate_bitmap ();
-
-  memset (&problem, 0, sizeof (problem));
-  memset (&dflow, 0, sizeof (dflow));
-  dflow.problem= &problem;
-
-  reg_map = ira_allocate (sizeof (rtx) * max_reg_num ());
-  memset (reg_map, 0, sizeof (rtx) * max_reg_num ());
-  regs_live = ira_allocate_bitmap ();
-  referenced_regs = ira_allocate_bitmap ();
-  regs_to_save_restore = ira_allocate_bitmap ();
-  temp_bitmap = ira_allocate_bitmap ();
-  temp_bitmap2 = ira_allocate_bitmap ();
-}
-
-/* Print bitmap B with TITLE to file F.  */
-static void
-print_bitmap (FILE *f, bitmap b, const char *title)
-{
-  unsigned int j;
-  bitmap_iterator bi;
-
-  fprintf (f, "%s:", title);
-  EXECUTE_IF_SET_IN_BITMAP (b, FIRST_PSEUDO_REGISTER, j, bi)
-    fprintf (f, " %d", j);
-  fprintf (f, "\n");
-}
-
-/* Print data used for splitting allocnos around calls to file F.  */
-static void
-print_ira_call_data (FILE *f)
-{
-  int i;
-  basic_block bb;
-
-  print_bitmap (f, regs_to_save_restore, "to save/restore") ;
-  for (i = 0; i < loop_referenced_regs_array_len; i++)
-    {
-      fprintf (f, "Loop %d -- ", i);
-      print_bitmap (f, loop_referenced_regs_array [i], "referenced");
-    }
-  FOR_EACH_BB (bb)
-    {
-      struct bb_info *bb_info;
-
-      bb_info = BB_INFO (bb);
-      fprintf (f, "BB %d (loop %d)\n", bb->index, bb->loop_father->num);
-      print_bitmap (f, bb_info->kill, "  kill") ;
-      print_bitmap (f, bb_info->saveloc, "  saveloc") ;
-      print_bitmap (f, bb_info->restoreloc, "  restoreloc") ;
-      print_bitmap (f, bb_info->savein, "  savein") ;
-      print_bitmap (f, bb_info->saveout, "  saveout") ;
-      print_bitmap (f, bb_info->restorein, "  restorein") ;
-      print_bitmap (f, bb_info->restoreout, "  restoreout") ;
-    }
-}
-
-/* Print data used for splitting allocnos around calls to STDERR.  */
-extern void
-debug_ira_call_data (void)
-{
-  print_ira_call_data (stderr);
-}
-
-/* Finish data used for splitting allocnos around calls.  */
-static void
-finish_ira_call_data (void)
-{
-  int i;
-
-  ira_free_bitmap (temp_bitmap2);
-  ira_free_bitmap (temp_bitmap);
-  ira_free_bitmap (regs_to_save_restore);
-  ira_free_bitmap (referenced_regs);
-  ira_free_bitmap (regs_live);
-  ira_free (reg_map);
-  for (i = 0; i < loop_referenced_regs_array_len; i++)
-    ira_free_bitmap (loop_referenced_regs_array [i]);
-  ira_free (loop_referenced_regs_array);
-  for (i = 0; i < n_blocks; i++)
-    {
-      struct bb_info *bb_info;
-
-      bb_info = BB_INFO_BY_INDEX (postorder [i]);
-      ira_free_bitmap (bb_info->restoreout);
-      ira_free_bitmap (bb_info->restorein);
-      ira_free_bitmap (bb_info->saveout);
-      ira_free_bitmap (bb_info->savein);
-      ira_free_bitmap (bb_info->restoreloc);
-      ira_free_bitmap (bb_info->saveloc);
-      ira_free_bitmap (bb_info->kill);
-    }
-  free_aux_for_blocks ();
-  ira_free_bitmap (current_all_blocks);
-  ira_free (postorder);
-}
-
-/* TRUE if insns and new registers are created.  */
-static int change_p;
-
-/* Record all regs that are set in any one insn.  Communication from
-   mark_reg_{store,clobber}.  */
-static VEC(rtx, heap) *regs_set;
-
-/* Handle the case where REG is set by the insn being scanned.  Store
-   a 1 in hard_regs_live or regs_live for this register.
-
-   REG might actually be something other than a register; if so, we do
-   nothing.
-
-   SETTER is 0 if this register was modified by an auto-increment
-   (i.e., a REG_INC note was found for it).  */
-static void
-mark_reg_store (rtx reg, const_rtx setter ATTRIBUTE_UNUSED,
-		void *data ATTRIBUTE_UNUSED)
-{
-  int regno;
-
-  if (GET_CODE (reg) == SUBREG)
-    reg = SUBREG_REG (reg);
-
-  if (! REG_P (reg))
-    return;
-
-  VEC_safe_push (rtx, heap, regs_set, reg);
-
-  regno = REGNO (reg);
-
-  if (regno >= FIRST_PSEUDO_REGISTER)
-    bitmap_set_bit (regs_live, regno);
-  else if (! TEST_HARD_REG_BIT (no_alloc_regs, regno))
-    {
-      int last = regno + hard_regno_nregs [regno] [GET_MODE (reg)];
-
-      while (regno < last)
-	{
-	  if (! TEST_HARD_REG_BIT (eliminable_regset, regno))
-	    SET_HARD_REG_BIT (hard_regs_live, regno);
-	  regno++;
-	}
-    }
-}
-
-/* Like mark_reg_store except notice just CLOBBERs; ignore SETs.  */
-static void
-mark_reg_clobber (rtx reg, const_rtx setter, void *data)
-{
-  if (GET_CODE (setter) == CLOBBER)
-    mark_reg_store (reg, setter, data);
-}
-
-/* Mark REG as being dead (following the insn being scanned now).
-   Store a 0 in hard_regs_live or regs_live for this register.  */
-static void
-mark_reg_death (rtx reg)
-{
-  int regno = REGNO (reg);
-
-  if (regno >= FIRST_PSEUDO_REGISTER)
-    bitmap_clear_bit (regs_live, regno);
-  else if (! TEST_HARD_REG_BIT (no_alloc_regs, regno))
-    {
-      int last = regno + hard_regno_nregs [regno] [GET_MODE (reg)];
-
-      while (regno < last)
-	{
-	  CLEAR_HARD_REG_BIT (hard_regs_live, regno);
-	  regno++;
-	}
-    }
-}
-
-/* The recursive function walks X and records all referenced registers
-   in REFERENCED_REGS.  */
-static void
-mark_referenced_regs (rtx x)
-{
-  enum rtx_code code;
-  const char *fmt;
-  int i, j;
-
-  if (x == NULL_RTX)
-    return;
-  code = GET_CODE (x);
-  if (code == SET)
-    mark_referenced_regs (SET_SRC (x));
-  if (code == SET || code == CLOBBER)
-    {
-      x = SET_DEST (x);
-      code = GET_CODE (x);
-      if ((code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
-	  || code == PC || code == CC0)
-	return;
-    }
-  if (code == MEM || code == SUBREG)
-    {
-      x = XEXP (x, 0);
-      code = GET_CODE (x);
-    }
-
-  if (code == REG)
-    {
-      int regno = REGNO (x);
-
-      bitmap_set_bit (referenced_regs, 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));
-    }
-}
-
-/* The function sets up REFERENCED_REGS for rtx X and all their
-   equivalences.  */
-static void
-mark_all_referenced_regs (rtx x)
-{
-  rtx list, note;
-  unsigned int j;
-  bitmap_iterator bi;
-
-  mark_referenced_regs (x);
-  bitmap_copy (temp_bitmap, referenced_regs);
-  bitmap_copy (temp_bitmap2, referenced_regs);
-  for (;;)
-    {
-      bitmap_clear (referenced_regs);
-      EXECUTE_IF_SET_IN_BITMAP (temp_bitmap2, FIRST_PSEUDO_REGISTER, j, bi)
-	if (j < (unsigned) ira_max_regno_before)
-	  for (list = reg_equiv_init [j];
-	       list != NULL_RTX;
-	       list = XEXP (list, 1))
-	    {
-	      note = find_reg_note (XEXP (list, 0), REG_EQUIV, NULL_RTX);
-	      
-	      if (note == NULL_RTX)
-		continue;
-	      
-	      mark_referenced_regs (XEXP (note, 0));
-	    }
-      bitmap_and_compl (temp_bitmap2, temp_bitmap, referenced_regs);
-      if (! bitmap_ior_into (temp_bitmap, referenced_regs))
-	break;
-    }
-  bitmap_copy (referenced_regs, temp_bitmap);
-}
-
-/* The function emits a new save/restore insn with pattern PATH before
-   (if BEFORE_P) or after INSN.  */
-static void
-insert_one_insn (rtx insn, int before_p, rtx pat)
-{
-  rtx new_insn;
-
-  change_p = TRUE;
-#ifdef HAVE_cc0
-  /* If INSN references CC0, put our insns in front of the insn that
-     sets CC0.  This is always safe, since the only way we could be
-     passed an insn that references CC0 is for a restore, and doing a
-     restore earlier isn't a problem.  We do, however, assume here
-     that CALL_INSNs don't reference CC0.  Guard against non-INSN's
-     like CODE_LABEL.  */
-
-  if ((NONJUMP_INSN_P (insn) || JUMP_P (insn))
-      && before_p && reg_referenced_p (cc0_rtx, PATTERN (insn)))
-    insn = PREV_INSN (insn);
-#endif
-
-  if (before_p)
-    {
-      new_insn = emit_insn_before (pat, insn);
-      if (insn == BB_HEAD (BLOCK_FOR_INSN (insn)))
-	BB_HEAD (BLOCK_FOR_INSN (insn)) = new_insn;
-    }
-  else
-    {
-      if (GET_CODE (insn) != CODE_LABEL)
-	new_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_insn = emit_insn_after (pat, NEXT_INSN (insn));
-	}
-      if (insn == BB_END (BLOCK_FOR_INSN (insn)))
-	BB_END (BLOCK_FOR_INSN (insn)) = new_insn;
-    }
-  if (ira_dump_file != NULL)
-    fprintf (ira_dump_file,
-	     "Generating save/restore insn %d:%d<-%d in bb %d\n",
-	     INSN_UID (new_insn), REGNO (SET_DEST (pat)),
-	     REGNO (SET_SRC (pat)), BLOCK_FOR_INSN (insn)->index);
-}
-
-/* The function creates a new register (if it is not created yet) and
-   returns it for allocno with REGNO.  */
-static rtx
-get_new_reg (unsigned int regno)
-{
-  rtx reg, newreg;
-
-  reg = regno_reg_rtx [regno];
-  if ((newreg = reg_map [regno]) == NULL_RTX)
-    {
-      newreg = gen_reg_rtx (GET_MODE (reg));
-      REG_USERVAR_P (newreg) = REG_USERVAR_P (reg);
-      REG_POINTER (newreg) = REG_POINTER (reg);
-      REG_ATTRS (newreg) = REG_ATTRS (reg);
-      reg_map [regno] = newreg;
-    }
-  return newreg;
-}
-
-/* Return move insn dest<-src.  */
-static rtx
-get_move_insn (rtx src, rtx dest) 
-{
-  rtx result;
-
-  start_sequence ();
-  emit_move_insn (src, dest);
-  result = get_insns ();
-  end_sequence ();
-  return result;
-}
-
-/* The function inserts save/restore code which can be placed in any
-   case inside the BB and caclulate local bb info (kill, saveloc,
-   restoreloc).  */
-static void
-put_save_restore_and_calculate_local_info (void)
-{
-  int i;
-  unsigned int j;
-  basic_block bb;
-  rtx insn, reg, newreg, pat;
-  bitmap_iterator bi;
-  bitmap reg_live_in, reg_live_out, saveloc, restoreloc, kill;
-
-  /* Make a vector that mark_reg_{store,clobber} will store in.  */
-  if (! regs_set)
-    regs_set = VEC_alloc (rtx, heap, 10);
-  FOR_EACH_BB (bb)
-    {
-      rtx first_insn, last_insn;
-      struct loop *loop;
-      struct bb_info *bb_info = BB_INFO (bb);
-
-      saveloc = bb_info->saveloc;
-      restoreloc = bb_info->restoreloc;
-      kill = bb_info->kill;
-      reg_live_in = DF_LR_IN (bb);
-      reg_live_out = DF_LR_OUT (bb);
-      REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_in);
-      AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
-      bitmap_copy (regs_live, reg_live_in);
-      first_insn = last_insn = NULL_RTX;
-      /* Scan the code of this basic block, noting which regs and hard
-	 regs are born or die.  */
-      FOR_BB_INSNS (bb, insn)
-	{
-	  rtx link;
-	  
-	  if (! INSN_P (insn))
-	    continue;
-	  
-	  if (first_insn == NULL_RTX)
-	    first_insn = insn;
-	  last_insn = insn;
-
-	  bitmap_clear (referenced_regs);
-	  mark_all_referenced_regs (insn);
-	  
-	  EXECUTE_IF_SET_IN_BITMAP (restoreloc, FIRST_PSEUDO_REGISTER, j, bi)
-	    if (bitmap_bit_p (referenced_regs, j))
-	      insert_one_insn (insn, TRUE,
-			       get_move_insn (regno_reg_rtx [j],
-					      get_new_reg (j)));
-	  
-	  bitmap_ior_into (kill, referenced_regs);
-	  bitmap_and_compl_into (restoreloc, referenced_regs);
-
-	  /* Check that regs_set is an empty set.  */
-	  gcc_assert (VEC_empty (rtx, regs_set));
-      
-	  /* Mark any regs clobbered by INSN as live, so they
-	     conflict with the inputs.  */
-	  note_stores (PATTERN (insn), mark_reg_clobber, NULL);
-	  
-	  /* Mark any regs dead after INSN as dead now.  */
-	  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-	    if (REG_NOTE_KIND (link) == REG_DEAD)
-	      mark_reg_death (XEXP (link, 0));
-	  
-	  if (CALL_P (insn) && ! find_reg_note (insn, REG_NORETURN, NULL))
-	    {
-	      EXECUTE_IF_SET_IN_BITMAP (regs_live, FIRST_PSEUDO_REGISTER,
-					j, bi)
-		if ((j >= (unsigned) ira_max_regno_before
-		     || (reg_equiv_const [j] == NULL_RTX
-			 && ! reg_equiv_invariant_p [j]))
-		    && reg_renumber [j] >= 0
-		    && ! hard_reg_not_in_set_p (reg_renumber [j],
-						GET_MODE (regno_reg_rtx [j]),
-						call_used_reg_set))
-		  {
-		    bitmap_set_bit (regs_to_save_restore, j);
-		    if (! bitmap_bit_p (restoreloc, j)
-			&& bitmap_bit_p (kill, j))
-		      {
-			for (i = 0; i < (int) VEC_length (rtx, regs_set); i++)
-			  if (REGNO (VEC_index (rtx, regs_set, i)) == j)
-			    break;
-			if (i < (int) VEC_length (rtx, regs_set))
-			  continue;
-			/* Insert save insn */
-			reg = regno_reg_rtx [j];
-			newreg = get_new_reg (j);
-			pat = get_move_insn (newreg, reg);
-			insert_one_insn (insn, TRUE, pat);
-		      }
-		    if (! bitmap_bit_p (kill, j))
-		      bitmap_set_bit (saveloc, j);
-		    bitmap_set_bit (restoreloc, j);
-		  }
-	    }
-	  
-	  /* Mark any regs set in INSN as live.  */
-	  note_stores (PATTERN (insn), mark_reg_store, NULL);
-	  
-#ifdef AUTO_INC_DEC
-	  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-	    if (REG_NOTE_KIND (link) == REG_INC)
-	      mark_reg_store (XEXP (link, 0), NULL_RTX, NULL);
-#endif
-	  
-	  /* Mark any regs set in INSN and then never used.  */
-	  while (! VEC_empty (rtx, regs_set))
-	    {
-	      rtx reg = VEC_pop (rtx, regs_set);
-	      rtx note = find_regno_note (insn, REG_UNUSED, REGNO (reg));
-
-	      if (note)
-		mark_reg_death (XEXP (note, 0));
-	    }
-	}
-      if (! flag_ira_move_spills)
-	{
-	  EXECUTE_IF_SET_IN_BITMAP (saveloc, FIRST_PSEUDO_REGISTER, j, bi)
-	    insert_one_insn (first_insn, TRUE,
-			     get_move_insn (get_new_reg (j),
-					    regno_reg_rtx [j]));
-	  EXECUTE_IF_SET_IN_BITMAP (restoreloc, FIRST_PSEUDO_REGISTER, j, bi)
-	    insert_one_insn (last_insn, JUMP_P (last_insn),
-			     get_move_insn (regno_reg_rtx [j],
-					    get_new_reg (j)));
-	}
-      for (loop = bb->loop_father; loop != NULL; loop = loop_outer (loop))
-	bitmap_ior_into (loop_referenced_regs_array [loop->num], kill);
-    }
-}
-
-
-
-/* The function used by the DF equation solver to propagate restore
-   info through block with BB_INDEX.  */
-static bool
-save_trans_fun (int bb_index)
-{
-  struct bb_info *bb_info = BB_INFO_BY_INDEX (bb_index);
-  bitmap in = bb_info->savein;
-  bitmap out = bb_info->saveout;
-  bitmap loc = bb_info->saveloc;
-  bitmap kill = bb_info->kill;
-
-  return bitmap_ior_and_compl (in, loc, out, kill);
-}
-
-/* The function used by the DF equation solver to set up save info
-   for a block BB without successors.  */
-static void
-save_con_fun_0 (basic_block bb)
-{
-  bitmap_clear (BB_INFO (bb)->saveout);
-}
-
-/* The function used by the DF equation solver to propagate save info
-   from successor to predecessor on edge E.  */
-static void
-save_con_fun_n (edge e)
-{
-  bitmap op1 = BB_INFO (e->src)->saveout;
-  bitmap op2 = BB_INFO (e->dest)->savein;
-
-  if (e->src->loop_depth > e->dest->loop_depth)
-    {
-      bitmap_and_into (op1, op2);
-      bitmap_and_compl_into
-	(op1, loop_referenced_regs_array [e->src->loop_father->num]);
-    }
-  else
-    bitmap_and_into (op1, op2);
-}
-
-/* The function calculates savein/saveout sets.  */
-static void
-calculate_save (void)
-{
-  basic_block bb;
-
-  /* Initialize relations to find maximal solution.  */
-  FOR_ALL_BB (bb)
-    {
-      bitmap_copy (BB_INFO (bb)->savein, regs_to_save_restore);
-      bitmap_copy (BB_INFO (bb)->saveout, regs_to_save_restore);
-    }
-  df_simple_dataflow (DF_BACKWARD, NULL, save_con_fun_0, save_con_fun_n,
-		      save_trans_fun, current_all_blocks,
-		      df_get_postorder (DF_BACKWARD),
-		      df_get_n_blocks (DF_BACKWARD));
-}
-
-
-
-/* The function used by the DF equation solver to propagate restore
-   info through block with BB_INDEX.  */
-static bool
-restore_trans_fun (int bb_index)
-{
-  struct bb_info *bb_info = BB_INFO_BY_INDEX (bb_index);
-  bitmap in = bb_info->restorein;
-  bitmap out = bb_info->restoreout;
-  bitmap loc = bb_info->restoreloc;
-  bitmap kill = bb_info->kill;
-
-  return bitmap_ior_and_compl (out, loc, in, kill);
-}
-
-/* The function used by the DF equation solver to set up restore info
-   for a block BB without predecessors.  */
-static void
-restore_con_fun_0 (basic_block bb)
-{
-  bitmap_clear (BB_INFO (bb)->restorein);
-}
-
-/* The function used by the DF equation solver to propagate restore
-   info from predecessor to successor on edge E.  */
-static void
-restore_con_fun_n (edge e)
-{
-  bitmap op1 = BB_INFO (e->dest)->restorein;
-  bitmap op2 = BB_INFO (e->src)->restoreout;
-
-  if (e->dest->loop_depth > e->src->loop_depth)
-    {
-      bitmap_and_into (op1, op2);
-      bitmap_and_compl_into
-	(op1, loop_referenced_regs_array [e->dest->loop_father->num]);
-    }
-  else
-    bitmap_and_into (op1, op2);
-}
-
-/* The function calculates restorein/restoreout sets.  */
-static void
-calculate_restore (void)
-{
-  basic_block bb;
-
-  /* Initialize relations to find maximal solution.  */
-  FOR_ALL_BB (bb)
-    {
-      bitmap_copy (BB_INFO (bb)->restoreout, regs_to_save_restore);
-      bitmap_copy (BB_INFO (bb)->restorein, regs_to_save_restore);
-    }
-  df_simple_dataflow (DF_FORWARD, NULL, restore_con_fun_0, restore_con_fun_n,
-		      restore_trans_fun, current_all_blocks,
-		      df_get_postorder (DF_FORWARD),
-		      df_get_n_blocks (DF_FORWARD));
-}
-
-
-
-/* The function put save/restores insn according to the calculated
-   equation.  The function even puts the insns inside blocks to
-   increase live range of allocnos which will be in memory.  */
-static void
-put_save_restore (void)
-{
-  basic_block bb;
-  edge e;
-  edge_iterator ei;
-  unsigned int j;
-  bitmap_iterator bi;
-  rtx pat;
-  int first_p;
-  bitmap save_at_end, restore_at_start, progress;
-
-  save_at_end = ira_allocate_bitmap ();
-  restore_at_start = ira_allocate_bitmap ();
-  progress = ira_allocate_bitmap ();
-  FOR_EACH_BB (bb)
-    {
-      struct bb_info *bb_info = BB_INFO (bb);
-      bitmap kill = bb_info->kill;
-      bitmap restoreout = bb_info->restoreout;
-      bitmap saveout = bb_info->saveout;
-      bitmap savein = bb_info->savein;
-      bitmap restorein = bb_info->restorein;
-      bitmap live_at_start;
-      rtx bb_head, bb_end;
-      rtx insn, next_insn;
-
-      for (bb_head = BB_HEAD (bb);
-	   bb_head != BB_END (bb) && ! INSN_P (bb_head);
-	   bb_head = NEXT_INSN (bb_head))
-	;
-      for (bb_end = BB_END (bb);
-	   bb_end != BB_HEAD (bb) && ! INSN_P (bb_end);
-	   bb_end = PREV_INSN (bb_end))
-	;
-
-      bitmap_clear (save_at_end);
-      first_p = TRUE;
-      FOR_EACH_EDGE (e, ei, bb->succs)
-	{
-	  bitmap savein = BB_INFO (e->dest)->savein;
-
-	  live_at_start = DF_LR_IN (e->dest);
-	  /* (savein - restoreout) ^ (kill U ! saveout) ==
-              ^ live_at_start ==
-	     (savein - restoreout) ^ live_at_start ^ kill
-             U (savein - restoreout) ^ live_at_start - saveout
-	  */
-	  bitmap_and_compl (temp_bitmap2, savein, restoreout);
-	  bitmap_and_into (temp_bitmap2, live_at_start);
-	  bitmap_and (temp_bitmap, temp_bitmap2, kill);
-	  bitmap_ior_and_compl_into (temp_bitmap, temp_bitmap2, saveout);
-	  if (first_p)
-	    {
-	      bitmap_copy (save_at_end, temp_bitmap);
-	      first_p = FALSE;
-	    }
-	  else
-	    bitmap_and_into (save_at_end, temp_bitmap);
-	}
-
-      bitmap_copy (progress, save_at_end);
-      for (insn = BB_END (bb);
-	   insn != PREV_INSN (BB_HEAD (bb));
-	   insn = next_insn)
-	{
-	  next_insn = PREV_INSN (insn);
-	  if (! INSN_P (insn))
-	    continue;
-	  bitmap_clear (referenced_regs);
-	  mark_all_referenced_regs (insn);
-	  EXECUTE_IF_SET_IN_BITMAP (referenced_regs, FIRST_PSEUDO_REGISTER,
-				    j, bi)
-	    if (bitmap_bit_p (progress, j))
-	      {
-		pat = get_move_insn (get_new_reg (j), regno_reg_rtx [j]);
-		insert_one_insn (insn, JUMP_P (insn), pat);
-		bitmap_clear_bit (progress, j);
-	      }
-	}
-      /* When we don't move info inside the loop, progress can
-	 be not empty here.  */
-      EXECUTE_IF_SET_IN_BITMAP (progress, FIRST_PSEUDO_REGISTER, j, bi)
-	{
-	  pat = get_move_insn (get_new_reg (j), regno_reg_rtx [j]);
-	  insert_one_insn (bb_head, TRUE, pat);
-	}
-
-      bitmap_clear (restore_at_start);
-      first_p = TRUE;
-      live_at_start = DF_LR_IN (bb);
-      FOR_EACH_EDGE (e, ei, bb->preds)
-	{
-	  bitmap restoreout = BB_INFO (e->src)->restoreout;
-
-	  /* (restoreout - savein) ^ (kill U ! restorein)
-              ^ live_at_start ==
-	     (((restoreout - savein) ^ live_at_start) ^ kill
-              U ((restoreout - savein) ^ live_at_start) - restorein)
-	  */
-	  bitmap_and_compl (temp_bitmap2, restoreout, savein);
-	  bitmap_and_into (temp_bitmap2, live_at_start);
-	  bitmap_and (temp_bitmap, temp_bitmap2, kill);
-	  bitmap_ior_and_compl_into (temp_bitmap, temp_bitmap2, restorein);
-	  if (first_p)
-	    {
-	      bitmap_copy (restore_at_start, temp_bitmap);
-	      first_p = FALSE;
-	    }
-	  else
-	    bitmap_and_into (restore_at_start, temp_bitmap);
-	}
-	    
-      bitmap_copy (progress, restore_at_start);
-      for (insn = BB_HEAD (bb);
-	   insn != NEXT_INSN (BB_END (bb));
-	   insn = next_insn)
-	{
-	  next_insn = NEXT_INSN (insn);
-	  if (! INSN_P (insn))
-	    continue;
-	  bitmap_clear (referenced_regs);
-	  mark_all_referenced_regs (insn);
-	  EXECUTE_IF_SET_IN_BITMAP (referenced_regs, FIRST_PSEUDO_REGISTER,
-				    j, bi)
-	    if (bitmap_bit_p (progress, j))
-	      {
-		pat = get_move_insn (regno_reg_rtx [j], get_new_reg (j));
-		insert_one_insn (insn, TRUE, pat);
-		bitmap_clear_bit (progress, j);
-	      }
-	}
-      /* When we don't move info inside the loop, progress can
-	 be not empty here.  */
-      EXECUTE_IF_SET_IN_BITMAP (progress, FIRST_PSEUDO_REGISTER, j, bi)
-	{
-	  pat = get_move_insn (regno_reg_rtx [j], get_new_reg (j));
-	  insert_one_insn (bb_end, JUMP_P (bb_end), pat);
-	}
-	
-      FOR_EACH_EDGE (e, ei, bb->succs)
-	{
-	  bitmap savein = BB_INFO (e->dest)->savein;
-
-	  live_at_start = DF_LR_IN (e->dest);
-	  EXECUTE_IF_SET_IN_BITMAP (savein, FIRST_PSEUDO_REGISTER, j, bi)
-	    if (! bitmap_bit_p (restoreout, j)
-		&& (bitmap_bit_p (kill, j)
-		    || ! bitmap_bit_p (saveout, j))
-		&& ! bitmap_bit_p (save_at_end, j)
-		&& bitmap_bit_p (live_at_start, j))
-	      {
-		pat = get_move_insn (get_new_reg (j),
-				   regno_reg_rtx [j]);
-		insert_insn_on_edge (pat, e);
-		change_p = TRUE;
-		if (ira_dump_file != NULL)
-		  fprintf
-		    (ira_dump_file,
-		     "Generating save/restore insn %d<-%d on edge %d->%d\n",
-		     REGNO (SET_DEST (pat)), REGNO (SET_SRC (pat)),
-		     e->src->index, e->dest->index);
-	      }
-	}
-
-      live_at_start = DF_LR_IN (bb);
-      FOR_EACH_EDGE (e, ei, bb->preds)
-	{
-	  bitmap restoreout = BB_INFO (e->src)->restoreout;
-
-	  EXECUTE_IF_SET_IN_BITMAP (restoreout, FIRST_PSEUDO_REGISTER, j, bi)
-	    if (! bitmap_bit_p (savein, j)
-		&& (bitmap_bit_p (kill, j)
-		    || ! bitmap_bit_p (restorein, j))
-		&& ! bitmap_bit_p (restore_at_start, j)
-		&& bitmap_bit_p (live_at_start, j))
-	      {
-		pat = get_move_insn (regno_reg_rtx [j],
-				   get_new_reg (j));
-		insert_insn_on_edge (pat, e);
-		change_p = TRUE;
-		if (ira_dump_file != NULL)
-		  fprintf
-		    (ira_dump_file,
-		     "Generating save/restore insn %d<-%d on edge %d->%d\n",
-		     REGNO (SET_DEST (pat)), REGNO (SET_SRC (pat)),
-		     e->src->index, e->dest->index);
-	      }
-	}
-    }
-  ira_free_bitmap (progress);
-  ira_free_bitmap (save_at_end);
-  ira_free_bitmap (restore_at_start);
-}
-
-/* The function splits allocnos living through calls and assigned to a
-   call used register.  If FLAG_IRA_MOVE_SPILLS, the function moves
-   save/restore insns to correspondingly to the top and bottom of the
-   CFG but not moving them to more frequently executed places.  */
-int
-split_around_calls (void)
-{
-  change_p = FALSE;
-  init_ira_call_data ();
-  put_save_restore_and_calculate_local_info ();
-  if (flag_ira_move_spills)
-    {
-      calculate_save ();
-      calculate_restore ();
-      put_save_restore ();
-    }
-  finish_ira_call_data ();
-  fixup_abnormal_edges ();
-  commit_edge_insertions ();
-  return change_p;
-}
-
-
-
-/* The function returns regno of living through call allocno which is
-   result of splitting allocno with ORIGINAL_REGNO.  If there is no
-   such regno, the function returns -1.  */
-int
-get_around_calls_regno (int original_regno)
-{
-  allocno_t a, another_a;
-  copy_t cp, next_cp;
-
-  if (original_regno >= ira_max_regno_call_before)
-    return -1;
-  a = regno_allocno_map [original_regno];
-  for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp)
-    {
-      if (cp->first == a)
-	{
-	  another_a = cp->second;
-	  next_cp = cp->next_first_allocno_copy;
-	}
-      else
-	{
-	  another_a = cp->first;
-	  next_cp = cp->next_second_allocno_copy;
-	}
-      if (cp->move_insn == NULL_RTX)
-	continue;
-      if (ALLOCNO_REGNO (another_a) >= ira_max_regno_call_before)
-	return ALLOCNO_REGNO (another_a);
-    }
-  return -1;
-}
Index: ira-lives.c
===================================================================
--- ira-lives.c	(revision 0)
+++ ira-lives.c	(revision 0)
@@ -0,0 +1,891 @@
+/* IRA processing allocno lives.
+   Copyright (C) 2006, 2007
+   Free Software Foundation, Inc.
+   Contributed by Vladimir Makarov <vmakarov@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "regs.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "target.h"
+#include "flags.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "toplev.h"
+#include "params.h"
+#include "df.h"
+#include "ira-int.h"
+
+/* The file contains code is analogous to one in global but the code
+   works on the allocno basis.  */
+
+static void set_allocno_live (allocno_t);
+static void clear_allocno_live (allocno_t);
+static void mark_reg_store (rtx, const_rtx, void *);
+static void mark_reg_clobber (rtx, const_rtx, void *);
+static void mark_reg_conflicts (rtx);
+static void mark_reg_death (rtx);
+static enum reg_class single_reg_class (const char *, rtx op, rtx);
+static enum reg_class single_reg_operand_class (int);
+static void process_single_reg_class_operands (int);
+static void process_bb_node_lives (loop_tree_node_t);
+
+/* Program points are enumerated by number from range
+   0..MAX_POINT-1.  */
+int max_point;
+
+/* Arrays of size MAX_POINT mapping a program point to the allocno
+   live ranges with given start/finish point.  */
+allocno_live_range_t *start_point_ranges, *finish_point_ranges;
+
+/* Number of the current program point.  */
+static int curr_point;
+
+/* Number of ints required to hold allocnos_num bits.  */
+int allocno_set_words;
+
+/* Set, clear or test bit number I in `allocnos_live',
+   a bit vector indexed by allocno number.  */
+#define SET_ALLOCNO_LIVE(I) SET_ALLOCNO_SET_BIT (allocnos_live, I)
+#define CLEAR_ALLOCNO_LIVE(I) CLEAR_ALLOCNO_SET_BIT (allocnos_live, I)
+#define TEST_ALLOCNO_LIVE(I) TEST_ALLOCNO_SET_BIT (allocnos_live, I)
+
+/* Bit mask for allocnos live at current point in the scan.  */
+static INT_TYPE *allocnos_live;
+
+/* The same as previous but as bitmap.  */
+static bitmap allocnos_live_bitmap;
+
+/* Set of hard regs (except eliminable ones) currently live (during
+   scan of all insns).  */
+static HARD_REG_SET hard_regs_live;
+
+/* Loop tree node corresponding to the current basic block.  */
+static loop_tree_node_t curr_bb_node;
+
+/* The function processing birth of register REGNO.  It updates living
+   hard regs and conflict hard regs for living allocnos or starts a
+   new live range for allocno corresponding to REGNO.  */
+static void
+make_regno_born (int regno)
+{
+  int i;
+  allocno_t a;
+  allocno_live_range_t p;
+
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      SET_HARD_REG_BIT (hard_regs_live, regno);
+      EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
+        {
+	  SET_HARD_REG_BIT (ALLOCNO_CONFLICT_HARD_REGS (allocnos [i]), regno);
+	  SET_HARD_REG_BIT (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (allocnos [i]),
+			    regno);
+	});
+      return;
+    }
+  a = ira_curr_regno_allocno_map [regno];
+  if (a == NULL)
+    return;
+  if ((p = ALLOCNO_LIVE_RANGES (a)) == NULL
+      || (p->finish != curr_point && p->finish + 1 != curr_point))
+    ALLOCNO_LIVE_RANGES (a)
+      = create_allocno_live_range (a, curr_point, -1, ALLOCNO_LIVE_RANGES (a));
+}
+
+/* The function processing death of register REGNO.  It updates live
+   hard regs or finish the current live range for allocno
+   corresponding to REGNO.  */
+static void
+make_regno_dead (int regno)
+{
+  allocno_t a;
+  allocno_live_range_t p;
+
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      CLEAR_HARD_REG_BIT (hard_regs_live, regno);
+      return;
+    }
+  a = ira_curr_regno_allocno_map [regno];
+  if (a == NULL)
+    return;
+  p = ALLOCNO_LIVE_RANGES (a);
+  ira_assert (p != NULL);
+  p->finish = curr_point;
+}
+
+/* The function processing birth and, right after then, death of
+   register REGNO.  */
+static void
+make_regno_born_and_died (int regno)
+{
+  make_regno_born (regno);
+  make_regno_dead (regno);
+}
+
+/* The current pressure for the current basic block.  */
+static int curr_reg_pressure [N_REG_CLASSES];
+
+/* The function marks allocno A as currently living.  */
+static void
+set_allocno_live (allocno_t a)
+{
+  enum reg_class cover_class;
+
+  if (TEST_ALLOCNO_LIVE (ALLOCNO_NUM (a)))
+    return;
+  SET_ALLOCNO_LIVE (ALLOCNO_NUM (a));
+  IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), hard_regs_live);
+  IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), hard_regs_live);
+  bitmap_set_bit (allocnos_live_bitmap, ALLOCNO_NUM (a));
+  cover_class = ALLOCNO_COVER_CLASS (a);
+  curr_reg_pressure [cover_class]
+    += reg_class_nregs [cover_class] [ALLOCNO_MODE (a)];
+  if (curr_bb_node->reg_pressure [cover_class]
+      < curr_reg_pressure [cover_class])
+    curr_bb_node->reg_pressure [cover_class] = curr_reg_pressure [cover_class];
+}
+
+/* The function marks allocno A as currently not living.  */
+static void
+clear_allocno_live (allocno_t a)
+{
+  enum reg_class cover_class;
+
+  if (bitmap_bit_p (allocnos_live_bitmap, ALLOCNO_NUM (a)))
+    {
+      cover_class = ALLOCNO_COVER_CLASS (a);
+      curr_reg_pressure [cover_class]
+	-= reg_class_nregs [cover_class] [ALLOCNO_MODE (a)];
+      ira_assert (curr_reg_pressure [cover_class] >= 0);
+    }
+  CLEAR_ALLOCNO_LIVE (ALLOCNO_NUM (a));
+  bitmap_clear_bit (allocnos_live_bitmap, ALLOCNO_NUM (a));
+}
+
+/* Record all regs that are set in any one insn.  Communication from
+   mark_reg_{store,clobber}.  */
+static VEC(rtx, heap) *regs_set;
+
+/* Handle the case where REG is set by the insn being scanned, during
+   the scan to accumulate conflicts.  Store a 1 in hard_regs_live or
+   allocnos_live for this register or the
+   corresponding allocno, record how many consecutive hardware
+   registers it actually needs, and record a conflict with all other
+   reg allocnos already live.
+
+   Note that even if REG does not remain alive after this insn, we
+   must mark it here as live, to ensure a conflict between REG and any
+   other reg allocnos set in this insn that really do live.  This is
+   because those other allocnos could be considered after this.
+
+   REG might actually be something other than a register; if so, we do
+   nothing.
+
+   SETTER is 0 if this register was modified by an auto-increment
+   (i.e., a REG_INC note was found for it).  */
+static void
+mark_reg_store (rtx reg, const_rtx setter ATTRIBUTE_UNUSED,
+		void *data ATTRIBUTE_UNUSED)
+{
+  int regno;
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (! REG_P (reg))
+    return;
+
+  VEC_safe_push (rtx, heap, regs_set, reg);
+
+  regno = REGNO (reg);
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      allocno_t a = ira_curr_regno_allocno_map [regno];
+
+      ira_assert (a != NULL || REG_N_REFS (regno) == 0);
+      if (a != NULL)
+	{
+	  if (bitmap_bit_p (allocnos_live_bitmap, ALLOCNO_NUM (a)))
+	    return;
+	  set_allocno_live (a);
+	}
+      make_regno_born (regno);
+    }
+  else if (! TEST_HARD_REG_BIT (no_alloc_regs, regno))
+    {
+      int last = regno + hard_regno_nregs [regno] [GET_MODE (reg)];
+      enum reg_class cover_class;
+
+      while (regno < last)
+	{
+	  if (! TEST_HARD_REG_BIT (hard_regs_live, regno)
+	      && ! TEST_HARD_REG_BIT (eliminable_regset, regno))
+	    {
+	      cover_class = class_translate [REGNO_REG_CLASS (regno)];
+	      curr_reg_pressure [cover_class]++;
+	      make_regno_born (regno);
+	      if (curr_bb_node->reg_pressure [cover_class]
+		  < curr_reg_pressure [cover_class])
+		curr_bb_node->reg_pressure [cover_class]
+		  = curr_reg_pressure [cover_class];
+	    }
+	  regno++;
+	}
+    }
+}
+
+/* Like mark_reg_store except notice just CLOBBERs; ignore SETs.  */
+static void
+mark_reg_clobber (rtx reg, const_rtx setter, void *data)
+{
+  if (GET_CODE (setter) == CLOBBER)
+    mark_reg_store (reg, setter, data);
+}
+
+/* Record that REG (or the corresponding allocno) has conflicts with
+   all the allocno currently live.  Do not mark REG (or the allocno)
+   itself as live.  */
+static void
+mark_reg_conflicts (rtx reg)
+{
+  int regno;
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (! REG_P (reg))
+    return;
+
+  regno = REGNO (reg);
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    make_regno_born_and_died (regno);
+  else if (! TEST_HARD_REG_BIT (no_alloc_regs, regno))
+    {
+      int last = regno + hard_regno_nregs [regno] [GET_MODE (reg)];
+
+      while (regno < last)
+	{
+	  make_regno_born_and_died (regno);
+	  regno++;
+	}
+    }
+}
+
+/* Mark REG (or the corresponding allocno) as being dead (following
+   the insn being scanned now).  Store a 0 in hard_regs_live or
+   allocnos_live for this register.  */
+static void
+mark_reg_death (rtx reg)
+{
+  int regno = REGNO (reg);
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      allocno_t a = ira_curr_regno_allocno_map [regno];
+
+      ira_assert (a != NULL || REG_N_REFS (regno) == 0);
+      if (a != NULL)
+	{
+	  if (! bitmap_bit_p (allocnos_live_bitmap, ALLOCNO_NUM (a)))
+	    return;
+	  clear_allocno_live (a);
+	}
+      make_regno_dead (regno);
+    }
+  else if (! TEST_HARD_REG_BIT (no_alloc_regs, regno))
+    {
+      int last = regno + hard_regno_nregs [regno] [GET_MODE (reg)];
+      enum reg_class cover_class;
+
+      while (regno < last)
+	{
+	  if (TEST_HARD_REG_BIT (hard_regs_live, regno))
+	    {
+	      cover_class = class_translate [REGNO_REG_CLASS (regno)];
+	      curr_reg_pressure [cover_class]--;
+	      ira_assert (curr_reg_pressure [cover_class] >= 0);
+	      make_regno_dead (regno);
+	    }
+	  regno++;
+	}
+    }
+}
+
+/* The function checks that CONSTRAINTS permits to use only one hard
+   register.  If it is so, the function returns the class of the hard
+   register.  Otherwise it returns NO_REGS.
+
+   EQUIV_COSNT ??? */
+static enum reg_class
+single_reg_class (const char *constraints, rtx op, rtx equiv_const)
+{
+  int ignore_p;
+  enum reg_class cl, next_cl;
+  int c;
+
+  cl = NO_REGS;
+  for (ignore_p = FALSE;
+       (c = *constraints);
+       constraints += CONSTRAINT_LEN (c, constraints))
+    if (c == '#')
+      ignore_p = TRUE;
+    else if (c == ',')
+      ignore_p = FALSE;
+    else if (! ignore_p)
+      switch (c)
+	{
+	case ' ':
+	case '\t':
+	case '=':
+	case '+':
+	case '*':
+	case '&':
+	case '%':
+	case '!':
+	case '?':
+	  break;
+	case 'i':
+	  if (CONSTANT_P (op)
+	      || (equiv_const != NULL_RTX && CONSTANT_P (equiv_const)))
+	    return NO_REGS;
+	  break;
+
+	case 'n':
+	  if (GET_CODE (op) == CONST_INT
+	      || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
+	      || (equiv_const != NULL_RTX
+		  && (GET_CODE (equiv_const) == CONST_INT
+		      || (GET_CODE (equiv_const) == CONST_DOUBLE
+			  && GET_MODE (equiv_const) == VOIDmode))))
+	    return NO_REGS;
+	  break;
+	  
+	case 's':
+	  if ((CONSTANT_P (op) && GET_CODE (op) != CONST_INT
+	       && (GET_CODE (op) != CONST_DOUBLE || GET_MODE (op) != VOIDmode))
+	      || (equiv_const != NULL_RTX
+		  && CONSTANT_P (equiv_const)
+		  && GET_CODE (equiv_const) != CONST_INT
+		  && (GET_CODE (equiv_const) != CONST_DOUBLE
+		      || GET_MODE (equiv_const) != VOIDmode)))
+	    return NO_REGS;
+	  break;
+	  
+	case 'I':
+	case 'J':
+	case 'K':
+	case 'L':
+	case 'M':
+	case 'N':
+	case 'O':
+	case 'P':
+	  if ((GET_CODE (op) == CONST_INT
+	       && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, constraints))
+	      || (equiv_const != NULL_RTX
+		  && GET_CODE (equiv_const) == CONST_INT
+		  && CONST_OK_FOR_CONSTRAINT_P (INTVAL (equiv_const),
+						c, constraints)))
+	    return NO_REGS;
+	  break;
+	  
+	case 'E':
+	case 'F':
+	  if (GET_CODE (op) == CONST_DOUBLE
+	      || (GET_CODE (op) == CONST_VECTOR
+		  && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT)
+	      || (equiv_const != NULL_RTX
+		  && (GET_CODE (equiv_const) == CONST_DOUBLE
+		      || (GET_CODE (equiv_const) == CONST_VECTOR
+			  && (GET_MODE_CLASS (GET_MODE (equiv_const))
+			      == MODE_VECTOR_FLOAT)))))
+	    return NO_REGS;
+	  break;
+	  
+	case 'G':
+	case 'H':
+	  if ((GET_CODE (op) == CONST_DOUBLE
+	       && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, constraints))
+	      || (equiv_const != NULL_RTX
+		  && GET_CODE (equiv_const) == CONST_DOUBLE
+		  && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (equiv_const,
+						       c, constraints)))
+	    return NO_REGS;
+	  /* ??? what about memory */
+	case 'r':
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+	case 'h': case 'j': case 'k': case 'l':
+	case 'q': case 't': case 'u':
+	case 'v': case 'w': case 'x': case 'y': case 'z':
+	case 'A': case 'B': case 'C': case 'D':
+	case 'Q': case 'R': case 'S': case 'T': case 'U':
+	case 'W': case 'Y': case 'Z':
+	  next_cl = (c == 'r'
+		     ? GENERAL_REGS
+		     : REG_CLASS_FROM_CONSTRAINT (c, constraints));
+	  if ((cl != NO_REGS && next_cl != cl)
+	      || available_class_regs [next_cl] > 1)
+	    return NO_REGS;
+	  cl = next_cl;
+	  break;
+	  
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+	  next_cl
+	    = single_reg_class (recog_data.constraints [c - '0'],
+				recog_data.operand [c - '0'], NULL_RTX);
+	  if ((cl != NO_REGS && next_cl != cl) || next_cl == NO_REGS
+	      || available_class_regs [next_cl] > 1)
+	    return NO_REGS;
+	  cl = next_cl;
+	  break;
+	  
+	default:
+	  return NO_REGS;
+	}
+  return cl;
+}
+
+/* The function checks that operand OP_NUM of the current insn can use
+   only one hard register.  If it is so, the function returns the
+   class of the hard register.  Otherwise it returns NO_REGS.  */
+static enum reg_class
+single_reg_operand_class (int op_num)
+{
+  if (op_num < 0 || recog_data.n_alternatives == 0)
+    return NO_REGS;
+  return single_reg_class (recog_data.constraints [op_num],
+			   recog_data.operand [op_num], NULL_RTX);
+}
+
+/* The function processes input (if IN_P) or output operands to find
+   allocno which can use only one hard register and makes other
+   currently living reg allocnos conflicting with the hard register.  */
+static void
+process_single_reg_class_operands (int in_p)
+{
+  int i, regno, px, cost;
+  enum reg_class cl, cover_class;
+  rtx operand;
+  allocno_t operand_a, a;
+
+  for (i = 0; i < recog_data.n_operands; i++)
+    {
+      operand = recog_data.operand [i];
+      if (in_p && recog_data.operand_type [i] != OP_IN
+	  && recog_data.operand_type [i] != OP_INOUT)
+	continue;
+      if (! in_p && recog_data.operand_type [i] != OP_OUT
+	  && recog_data.operand_type [i] != OP_INOUT)
+	continue;
+      cl = single_reg_operand_class (i);
+      if (cl == NO_REGS)
+	continue;
+
+      operand_a = NULL;
+
+      if (GET_CODE (operand) == SUBREG)
+	operand = SUBREG_REG (operand);
+      
+      if (REG_P (operand)
+	  && (regno = REGNO (operand)) >= FIRST_PSEUDO_REGISTER)
+	{
+	  enum machine_mode mode;
+	  enum reg_class cover_class;
+
+	  operand_a = ira_curr_regno_allocno_map [regno];
+	  mode = ALLOCNO_MODE (operand_a);
+	  cover_class = ALLOCNO_MODE (operand_a);
+	  if (class_subset_p [cl] [cover_class]
+	      && (reg_class_size [cl]
+		  <= (unsigned) CLASS_MAX_NREGS (cl, mode)))
+	    {
+	      cost = (in_p
+		      ? register_move_cost [mode] [cover_class] [cl]
+		      : register_move_cost [mode] [cl] [cover_class]);
+	      ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a)
+		[class_hard_reg_index [cover_class] [class_hard_regs [cl] [0]]]
+		-= cost;
+	    }
+	}
+
+      EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, px,
+        {
+	  a = allocnos [px];
+	  cover_class = ALLOCNO_COVER_CLASS (a);
+	  if (a != operand_a)
+	    {
+	      /* We could increase costs of A instead of making it
+		 conflicting with the hard register.  But it works worse
+		 because it will be spilled in reload in anyway.  */
+	      IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a),
+				reg_class_contents [cl]);
+	      IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a),
+				reg_class_contents [cl]);
+	    }
+	});
+    }
+}
+
+/* The function processes insns of the basic block given by its
+   LOOP_TREE_NODE to update allocno conflict table.  */
+static void
+process_bb_node_lives (loop_tree_node_t loop_tree_node)
+{
+  int i, index;
+  unsigned int j;
+  basic_block bb;
+  rtx insn;
+  edge e;
+  edge_iterator ei;
+  bitmap_iterator bi;
+  bitmap reg_live_in;
+  int px = 0;
+
+  bb = loop_tree_node->bb;
+  if (bb != NULL)
+    {
+      for (i = 0; i < reg_class_cover_size; i++)
+	curr_reg_pressure [reg_class_cover [i]] = 0;
+      curr_bb_node = loop_tree_node;
+      reg_live_in = DF_LR_IN (bb);
+      memset (allocnos_live, 0, allocno_set_words * sizeof (INT_TYPE));
+      REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_in);
+      AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+	if (TEST_HARD_REG_BIT (hard_regs_live, i))
+	  {
+	    enum reg_class cover_class;
+	    
+	    cover_class = class_translate [REGNO_REG_CLASS (i)];
+	    curr_reg_pressure [cover_class]++;
+	    if (curr_bb_node->reg_pressure [cover_class]
+		< curr_reg_pressure [cover_class])
+	      curr_bb_node->reg_pressure [cover_class]
+		= curr_reg_pressure [cover_class];
+	  }
+      bitmap_clear (allocnos_live_bitmap);
+      EXECUTE_IF_SET_IN_BITMAP (reg_live_in, FIRST_PSEUDO_REGISTER, j, bi)
+	{
+	  allocno_t a = ira_curr_regno_allocno_map [j];
+	  
+	  ira_assert (a != NULL || REG_N_REFS (j) == 0);
+	  if (a == NULL)
+	    continue;
+	  ira_assert (! bitmap_bit_p (allocnos_live_bitmap, ALLOCNO_NUM (a)));
+	  set_allocno_live (a);
+	  make_regno_born (j);
+	}
+      
+#ifdef EH_RETURN_DATA_REGNO
+      if (bb_has_eh_pred (bb))
+	{
+	  for (j = 0; ; ++j)
+	    {
+	      unsigned int regno = EH_RETURN_DATA_REGNO (j);
+	      
+	      if (regno == INVALID_REGNUM)
+		break;
+	      make_regno_born_and_died (regno);
+	    }
+	}
+#endif
+      
+      /* Reg allocnos can't go in stack regs at the start of a basic block
+	 that is reached by an abnormal edge. Likewise for call
+	 clobbered regs, because caller-save, fixup_abnormal_edges and
+	 possibly the table driven EH machinery are not quite ready to
+	 handle such reg allocnos live across such edges.  */
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	if (e->flags & EDGE_ABNORMAL)
+	  break;
+      
+      if (e != NULL)
+	{
+#ifdef STACK_REGS
+	  EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, px,
+	    {
+	      ALLOCNO_NO_STACK_REG_P (allocnos [px]) = TRUE;
+	      ALLOCNO_TOTAL_NO_STACK_REG_P (allocnos [px]) = TRUE;
+	    });
+	  for (px = FIRST_STACK_REG; px <= LAST_STACK_REG; px++)
+	    make_regno_born_and_died (px);
+#endif
+	  /* No need to record conflicts for call clobbered regs if we
+	     have nonlocal labels around, as we don't ever try to
+	     allocate such regs in this case.  */
+	  if (! current_function_has_nonlocal_label)
+	    for (px = 0; px < FIRST_PSEUDO_REGISTER; px++)
+	      if (call_used_regs [px])
+		make_regno_born_and_died (px);
+	}
+  
+      /* Scan the code of this basic block, noting which allocnos and
+	 hard regs are born or die.  When one is born, record a
+	 conflict with all others currently live.  */
+      FOR_BB_INSNS (bb, insn)
+	{
+	  rtx link;
+	  
+	  if (! INSN_P (insn))
+	    continue;
+	  
+	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+	    fprintf (ira_dump_file, "   Insn %u(l%d): point = %d\n",
+		     INSN_UID (insn), loop_tree_node->father->loop->num,
+		     curr_point);
+
+	  /* Check regs_set is an empty set.  */
+	  gcc_assert (VEC_empty (rtx, regs_set));
+      
+	  /* Mark any allocnos clobbered by INSN as live, so they
+	     conflict with the inputs.  */
+	  note_stores (PATTERN (insn), mark_reg_clobber, NULL);
+	  
+	  extract_insn (insn);
+	  process_single_reg_class_operands (TRUE);
+	  
+	  /* Mark any allocnos dead after INSN as dead now.  */
+	  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+	    if (REG_NOTE_KIND (link) == REG_DEAD)
+	      mark_reg_death (XEXP (link, 0));
+	  
+	  curr_point++;
+	  if (CALL_P (insn))
+	    {
+	      HARD_REG_SET clobbered_regs;
+	      
+	      get_call_invalidated_used_regs (insn, &clobbered_regs, FALSE);
+	      IOR_HARD_REG_SET (cfun->emit->call_used_regs, clobbered_regs);
+	      EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
+	        {
+		  int freq;
+		  allocno_t a = allocnos [i];
+		  
+		  freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
+		  if (freq == 0)
+		    freq = 1;
+		  ALLOCNO_CALL_FREQ (a) += freq;
+		  index = add_regno_call (ALLOCNO_REGNO (a), insn);
+		  if (ALLOCNO_CALLS_CROSSED_START (a) < 0)
+		    ALLOCNO_CALLS_CROSSED_START (a) = index;
+		  ALLOCNO_CALLS_CROSSED_NUM (a)++;
+		  /* Don't allocate allocnos that cross calls, if this
+		     function receives a nonlocal goto.  */
+		  if (current_function_has_nonlocal_label)
+		    {
+		      SET_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a));
+		      SET_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
+		    }
+		});
+	    }
+	  
+	  /* Mark any allocnos set in INSN as live, and mark them as
+	     conflicting with all other live reg allocnos.  Clobbers are
+	     processed again, so they conflict with the reg allocnos that
+	     are set.  */
+	  note_stores (PATTERN (insn), mark_reg_store, NULL);
+	  
+#ifdef AUTO_INC_DEC
+	  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+	    if (REG_NOTE_KIND (link) == REG_INC)
+	      mark_reg_store (XEXP (link, 0), NULL_RTX, NULL);
+#endif
+	  
+	  /* If INSN has multiple outputs, then any allocno that dies
+	     here and is used inside of an output must conflict with
+	     the other outputs.
+	     
+	     It is unsafe to use !single_set here since it will ignore
+	     an unused output.  Just because an output is unused does
+	     not mean the compiler can assume the side effect will not
+	     occur.  Consider if ALLOCNO appears in the address of an
+	     output and we reload the output.  If we allocate ALLOCNO
+	     to the same hard register as an unused output we could
+	     set the hard register before the output reload insn.  */
+	  if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
+	    for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+	      if (REG_NOTE_KIND (link) == REG_DEAD)
+		{
+		  int i;
+		  int used_in_output = 0;
+		  rtx reg = XEXP (link, 0);
+		  
+		  for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+		    {
+		      rtx set = XVECEXP (PATTERN (insn), 0, i);
+		      
+		      if (GET_CODE (set) == SET
+			  && ! REG_P (SET_DEST (set))
+			  && ! rtx_equal_p (reg, SET_DEST (set))
+			  && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+			used_in_output = 1;
+		    }
+		  if (used_in_output)
+		    mark_reg_conflicts (reg);
+		}
+	  
+	  process_single_reg_class_operands (FALSE);
+	  
+	  /* Mark any allocnos set in INSN and then never used.  */
+	  while (! VEC_empty (rtx, regs_set))
+	    {
+	      rtx reg = VEC_pop (rtx, regs_set);
+	      rtx note = find_regno_note (insn, REG_UNUSED, REGNO (reg));
+
+	      if (note)
+		mark_reg_death (XEXP (note, 0));
+	    }
+	  curr_point++;
+	}
+      EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
+       {
+	 make_regno_dead (ALLOCNO_REGNO (allocnos [i]));
+       });
+      curr_point++;
+    }
+  /* Propagate register pressure: */
+  if (loop_tree_node != ira_loop_tree_root)
+    for (i = 0; i < reg_class_cover_size; i++)
+      {
+	enum reg_class cover_class;
+
+	cover_class = reg_class_cover [i];
+	if (loop_tree_node->reg_pressure [cover_class]
+	    > loop_tree_node->father->reg_pressure [cover_class])
+	  loop_tree_node->father->reg_pressure [cover_class]
+	    = loop_tree_node->reg_pressure [cover_class];
+      }
+}
+
+static void
+create_start_finish_chains (void)
+{
+  int i;
+  allocno_t a;
+  allocno_live_range_t r;
+
+  start_point_ranges
+    = ira_allocate (max_point * sizeof (allocno_live_range_t));
+  memset (start_point_ranges, 0, max_point * sizeof (allocno_live_range_t));
+  finish_point_ranges
+    = ira_allocate (max_point * sizeof (allocno_live_range_t));
+  memset (finish_point_ranges, 0, max_point * sizeof (allocno_live_range_t));
+  for (i = 0; i < allocnos_num; i++)
+    {
+      a = allocnos [i];
+      for (r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = r->next)
+	{
+	  r->start_next = start_point_ranges [r->start];
+	  start_point_ranges [r->start] = r;
+	  r->finish_next = finish_point_ranges [r->finish];
+ 	  finish_point_ranges [r->finish] = r;
+	}
+    }
+}
+
+void
+rebuild_start_finish_chains (void)
+{
+  ira_free (finish_point_ranges);
+  ira_free (start_point_ranges);
+  create_start_finish_chains ();
+}
+
+void
+print_live_range_list (FILE *f, allocno_live_range_t r)
+{
+  for (; r != NULL; r = r->next)
+    fprintf (f, " [%d..%d]", r->start, r->finish);
+  fprintf (f, "\n");
+}
+
+void
+debug_live_range_list (allocno_live_range_t r)
+{
+  print_live_range_list (stderr, r);
+}
+
+static void
+print_allocno_live_ranges (FILE *f, allocno_t a)
+{
+  fprintf (f, " a%d(r%d):", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
+  print_live_range_list (f, ALLOCNO_LIVE_RANGES (a));
+}
+
+void
+debug_allocno_live_ranges (allocno_t a)
+{
+  print_allocno_live_ranges (stderr, a);
+}
+
+static void
+print_live_ranges (FILE *f)
+{
+  int i;
+
+  for (i = 0; i < allocnos_num; i++)
+    print_allocno_live_ranges (f, allocnos [i]);
+}
+
+void
+debug_live_ranges (void)
+{
+  print_live_ranges (stderr);
+}
+
+/* The function creates live ranges, set up CONFLICT_HARD_REGS and
+   TOTAL_CONFLICT_HARD_REGS for allocnos.  It also modifies hard reg
+   costs for allocnos whose hard register is actually fixed in an
+   insn.  */
+void
+create_allocno_live_ranges (void)
+{
+  allocno_set_words = (allocnos_num + INT_BITS - 1) / INT_BITS;
+  allocnos_live = ira_allocate (sizeof (INT_TYPE) * allocno_set_words);
+  allocnos_live_bitmap = ira_allocate_bitmap ();
+  /* Make a vector that mark_reg_{store,clobber} will store in.  */
+  if (!regs_set)
+    regs_set = VEC_alloc (rtx, heap, 10);
+  curr_point = 0;
+  traverse_loop_tree (FALSE, ira_loop_tree_root, NULL, process_bb_node_lives);
+  max_point = curr_point;
+  create_start_finish_chains ();
+  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+    print_live_ranges (ira_dump_file);
+  /* Clean up.  */
+  ira_free_bitmap (allocnos_live_bitmap);
+  ira_free (allocnos_live);
+}
+
+void
+finish_allocno_live_ranges (void)
+{
+  ira_free (finish_point_ranges);
+  ira_free (start_point_ranges);
+}
Index: print-rtl.c
===================================================================
--- print-rtl.c	(revision 129968)
+++ print-rtl.c	(working copy)
@@ -60,8 +60,10 @@ const char *print_rtx_head = "";
    This must be defined here so that programs like gencodes can be linked.  */
 int flag_dump_unnumbered = 0;
 
+#ifdef GENERATOR_FILE
 /* Nonzero means use simplified format without flags, modes, etc.  */
-int flag_simple = 0;
+int flag_dump_simple_rtl = 0;
+#endif
 
 /* Nonzero if we are dumping graphical description.  */
 int dump_for_graph;
@@ -136,7 +138,7 @@ print_rtx (const_rtx in_rtx)
 
   if (sawclose)
     {
-      if (flag_simple)
+      if (flag_dump_simple_rtl)
 	fputc (' ', outfile);
       else
 	fprintf (outfile, "\n%s%*s", print_rtx_head, indent * 2, "");
@@ -170,12 +172,12 @@ print_rtx (const_rtx in_rtx)
   else
     {
       /* Print name of expression code.  */
-      if (flag_simple && GET_CODE (in_rtx) == CONST_INT)
+      if (flag_dump_simple_rtl && GET_CODE (in_rtx) == CONST_INT)
 	fputc ('(', outfile);
       else
 	fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
 
-      if (! flag_simple)
+      if (! flag_dump_simple_rtl)
 	{
 	  if (RTX_FLAG (in_rtx, in_struct))
 	    fputs ("/s", outfile);
@@ -376,10 +378,10 @@ print_rtx (const_rtx in_rtx)
 	break;
 
       case 'w':
-	if (! flag_simple)
+	if (! flag_dump_simple_rtl)
 	  fprintf (outfile, " ");
 	fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, XWINT (in_rtx, i));
-	if (! flag_simple)
+	if (! flag_dump_simple_rtl)
 	  fprintf (outfile, " [" HOST_WIDE_INT_PRINT_HEX "]",
 		   XWINT (in_rtx, i));
 	break;
@@ -766,7 +768,9 @@ print_rtl_single (FILE *outf, const_rtx 
 void
 print_simple_rtl (FILE *outf, const_rtx x)
 {
-  flag_simple = 1;
+  int save = flag_dump_simple_rtl;
+
+  flag_dump_simple_rtl = 1;
   print_rtl (outf, x);
-  flag_simple = 0;
+  flag_dump_simple_rtl = save;
 }
Index: ira-emit.c
===================================================================
--- ira-emit.c	(revision 129968)
+++ ira-emit.c	(working copy)
@@ -54,19 +54,22 @@ static int eq_move_lists_p (struct move 
 static int change_regs (rtx *);
 static void add_to_edge_list (edge, struct move *, int);
 static rtx create_new_reg (rtx);
-static int subloop_tree_node_p (struct ira_loop_tree_node *,
-				struct ira_loop_tree_node *);
+static int subloop_tree_node_p (loop_tree_node_t, loop_tree_node_t);
 static void set_allocno_reg (allocno_t, rtx);
 static int not_modified_p (allocno_t, allocno_t);
 static void generate_edge_moves (edge);
-static void change_loop (struct ira_loop_tree_node *);
+static void change_loop (loop_tree_node_t);
 static int eq_edge_move_lists_p (VEC(edge,gc) *);
-static int can_move_through_p (rtx *, struct move *, int);
 static void unify_moves (basic_block, int);
 static void traverse_moves (struct move *);
 static struct move *modify_move_list (struct move *);
 static rtx emit_move_list (struct move *, int);
 static void emit_moves (void);
+static void update_costs (allocno_t, int, int);
+static void add_range_and_copies_from_move_list (struct move *,
+						 loop_tree_node_t,
+						 bitmap, int);
+static void add_ranges_and_copies (void);
 
 /* The structure represents allocno shuffling.  */
 struct move
@@ -82,6 +85,8 @@ struct move
   /* Moves on which given move depends on.  Dependency can be cyclic.
      It means we need a temporary to generates the moves.  */
   struct move **deps;
+  /* First insn generated for the move.  */
+  rtx insn;
 };
 
 /* Array of moves (indexed by BB index) which should be put at the
@@ -105,6 +110,7 @@ create_move (allocno_t to, allocno_t fro
   move->to = to;
   move->from = from;
   move->next = NULL;
+  move->insn = NULL_RTX;
   move->visited_p = FALSE;
   return move;
 }
@@ -221,8 +227,8 @@ create_new_reg (rtx original_reg)
   REG_USERVAR_P (new_reg) = REG_USERVAR_P (original_reg);
   REG_POINTER (new_reg) = REG_POINTER (original_reg);
   REG_ATTRS (new_reg) = REG_ATTRS (original_reg);
-  if (ira_dump_file)
-    fprintf (ira_dump_file, "  Creating newreg=%i from oldreg=%i\n",
+  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "      Creating newreg=%i from oldreg=%i\n",
 	     REGNO (new_reg), REGNO (original_reg));
   return new_reg;
 }
@@ -230,8 +236,7 @@ create_new_reg (rtx original_reg)
 /* The function returns non-zero if loop given by SUBNODE inside the
    loop given by NODE.  */
 static int
-subloop_tree_node_p (struct ira_loop_tree_node *subnode,
-		     struct ira_loop_tree_node *node)
+subloop_tree_node_p (loop_tree_node_t subnode, loop_tree_node_t node)
 {
   for (; subnode != NULL; subnode = subnode->father)
     if (subnode == node)
@@ -246,7 +251,7 @@ static void
 set_allocno_reg (allocno_t allocno, rtx reg)
 {
   allocno_t a;
-  struct ira_loop_tree_node *node;
+  loop_tree_node_t node;
 
   node = ALLOCNO_LOOP_TREE_NODE (allocno);
   for (a = regno_allocno_map [ALLOCNO_REGNO (allocno)];
@@ -263,7 +268,7 @@ not_modified_p (allocno_t src_allocno, a
 {
   int regno, orig_regno;
   allocno_t a;
-  struct ira_loop_tree_node *node;
+  loop_tree_node_t node;
 
   orig_regno = ALLOCNO_REGNO (src_allocno);
   regno = REGNO (ALLOCNO_REG (dest_allocno));
@@ -285,7 +290,7 @@ not_modified_p (allocno_t src_allocno, a
 static void
 generate_edge_moves (edge e)
 {
-  struct ira_loop_tree_node *src_loop_node, *dest_loop_node;
+  loop_tree_node_t src_loop_node, dest_loop_node;
   unsigned int regno;
   bitmap_iterator bi;
   allocno_t src_allocno, dest_allocno, *src_map, *dest_map;
@@ -314,9 +319,12 @@ generate_edge_moves (edge e)
 	    && ALLOCNO_HARD_REGNO (src_allocno) >= 0
 	    && not_modified_p (src_allocno, dest_allocno))
 	  {
-	    if (ira_dump_file != NULL)
-	      fprintf (ira_dump_file, "Remove r%d:%d->%d\n", regno,
-		       ALLOCNO_NUM (src_allocno), ALLOCNO_NUM (dest_allocno));
+	    ALLOCNO_MEM_OPTIMIZED_DEST (src_allocno) = dest_allocno;
+	    ALLOCNO_MEM_OPTIMIZED_DEST_P (dest_allocno) = TRUE;
+	    if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	      fprintf (ira_dump_file, "      Remove r%d:a%d->a%d(mem)\n",
+		       regno, ALLOCNO_NUM (src_allocno),
+		       ALLOCNO_NUM (dest_allocno));
 	    continue;
 	  }
 	move = create_move (dest_allocno, src_allocno);
@@ -335,7 +343,7 @@ static bitmap used_regno_bitmap;
 /* The following function changes (if necessary) pseudo-registers
    inside loop given by loop tree node NODE.  */
 static void
-change_loop (struct ira_loop_tree_node *node)
+change_loop (loop_tree_node_t node)
 {
   bitmap_iterator bi;
   unsigned int i;
@@ -357,8 +365,9 @@ change_loop (struct ira_loop_tree_node *
 	  return;
 	}
       
-      if (ira_dump_file != NULL)
-	fprintf (ira_dump_file, "Changing RTL for loop %d (header bb%d)\n",
+      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	fprintf (ira_dump_file,
+		 "      Changing RTL for loop %d (header bb%d)\n",
 		 node->loop->num, node->loop->header->index);
       
       map = ira_curr_loop_tree_node->father->regno_allocno_map;
@@ -378,6 +387,9 @@ change_loop (struct ira_loop_tree_node *
 	      && (ALLOCNO_HARD_REGNO (allocno)
 		  == ALLOCNO_HARD_REGNO (father_allocno))
 	      && (ALLOCNO_HARD_REGNO (allocno) < 0
+		  || TEST_HARD_REG_BIT (prohibited_mode_move_regs
+					[ALLOCNO_MODE (allocno)],
+					ALLOCNO_HARD_REGNO (allocno))
 		  /* don't create copies because reload can spill a
 		     allocno set by copy although allocno will not get
 		     memory slot.  */
@@ -388,7 +400,7 @@ change_loop (struct ira_loop_tree_node *
 	  if (father_allocno == NULL
 	      || REGNO (ALLOCNO_REG (father_allocno)) == REGNO (original_reg))
 	    {
-	      if (ira_dump_file)
+	      if (internal_flag_ira_verbose > 3 && ira_dump_file)
 		fprintf (ira_dump_file, "  %i vs father %i:",
 			 ALLOCNO_HARD_REGNO (allocno),
 			 ALLOCNO_HARD_REGNO (father_allocno));
@@ -431,114 +443,6 @@ eq_edge_move_lists_p (VEC(edge,gc) *vec)
   return TRUE;
 }
 
-/* Current regno allocno map used to check moves in function
-   `can_move_through_p'.  */
-static allocno_t *curr_jump_map;
-
-/* This recursive function returns nonzero if list of moves LIST can
-   be moved through setting (if OUTPUT_P is nonzero) or reading
-   LOC.  */
-static int
-can_move_through_p (rtx *loc, struct move *list, int output_p)
-{
-  int i;
-  const char *fmt;
-  enum rtx_code code = GET_CODE (*loc);
-
-  code = GET_CODE (*loc);
-  if (code == REG)
-    {
-      int hard_regno, regno;
-      HARD_REG_SET regs, move_regs;
-
-      regno = ORIGINAL_REGNO (*loc);
-      hard_regno = REGNO (*loc);
-      if (hard_regno >= FIRST_PSEUDO_REGISTER)
-	hard_regno = ALLOCNO_HARD_REGNO (curr_jump_map [regno]);
-      if (hard_regno < 0)
-	CLEAR_HARD_REG_SET (regs);
-      else
-	COPY_HARD_REG_SET
-	  (regs, reg_mode_hard_regset [hard_regno] [GET_MODE (*loc)]);
-      for (;list != NULL; list = list->next)
-	if (output_p
-	    && regno == (int) ORIGINAL_REGNO (ALLOCNO_REG (list->from)))
-	  return FALSE;
-	else
-	  {
-	    hard_regno = ALLOCNO_HARD_REGNO (list->to);
-	    if (hard_regno < 0)
-	      CLEAR_HARD_REG_SET (move_regs);
-	    else
-	      COPY_HARD_REG_SET
-		(move_regs,
-		 reg_mode_hard_regset [hard_regno] [ALLOCNO_MODE (list->to)]);
-	    if (output_p)
-	      {
-		hard_regno = ALLOCNO_HARD_REGNO (list->from);
-		if (hard_regno >= 0)
-		  IOR_HARD_REG_SET (move_regs,
-				    reg_mode_hard_regset
-				    [hard_regno] [ALLOCNO_MODE (list->from)]);
-	      }
-	    AND_HARD_REG_SET (move_regs, regs);
-	    if (! hard_reg_set_equal_p (move_regs, zero_hard_reg_set))
-	      return FALSE;
-	  }
-      return TRUE;
-    }
-  else if (code == SET)
-    {
-      if (! can_move_through_p (&SET_DEST (*loc), list, TRUE))
-	return FALSE;
-      if (! can_move_through_p (&SET_SRC (*loc), list, FALSE))
-	return FALSE;
-      return TRUE;
-    }
-  else if (code == CLOBBER)
-    {
-      if (! can_move_through_p (&XEXP (*loc, 0), list, TRUE))
-	return FALSE;
-      return TRUE;
-    }
-  else if (code == MEM)
-    {
-      if (! can_move_through_p (&XEXP (*loc, 0), list, FALSE))
-	return FALSE;
-      return TRUE;
-    }
-  else if (code == PRE_DEC || code == POST_DEC || code == PRE_INC || 
-	   code == POST_INC || code == POST_MODIFY || code == PRE_MODIFY)
-    {
-      if (! can_move_through_p (&XEXP (*loc, 0), list, TRUE))
-	return FALSE;
-      if (! can_move_through_p (&XEXP (*loc, 0), list, FALSE))
-	return FALSE;
-      return TRUE;
-    }
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e')
-	{
-	  if (! can_move_through_p (&XEXP (*loc, i), list, output_p))
-	    return FALSE;
-	}
-      else if (fmt[i] == 'E')
-	{
-	  int j;
-
-	  for (j = XVECLEN (*loc, i) - 1; j >= 0; j--)
-	    {
-	      if (! can_move_through_p (&XVECEXP (*loc, i, j), list, output_p))
-		return FALSE;
-	    }
-	}
-    }
-  return TRUE;
-}
-
 /* The function looks at all enter edges (if START_P) or exit edges of
    basic block BB and puts move lists at the BB start or end if it is
    possible.  In other words, it decreases code duplication of
@@ -556,10 +460,7 @@ unify_moves (basic_block bb, int start_p
     return;
   e = EDGE_I (vec, 0);
   list = e->aux;
-  curr_jump_map = IRA_BB_NODE (bb)->father->regno_allocno_map;
-  if (! start_p
-      && (control_flow_insn_p (BB_END (bb))
-	  && ! can_move_through_p (&PATTERN (BB_END (bb)), list, FALSE)))
+  if (! start_p && control_flow_insn_p (BB_END (bb)))
     return;
   e->aux = NULL;
   for (i = EDGE_COUNT (vec) - 1; i > 0; i--)
@@ -621,7 +522,7 @@ traverse_moves (struct move *move)
 static struct move *
 modify_move_list (struct move *list)
 {
-  int i, n, nregs, hard_regno;
+  int i, n, nregs, hard_regno, hard_regs_num;
   allocno_t to, from, new_allocno;
   struct move *move, *new_move, *set_move, *first, *last;
 
@@ -689,14 +590,35 @@ modify_move_list (struct move *list)
 	  for (i = 0; i < nregs; i++)
 	    if (hard_regno_last_set_check [hard_regno + i] == curr_tick
 		&& ALLOCNO_HARD_REGNO (hard_regno_last_set
-				      [hard_regno + i]->to) >= 0)
+				       [hard_regno + i]->to) >= 0)
 	      {
 		set_move = hard_regno_last_set [hard_regno + i];
+		/* It does not matter what loop_tree_node (of TO or
+		   FROM) to use for the new allocno because of
+		   subsequent IR flattening.  */
 		new_allocno
 		  = create_allocno (ALLOCNO_REGNO (set_move->to), FALSE,
-				   ALLOCNO_LOOP_TREE_NODE (set_move->to));
-		/* That is a minimum to emit allocnos correctly and for
-		   setting reg_renumber.  */
+				    ALLOCNO_LOOP_TREE_NODE (set_move->to));
+		ALLOCNO_MODE (new_allocno) = ALLOCNO_MODE (set_move->to);
+		ALLOCNO_COVER_CLASS (new_allocno)
+		  = ALLOCNO_COVER_CLASS (set_move->to);
+		ALLOCNO_BEST_CLASS (new_allocno)
+		  = ALLOCNO_COVER_CLASS (new_allocno);
+		hard_regs_num
+		  = class_hard_regs_num [ALLOCNO_COVER_CLASS (new_allocno)];
+		ALLOCNO_HARD_REG_COSTS (new_allocno)
+		  = ira_allocate (hard_regs_num * sizeof (int));
+		memset (ALLOCNO_HARD_REG_COSTS (new_allocno), 0,
+			hard_regs_num * sizeof (int));
+		ALLOCNO_CONFLICT_HARD_REG_COSTS (new_allocno)
+		  = ira_allocate (hard_regs_num * sizeof (int));
+		memset (ALLOCNO_CONFLICT_HARD_REG_COSTS (new_allocno), 0,
+			hard_regs_num * sizeof (int));
+		ALLOCNO_UPDATED_HARD_REG_COSTS (new_allocno)
+		  = ira_allocate (hard_regs_num * sizeof (int));
+		ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (new_allocno)
+		  = ira_allocate (hard_regs_num * sizeof (int));
+		ALLOCNO_ASSIGNED_P (new_allocno) = TRUE;
 		ALLOCNO_HARD_REGNO (new_allocno) = -1;
 		ALLOCNO_REG (new_allocno)
 		  = create_new_reg (ALLOCNO_REG (set_move->to));
@@ -704,6 +626,11 @@ modify_move_list (struct move *list)
 		set_move->to = new_allocno;
 		VARRAY_PUSH_GENERIC_PTR (move_varray, new_move);
 		move_loops_num++;
+		if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+		  fprintf (ira_dump_file,
+			   "    Creating temporary allocno a%dr%d\n",
+			   ALLOCNO_NUM (new_allocno),
+			   REGNO (ALLOCNO_REG (new_allocno)));
 	      }
 	}
       if ((hard_regno = ALLOCNO_HARD_REGNO (to)) < 0)
@@ -731,15 +658,24 @@ static rtx
 emit_move_list (struct move *list, int freq)
 {
   int cost;
-  rtx result;
+  rtx result, insn;
   enum machine_mode mode;
   enum reg_class cover_class;
 
-  list = modify_move_list (list);
   start_sequence ();
   for (; list != NULL; list = list->next)
     {
+      start_sequence ();
       emit_move_insn (ALLOCNO_REG (list->to), ALLOCNO_REG (list->from));
+      list->insn = get_insns ();
+      end_sequence ();
+      /* The reload needs to have set up insn codes.  If the reload
+	 sets up insn codes by itself, it may fail because insns will
+	 have hard registers instead of pseudos and there may be no
+	 machine insn with given hard registers.  */
+      for (insn = list->insn; insn != NULL_RTX; insn = NEXT_INSN (insn))
+	recog_memoized (insn);
+      emit_insn (list->insn);
       mode = ALLOCNO_MODE (list->to);
       cover_class = ALLOCNO_COVER_CLASS (list->to);
       cost = 0;
@@ -785,6 +721,7 @@ emit_moves (void)
     {
       if (at_bb_start [bb->index] != NULL)
 	{
+	  at_bb_start [bb->index] = modify_move_list (at_bb_start [bb->index]);
 	  insns = emit_move_list (at_bb_start [bb->index],
 				  REG_FREQ_FROM_BB (bb));
 	  tmp = BB_HEAD (bb);
@@ -802,12 +739,11 @@ emit_moves (void)
 
       if (at_bb_end [bb->index] != NULL)
 	{
+	  at_bb_end [bb->index] = modify_move_list (at_bb_end [bb->index]);
 	  insns = emit_move_list (at_bb_end [bb->index],
 				  REG_FREQ_FROM_BB (bb));
-	  if (! control_flow_insn_p (BB_END (bb)))
-	    emit_insn_after (insns, BB_END (bb));
-	  else
-	    emit_insn_before (insns, BB_END (bb));
+	  ira_assert (! control_flow_insn_p (BB_END (bb)));
+	  emit_insn_after (insns, BB_END (bb));
 	}
 
       FOR_EACH_EDGE (e, ei, bb->succs)
@@ -816,6 +752,7 @@ emit_moves (void)
 	    continue;
 	  ira_assert ((e->flags & EDGE_ABNORMAL) == 0
 		      || ! EDGE_CRITICAL_P (e));
+	  e->aux = modify_move_list (e->aux);
 	  insert_insn_on_edge
 	    (emit_move_list (e->aux,
 			     REG_FREQ_FROM_EDGE_FREQ (EDGE_FREQUENCY (e))),
@@ -826,27 +763,186 @@ emit_moves (void)
     }
 }
 
+/* Update costs of A and its parents from reading (if READ_P) or
+   writing A on an execution path with FREQ.  */
+static void
+update_costs (allocno_t a, int read_p, int freq)
+{
+  loop_tree_node_t father;
+
+  for (;;)
+    {
+      ALLOCNO_NREFS (a)++;
+      ALLOCNO_FREQ (a) += freq;
+      ALLOCNO_MEMORY_COST (a)
+	+= (memory_move_cost [ALLOCNO_MODE (a)] [ALLOCNO_COVER_CLASS (a)]
+	    [read_p ? 1 : 0] * freq);
+      if ((father = ALLOCNO_LOOP_TREE_NODE (a)->father) == NULL
+	  || (a = father->regno_allocno_map [ALLOCNO_REGNO (a)]) == NULL)
+	break;
+    }
+}
+
+/* The function processes moves from LIST with execution FREQ to add
+   ranges, copies, and modify costs.  All regnos living through the
+   list is in LIVE_THROUGH, and the loop tree node used to find
+   corresponding allocnos is NODE.  */
+static void
+add_range_and_copies_from_move_list (struct move *list, loop_tree_node_t node,
+				     bitmap live_through, int freq)
+{
+  int start, n;
+  unsigned int regno;
+  struct move *move;
+  allocno_t to, from, a;
+  copy_t cp;
+  allocno_live_range_t r;
+  bitmap_iterator bi;
+  HARD_REG_SET hard_regs_live;
+
+  if (list == NULL)
+    return;
+  n = 0;
+  EXECUTE_IF_SET_IN_BITMAP (live_through, FIRST_PSEUDO_REGISTER, regno, bi)
+    n++;
+  REG_SET_TO_HARD_REG_SET (hard_regs_live, live_through);
+  /* This is a trick to guarantee that new ranges is not merged with
+     the old ones.  */
+  max_point++;
+  start = max_point;
+  for (move = list; move != NULL; move = move->next)
+    {
+      from = move->from;
+      to = move->to;
+      if (ALLOCNO_CONFLICT_ALLOCNO_VEC (to) == NULL)
+	{
+	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+	    fprintf (ira_dump_file,
+		     "    Allocate conflict vector of size %d for a%dr%d\n",
+		     n, ALLOCNO_NUM (to), REGNO (ALLOCNO_REG (to)));
+	  allocate_allocno_conflicts (to, n);
+	}
+      bitmap_clear_bit (live_through, ALLOCNO_REGNO (from));
+      bitmap_clear_bit (live_through, ALLOCNO_REGNO (to));
+      IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (from), hard_regs_live);
+      IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (to), hard_regs_live);
+      IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (from),
+			hard_regs_live);
+      IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (to), hard_regs_live);
+      update_costs (from, TRUE, freq);
+      update_costs (to, FALSE, freq);
+      cp = add_allocno_copy (from, to, freq, move->insn, NULL);
+      if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+	fprintf (ira_dump_file, "    Adding cp%d:a%dr%d-a%dr%d\n",
+		 cp->num, ALLOCNO_NUM (cp->first),
+		 REGNO (ALLOCNO_REG (cp->first)), ALLOCNO_NUM (cp->second),
+		 REGNO (ALLOCNO_REG (cp->second)));
+      r = ALLOCNO_LIVE_RANGES (from);
+      if (r == NULL || r->finish >= 0)
+	{
+	  ALLOCNO_LIVE_RANGES (from)
+	    = create_allocno_live_range (from, start, max_point, r);
+	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+	    fprintf (ira_dump_file,
+		     "    Adding range [%d..%d] to allocno a%dr%d\n",
+		     start, max_point, ALLOCNO_NUM (from),
+		     REGNO (ALLOCNO_REG (from)));
+	}
+      else
+	r->finish = max_point;
+      max_point++;
+      ALLOCNO_LIVE_RANGES (to)
+	= create_allocno_live_range (to, max_point, -1,
+				     ALLOCNO_LIVE_RANGES (to));
+      max_point++;
+    }
+  for (move = list; move != NULL; move = move->next)
+    {
+      r = ALLOCNO_LIVE_RANGES (move->to);
+      if (r->finish < 0)
+	{
+	  r->finish = max_point - 1;
+	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+	    fprintf (ira_dump_file,
+		     "    Adding range [%d..%d] to allocno a%dr%d\n",
+		     r->start, r->finish, ALLOCNO_NUM (move->to),
+		     REGNO (ALLOCNO_REG (move->to)));
+	}
+    }
+  EXECUTE_IF_SET_IN_BITMAP (live_through, FIRST_PSEUDO_REGISTER, regno, bi)
+    {
+      a = node->regno_allocno_map [regno];
+      if (ALLOCNO_MEM_OPTIMIZED_DEST (a) == NULL)
+	{
+	  ALLOCNO_LIVE_RANGES (a)
+	    = create_allocno_live_range (a, start, max_point - 1,
+					 ALLOCNO_LIVE_RANGES (a));
+	  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+	    fprintf
+	      (ira_dump_file,
+	       "    Adding range [%d..%d] to live through allocno a%dr%d\n",
+	       start, max_point - 1, ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a)));
+	}
+    }
+}
+
+/* The function processes all move list to add ranges, conflicts,
+   copies, and modify costs.  */
+static void
+add_ranges_and_copies (void)
+{
+  basic_block bb;
+  edge_iterator ei;
+  edge e;
+  loop_tree_node_t node;
+  bitmap live_through;
+
+  live_through = ira_allocate_bitmap ();
+  FOR_EACH_BB (bb)
+    {
+      /* It does not matter what loop_tree_node (of source or
+	 destination block) to use for searching allocnos by their
+	 regnos because of subsequent IR flattening.  */
+      node = IRA_BB_NODE (bb)->father;
+      bitmap_copy (live_through, DF_LR_IN (bb));
+      add_range_and_copies_from_move_list
+	(at_bb_start [bb->index], node, live_through, REG_FREQ_FROM_BB (bb));
+      bitmap_copy (live_through, DF_LR_OUT (bb));
+      add_range_and_copies_from_move_list
+	(at_bb_end [bb->index], node, live_through, REG_FREQ_FROM_BB (bb));
+      FOR_EACH_EDGE (e, ei, bb->succs)
+	{
+	  bitmap_and (live_through, DF_LR_IN (e->dest), DF_LR_OUT (bb));
+	  add_range_and_copies_from_move_list
+	    (e->aux, node, live_through,
+	     REG_FREQ_FROM_EDGE_FREQ (EDGE_FREQUENCY (e)));
+	}
+    }
+  ira_free_bitmap (live_through);
+}
+
 /* Entry function changing code and generating allocno shuffling for
-   the regional register allocation.  */
+   the regional (LOOPS_P is TRUE in this case) register allocation.  */
 void
-ira_emit (void)
+ira_emit (int loops_p)
 {
   int i;
   basic_block bb;
   edge_iterator ei;
   edge e;
 
+  for (i = 0; i < allocnos_num; i++)
+    ALLOCNO_REG (allocnos [i]) = regno_reg_rtx [ALLOCNO_REGNO (allocnos [i])];
+  if (! loops_p)
+    return;
   at_bb_start = ira_allocate (sizeof (struct move *) * last_basic_block);
   memset (at_bb_start, 0, sizeof (struct move *) * last_basic_block);
   at_bb_end = ira_allocate (sizeof (struct move *) * last_basic_block);
   memset (at_bb_end, 0, sizeof (struct move *) * last_basic_block);
-  for (i = 0; i < allocnos_num; i++)
-    if (ALLOCNO_CAP_MEMBER (allocnos [i]) == NULL)
-      ALLOCNO_REG (allocnos [i]) = regno_reg_rtx [ALLOCNO_REGNO (allocnos [i])];
   local_allocno_bitmap = ira_allocate_bitmap ();
   used_regno_bitmap = ira_allocate_bitmap ();
   max_regno_before_changing = max_reg_num ();
-  traverse_loop_tree (ira_loop_tree_root, change_loop, NULL);
+  traverse_loop_tree (FALSE, ira_loop_tree_root, change_loop, NULL);
   ira_free_bitmap (used_regno_bitmap);
   ira_free_bitmap (local_allocno_bitmap);
   FOR_EACH_BB (bb)
@@ -868,6 +964,7 @@ ira_emit (void)
     unify_moves (bb, FALSE);
   VARRAY_GENERIC_PTR_NOGC_INIT (move_varray, allocnos_num, "ordered moves");
   emit_moves ();
+  add_ranges_and_copies ();
   /* Clean up: */
   FOR_EACH_BB (bb)
     {
Index: ira-build.c
===================================================================
--- ira-build.c	(revision 129968)
+++ ira-build.c	(working copy)
@@ -43,49 +43,70 @@ Software Foundation, 51 Franklin Street,
 static void create_loop_tree_nodes (int);
 static void finish_loop_tree_nodes (void);
 static void add_loop_to_tree (struct loop *);
+static int setup_loop_tree_level (loop_tree_node_t, int);
 static void form_loop_tree (void);
 
+static void rebuild_regno_allocno_maps (void);
+
 static void initiate_calls (void);
+static void expand_calls (void);
+static void compress_calls (void);
 static void finish_calls (void);
 
 static void initiate_allocnos (void);
 static void check_allocno_conflict_vec (allocno_t, int);
-static void add_allocno_conflict (allocno_t, allocno_t);
+static void add_to_allocno_conflict_vec (allocno_t, allocno_t);
 static allocno_t create_cap_allocno (allocno_t);
+static void propagate_info_to_cap (allocno_t);
+static allocno_live_range_t copy_allocno_live_range (allocno_live_range_t);
+static allocno_live_range_t
+  copy_allocno_live_range_list (allocno_live_range_t);
+
+static void finish_allocno (allocno_t);
 static void finish_allocnos (void);
 
 static void initiate_copies (void);
+static void finish_copy (copy_t);
 static void finish_copies (void);
 
 static void create_insn_allocnos (rtx, int);
-static void create_bb_allocnos (struct ira_loop_tree_node *);
+static void create_bb_allocnos (loop_tree_node_t);
 static void create_loop_allocnos (edge);
-static void create_loop_tree_node_allocnos (struct ira_loop_tree_node *);
+static void create_loop_tree_node_allocnos (loop_tree_node_t);
 static void create_allocnos (void);
-static void create_loop_tree_node_caps (struct ira_loop_tree_node *);
-#ifdef ENABLE_IRA_CHECKING
-static void check_coalesced_allocnos (void);
-#endif
+
+static void create_loop_tree_node_caps (loop_tree_node_t);
+static void propagate_info_to_loop_tree_node_caps (loop_tree_node_t);
+static allocno_live_range_t merge_ranges (allocno_live_range_t,
+					  allocno_live_range_t);
+static loop_tree_node_t common_loop_tree_node_dominator (loop_tree_node_t,
+							 loop_tree_node_t);
+static void check_and_add_conflicts (allocno_t, allocno_t *);
+static void add_conflict_with_underlying_allocnos (allocno_t,
+						   loop_tree_node_t, int);
 
 /* All natural loops.  */
 struct loops ira_loops;
 
 /* The root of the loop tree corresponding to the all function.  */
-struct ira_loop_tree_node *ira_loop_tree_root;
+loop_tree_node_t ira_loop_tree_root;
+
+/* Height of the loop tree.  */
+int ira_loop_tree_height;
 
 /* All basic block data are referred through the following array.  We
    can not use member `aux' for this because it is used for insertion
    of insns on edges.  */
-struct ira_loop_tree_node *ira_bb_nodes;
+loop_tree_node_t ira_bb_nodes;
 
 /* All loop data are referred through the following array.  */
-struct ira_loop_tree_node *ira_loop_nodes;
+loop_tree_node_t ira_loop_nodes;
 
-/* Map regno -> allocno for the current loop tree node.  */
+/* Map regno -> allocnos.  */
 allocno_t *regno_allocno_map;
 
-/* Array of references to all allocnos and its size.  The order number
-   of the allocno corresponds to the index in the array.  */
+/* Array of references to all allocnos and their size.  The order
+   number of the allocno corresponds to the index in the array.  */
 allocno_t *allocnos;
 int allocnos_num;
 
@@ -116,7 +137,7 @@ create_loop_tree_nodes (int loops_p)
   loop_p loop;
 
   ira_bb_nodes
-    = ira_allocate (sizeof (struct ira_loop_tree_node) * last_basic_block);
+    = ira_allocate (sizeof (struct loop_tree_node) * last_basic_block);
   last_basic_block_before_change = last_basic_block;
   for (i = 0; i < (unsigned int) last_basic_block; i++)
     {
@@ -128,7 +149,7 @@ create_loop_tree_nodes (int loops_p)
       ira_bb_nodes [i].border_allocnos = NULL;
       ira_bb_nodes [i].local_copies = NULL;
     }
-  ira_loop_nodes = ira_allocate (sizeof (struct ira_loop_tree_node)
+  ira_loop_nodes = ira_allocate (sizeof (struct loop_tree_node)
 				 * VEC_length (loop_p, ira_loops.larray));
   max_regno = max_reg_num ();
   for (i = 0; VEC_iterate (loop_p, ira_loops.larray, i, loop); i++)
@@ -213,7 +234,7 @@ static void
 add_loop_to_tree (struct loop *loop)
 {
   struct loop *father;
-  struct ira_loop_tree_node *loop_node, *father_node;
+  loop_tree_node_t loop_node, father_node;
 
   /* Can not use loop node access macros because of potential checking
      and because the nodes are not initialized yet.  */
@@ -246,6 +267,29 @@ add_loop_to_tree (struct loop *loop)
     }
 }
 
+/* Enumerate loops in loop with root LOOP_NODE starting with LEVEL and
+   return maximal value of level in the tree + 1.  */
+static int
+setup_loop_tree_level (loop_tree_node_t loop_node, int level)
+{
+  int height, max_height;
+  loop_tree_node_t subloop_node;
+
+  ira_assert (loop_node->bb == NULL);
+  loop_node->level = level;
+  max_height = level + 1;
+  for (subloop_node = loop_node->inner;
+       subloop_node != NULL;
+       subloop_node = subloop_node->next)
+    if (subloop_node->bb == NULL)
+      {
+	height = setup_loop_tree_level (subloop_node, level + 1);
+	if (height > max_height)
+	  max_height = height;
+      }
+  return max_height;
+}
+
 /* The following function creates the loop tree.  The algorithm is
    designed to provide correct order of loops (by the last loop BB)
    and basic blocks in chain formed by next.  */
@@ -255,7 +299,7 @@ form_loop_tree (void)
   unsigned int i;
   basic_block bb;
   struct loop *father;
-  struct ira_loop_tree_node *bb_node, *loop_node;
+  loop_tree_node_t bb_node, loop_node;
   loop_p loop;
 
   /* Can not use loop/bb node access macros because of potential
@@ -282,11 +326,54 @@ form_loop_tree (void)
       loop_node->inner = bb_node;
     }
   ira_loop_tree_root = IRA_LOOP_NODE_BY_INDEX (ira_loops.tree_root->num);
+  ira_loop_tree_height = setup_loop_tree_level (ira_loop_tree_root, 0);
   ira_assert (ira_loop_tree_root->regno_allocno_map != NULL);
 }
 
 
 
+/* The function rebuilds REGNO_ALLOCNO_MAP and REGNO_ALLOCNO_MAPs of
+   the loops using only allocno info.  */
+static void
+rebuild_regno_allocno_maps (void)
+{
+  unsigned int l;
+  int i, max_regno, regno;
+  allocno_t a;
+  loop_tree_node_t loop_tree_node;
+  loop_p loop;
+
+  max_regno = max_reg_num ();
+  for (l = 0; VEC_iterate (loop_p, ira_loops.larray, l, loop); l++)
+    if (ira_loop_nodes [l].regno_allocno_map != NULL)
+      {
+	ira_free (ira_loop_nodes [l].regno_allocno_map);
+	ira_loop_nodes [l].regno_allocno_map
+	  = ira_allocate (sizeof (allocno_t) * max_regno);
+	memset (ira_loop_nodes [l].regno_allocno_map, 0,
+		sizeof (allocno_t) * max_regno);
+      }
+  ira_free (regno_allocno_map);
+  regno_allocno_map = ira_allocate (max_regno * sizeof (allocno_t));
+  memset (regno_allocno_map, 0, max_regno * sizeof (allocno_t));
+  for (i = 0; i < allocnos_num; i++)
+    {
+      a = allocnos [i];
+      if (ALLOCNO_CAP_MEMBER (a) != NULL)
+	continue;
+      regno = ALLOCNO_REGNO (a);
+      loop_tree_node = ALLOCNO_LOOP_TREE_NODE (a);
+      ALLOCNO_NEXT_REGNO_ALLOCNO (a) = regno_allocno_map [regno];
+      regno_allocno_map [regno] = a;
+      if (loop_tree_node->regno_allocno_map [regno] == NULL)
+	/* Remember that we can create temporary allocnos to break
+	   cycles in register shuffle.  */
+	loop_tree_node->regno_allocno_map [regno] = a;
+    }
+}
+
+
+
 /* Array of vectors containing calls intersected by pseudo-registers.  */
 VEC(rtx, heap) **regno_calls;
 
@@ -298,11 +385,47 @@ static int regno_calls_num;
 static void
 initiate_calls (void)
 {
-  regno_calls_num = max_reg_num ();
+  regno_calls_num = max_reg_num () * 3 / 2;
   regno_calls = ira_allocate (regno_calls_num * sizeof (VEC(rtx, heap) *));
   memset (regno_calls, 0, regno_calls_num * sizeof (VEC(rtx, heap) *));
 }
 
+/* The function expands array of vectors containing calls for all
+   pseudo-registers.  */
+static void
+expand_calls (void)
+{
+  int max_regno = max_reg_num ();
+
+  if (max_regno > regno_calls_num)
+    {
+      regno_calls = ira_reallocate (regno_calls,
+				    max_regno * sizeof (VEC(rtx, heap) *));
+      memset (regno_calls + regno_calls_num, 0,
+	      (max_regno - regno_calls_num) * sizeof (VEC(rtx, heap) *));
+      regno_calls_num = max_regno;
+    }
+}
+
+/* The function removes NULL elements from vectors containing calls
+   intersected by pseudo-registers.  */
+static void
+compress_calls (void)
+{
+  int regno, curr, length, last;
+  rtx *allocno_calls;
+
+  for (regno = 0; regno < regno_calls_num; regno++)
+    {
+      allocno_calls = VEC_address (rtx, regno_calls [regno]);
+      length = VEC_length (rtx, regno_calls [regno]);
+      for (last = curr = 0; curr < length; curr++)
+	if (allocno_calls [curr] != NULL_RTX)
+	  allocno_calls [last++] = allocno_calls [curr];
+      VEC_truncate (rtx, regno_calls [regno], last);
+    }
+}
+
 /* The function adds CALL to REGNO's vector of intersected calls.  */
 int
 add_regno_call (int regno, rtx call)
@@ -351,11 +474,11 @@ initiate_allocnos (void)
    LOOP_TREE_NODE.  Add the allocno to the list of allocnos with the
    same regno if ! CAP_P.  */
 allocno_t
-create_allocno (int regno, int cap_p, struct ira_loop_tree_node *loop_tree_node)
+create_allocno (int regno, int cap_p, loop_tree_node_t loop_tree_node)
 {
   allocno_t a;
 
-  a = ira_allocate (sizeof (struct allocno));
+  a = pool_alloc (allocno_pool);
   ALLOCNO_REGNO (a) = regno;
   ALLOCNO_LOOP_TREE_NODE (a) = loop_tree_node;
   if (! cap_p)
@@ -371,8 +494,11 @@ create_allocno (int regno, int cap_p, st
   ALLOCNO_CAP_MEMBER (a) = NULL;
   ALLOCNO_NUM (a) = allocnos_num;
   ALLOCNO_CONFLICT_ALLOCNO_VEC (a) = NULL;
-  ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE (a) = 0;
+  ALLOCNO_CONFLICT_ALLOCNOS_NUM (a) = 0;
+  ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM (a) = 0;
   CLEAR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a));
+  CLEAR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
+  ALLOCNO_NREFS (a) = 0;
   ALLOCNO_FREQ (a) = 1;
   ALLOCNO_HARD_REGNO (a) = -1;
   ALLOCNO_CALL_FREQ (a) = 0;
@@ -380,7 +506,10 @@ create_allocno (int regno, int cap_p, st
   ALLOCNO_CALLS_CROSSED_START (a) = -1;
 #ifdef STACK_REGS
   ALLOCNO_NO_STACK_REG_P (a) = FALSE;
+  ALLOCNO_TOTAL_NO_STACK_REG_P (a) = FALSE;
 #endif
+  ALLOCNO_MEM_OPTIMIZED_DEST (a) = NULL;
+  ALLOCNO_MEM_OPTIMIZED_DEST_P (a) = FALSE;
   ALLOCNO_IN_GRAPH_P (a) = FALSE;
   ALLOCNO_ASSIGNED_P (a) = FALSE;
   ALLOCNO_MAY_BE_SPILLED_P (a) = FALSE;
@@ -388,23 +517,39 @@ create_allocno (int regno, int cap_p, st
   ALLOCNO_COPIES (a) = NULL;
   ALLOCNO_HARD_REG_COSTS (a) = NULL;
   ALLOCNO_CONFLICT_HARD_REG_COSTS (a) = NULL;
-  ALLOCNO_CURR_HARD_REG_COSTS (a) = NULL;
-  ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (a) = NULL;
+  ALLOCNO_UPDATED_HARD_REG_COSTS (a) = NULL;
+  ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) = NULL;
   ALLOCNO_LEFT_CONFLICTS_NUM (a) = -1;
   ALLOCNO_COVER_CLASS (a) = NO_REGS;
   ALLOCNO_BEST_CLASS (a) = NO_REGS;
   ALLOCNO_COVER_CLASS_COST (a) = 0;
-  ALLOCNO_MEMORY_COST (a) = 0;
+  ALLOCNO_UPDATED_MEMORY_COST (a) = 0;
   ALLOCNO_NEXT_BUCKET_ALLOCNO (a) = NULL;
   ALLOCNO_PREV_BUCKET_ALLOCNO (a) = NULL;
   ALLOCNO_FIRST_COALESCED_ALLOCNO (a) = a;
   ALLOCNO_NEXT_COALESCED_ALLOCNO (a) = a;
+  ALLOCNO_LIVE_RANGES (a) = NULL;
   VARRAY_PUSH_GENERIC_PTR (allocno_varray, a);
   allocnos = (allocno_t *) &VARRAY_GENERIC_PTR (allocno_varray, 0);
   allocnos_num = VARRAY_ACTIVE_SIZE (allocno_varray);
   return a;
 }
 
+/* The function returns index of A2 in conflict vector of A1, or -1 if
+   it is absent.  */
+int
+allocno_conflict_index (allocno_t a1, allocno_t a2)
+{
+  int i;
+  allocno_t conflict_allocno, *allocno_vec;
+
+  allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a1);
+  for (i = 0; (conflict_allocno = allocno_vec [i]) != NULL; i++)
+    if (conflict_allocno == a2)
+      return i;
+  return -1;
+}
+
 /* The function allocates conflict vector of A for NUM allocnos.  */
 void
 allocate_allocno_conflicts (allocno_t a, int num)
@@ -413,7 +558,8 @@ allocate_allocno_conflicts (allocno_t a,
   ALLOCNO_CONFLICT_ALLOCNO_VEC (a)
     = ira_allocate (sizeof (allocno_t) * (num + 1));
   ALLOCNO_CONFLICT_ALLOCNO_VEC (a) [0] = NULL;
-  ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE (a) = 0;
+  ALLOCNO_CONFLICT_ALLOCNOS_NUM (a) = 0;
+  ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM (a) = 0;
   ALLOCNO_CONFLICT_ALLOCNO_VEC_SIZE (a) = num;
 }
 
@@ -433,31 +579,33 @@ check_allocno_conflict_vec (allocno_t a,
   vec = ira_allocate (sizeof (allocno_t) * (size + 1));
   memcpy (vec, ALLOCNO_CONFLICT_ALLOCNO_VEC (a),
 	  sizeof (allocno_t)
-	  * (ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE (a) + 1));
+	  * (ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM (a) + 1));
   ira_free (ALLOCNO_CONFLICT_ALLOCNO_VEC (a));
   ALLOCNO_CONFLICT_ALLOCNO_VEC (a) = vec;
   ALLOCNO_CONFLICT_ALLOCNO_VEC_SIZE (a) = size;
 }
 
-/* The function adds A1 to conflict vector of A2 and vise versa.  */
+/* The function adds A2 to conflict vector of A1.  */
 static void
-add_allocno_conflict (allocno_t a1, allocno_t a2)
+add_to_allocno_conflict_vec (allocno_t a1, allocno_t a2)
 {
-  int size1, size2;
-  allocno_t *vec1, *vec2;
+  int size;
+  allocno_t *vec;
 
-  size1 = ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE (a1);
-  size2 = ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE (a2);
-  check_allocno_conflict_vec (a1, size1 + 1);
-  check_allocno_conflict_vec (a2, size2 + 1);
-  vec1 = ALLOCNO_CONFLICT_ALLOCNO_VEC (a1);
-  vec2 = ALLOCNO_CONFLICT_ALLOCNO_VEC (a2);
-  vec1 [size1] = a2;
-  vec2 [size2] = a1;
-  vec1 [size1 + 1] = NULL;
-  vec2 [size2 + 1] = NULL;
-  ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE (a1)++;
-  ALLOCNO_CONFLICT_ALLOCNO_VEC_ACTIVE_SIZE (a2)++;
+  size = ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM (a1);
+  check_allocno_conflict_vec (a1, size + 1);
+  vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a1);
+  vec [size] = a2;
+  vec [size + 1] = NULL;
+  ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM (a1)++;
+}
+
+/* The function adds A1 to conflict vector of A2 and vise versa.  */
+void
+add_allocno_conflict (allocno_t a1, allocno_t a2)
+{
+  add_to_allocno_conflict_vec (a1, a2);
+  add_to_allocno_conflict_vec (a2, a1);
 }
 
 /* This recursive function outputs allocno A and if it is cap the
@@ -485,12 +633,8 @@ print_expanded_allocno (allocno_t a)
 static allocno_t
 create_cap_allocno (allocno_t a)
 {
-  int i, regno, hard_regs_num, conflicts_num;
-  int *reg_costs, *conflict_reg_costs;
-  basic_block bb;
-  allocno_t cap, conflict_allocno, conflict_father_allocno;
-  allocno_t *allocno_vec;
-  struct ira_loop_tree_node *father;
+  allocno_t cap;
+  loop_tree_node_t father;
 
   ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (a) == a
 	      && ALLOCNO_NEXT_COALESCED_ALLOCNO (a) == a);
@@ -502,7 +646,39 @@ create_cap_allocno (allocno_t a)
   ALLOCNO_BEST_CLASS (cap) = ALLOCNO_BEST_CLASS (a);
   ALLOCNO_AVAILABLE_REGS_NUM (cap) = ALLOCNO_AVAILABLE_REGS_NUM (a);
   ALLOCNO_CAP_MEMBER (cap) = a;
-  hard_regs_num = class_hard_regs_num [ALLOCNO_COVER_CLASS (a)];
+  bitmap_set_bit (father->mentioned_allocnos, ALLOCNO_NUM (cap));
+  ALLOCNO_CAP (a) = cap;
+  ALLOCNO_COVER_CLASS_COST (cap) = ALLOCNO_COVER_CLASS_COST (a);
+  ALLOCNO_UPDATED_MEMORY_COST (cap) = ALLOCNO_UPDATED_MEMORY_COST (a);
+  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
+    {
+      fprintf (ira_dump_file, "    Creating cap ");
+      print_expanded_allocno (cap);
+      fprintf (ira_dump_file, "\n");
+    }
+  return cap;
+}
+
+/* The function propagate info obtained during conflicts building to
+   CAP.  */
+static void
+propagate_info_to_cap (allocno_t cap)
+{
+  int i, regno, hard_regs_num, conflicts_num;
+  int *reg_costs, *conflict_reg_costs;
+  allocno_t a, conflict_allocno, conflict_father_allocno;
+  allocno_t another_a, father_a;
+  allocno_t *allocno_vec;
+  loop_tree_node_t father;
+  copy_t cp, next_cp;
+
+  ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (cap) == cap
+	      && ALLOCNO_NEXT_COALESCED_ALLOCNO (cap) == cap
+	      && ALLOCNO_CONFLICT_ALLOCNO_VEC (cap) == NULL
+	      && ALLOCNO_CALLS_CROSSED_NUM (cap) == 0);
+  a = ALLOCNO_CAP_MEMBER (cap);
+  father = ALLOCNO_LOOP_TREE_NODE (cap);
+  hard_regs_num = class_hard_regs_num [ALLOCNO_COVER_CLASS (cap)];
   ALLOCNO_HARD_REG_COSTS (cap) = reg_costs
     = ira_allocate (hard_regs_num * sizeof (int));
   memcpy (reg_costs, ALLOCNO_HARD_REG_COSTS (a), hard_regs_num * sizeof (int));
@@ -510,61 +686,170 @@ create_cap_allocno (allocno_t a)
     = ira_allocate (hard_regs_num * sizeof (int));
   memcpy (conflict_reg_costs, ALLOCNO_CONFLICT_HARD_REG_COSTS (a),
 	  hard_regs_num * sizeof (int));
-  ALLOCNO_CURR_HARD_REG_COSTS (cap)
+  ALLOCNO_UPDATED_HARD_REG_COSTS (cap)
     = ira_allocate (hard_regs_num * sizeof (int));
-  ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (cap)
+  ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (cap)
     = ira_allocate (hard_regs_num * sizeof (int));
-  /* ??? costs, call_p etc.  */
-  bitmap_set_bit (father->mentioned_allocnos, ALLOCNO_NUM (cap));
-  ALLOCNO_CAP (a) = cap;
-  ALLOCNO_AVAILABLE_REGS_NUM (cap) = ALLOCNO_AVAILABLE_REGS_NUM (a);
-  ALLOCNO_COVER_CLASS_COST (cap) = ALLOCNO_COVER_CLASS_COST (a);
-  ALLOCNO_MEMORY_COST (cap) = ALLOCNO_MEMORY_COST (a);
+  ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a);
   ALLOCNO_FREQ (cap) = ALLOCNO_FREQ (a);
   ALLOCNO_CALL_FREQ (cap) = ALLOCNO_CALL_FREQ (a);
   IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (cap),
 		    ALLOCNO_CONFLICT_HARD_REGS (a));
+  IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (cap),
+		    ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
   ALLOCNO_CALLS_CROSSED_NUM (cap) = ALLOCNO_CALLS_CROSSED_NUM (a);
   ALLOCNO_CALLS_CROSSED_START (cap) = ALLOCNO_CALLS_CROSSED_START (a);
 #ifdef STACK_REGS
   ALLOCNO_NO_STACK_REG_P (cap) = ALLOCNO_NO_STACK_REG_P (a);
+  ALLOCNO_TOTAL_NO_STACK_REG_P (cap) = ALLOCNO_TOTAL_NO_STACK_REG_P (a);
 #endif
+  /* Add copies to the cap.  */
+  for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp)
+    {
+      if (cp->first == a)
+	{
+	  next_cp = cp->next_first_allocno_copy;
+	  another_a = cp->second;
+	}
+      else if (cp->second == a)
+	{
+	  next_cp = cp->next_second_allocno_copy;
+	  another_a = cp->first;
+	}
+      else
+	gcc_unreachable ();
+      father_a = father->regno_allocno_map [ALLOCNO_REGNO (another_a)];
+      if (father_a == NULL)
+	father_a = ALLOCNO_CAP (another_a);
+      if (father_a != NULL)
+	/* Upper level allocno might be not existing because it is
+	   not mentioned or lived on the border.  It is just
+	   living on bb start of the loop.  */
+	add_allocno_copy (cap, father_a, cp->freq, cp->move_insn,
+			  cp->loop_tree_node);
+    }
   allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
-  for (conflicts_num = i = 0;
-       (conflict_allocno = allocno_vec [i]) != NULL;
-       i++)
-    conflicts_num++;
-  allocate_allocno_conflicts (cap, conflicts_num);
-  for (conflicts_num = i = 0;
-       (conflict_allocno = allocno_vec [i]) != NULL;
-       i++)
-    {
-      regno = ALLOCNO_REGNO (conflict_allocno);
-      conflict_father_allocno = father->regno_allocno_map [regno];
-      if (conflict_father_allocno == NULL)
-	conflict_father_allocno = ALLOCNO_CAP (conflict_allocno);
-      if (conflict_father_allocno != NULL)
-	add_allocno_conflict (cap, conflict_father_allocno);
+  if (allocno_vec != NULL)
+    {
+      conflicts_num = 0;
+      for (i = 0;
+	   (conflict_allocno = allocno_vec [i]) != NULL;
+	   i++)
+	conflicts_num++;
+      allocate_allocno_conflicts (cap, conflicts_num);
+      for (conflicts_num = i = 0;
+	   (conflict_allocno = allocno_vec [i]) != NULL;
+	   i++)
+	{
+	  regno = ALLOCNO_REGNO (conflict_allocno);
+	  conflict_father_allocno = father->regno_allocno_map [regno];
+	  if (conflict_father_allocno == NULL)
+	    conflict_father_allocno = ALLOCNO_CAP (conflict_allocno);
+	  if (conflict_father_allocno != NULL
+	      && (ALLOCNO_CONFLICT_ALLOCNO_VEC (conflict_father_allocno)
+		  != NULL))
+	    add_allocno_conflict (cap, conflict_father_allocno);
+	}
     }
-  if (ira_dump_file != NULL)
+  if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
     {
-      fprintf (ira_dump_file, "  Creating cap ");
+      fprintf (ira_dump_file, "    Propagate info to cap ");
       print_expanded_allocno (cap);
-      fprintf (ira_dump_file, "\n    Conflicts:");
       allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (cap);
-      for (i = 0; (conflict_allocno = allocno_vec [i]) != NULL; i++)
+      if (allocno_vec != NULL)
 	{
-	  fprintf (ira_dump_file, " a%d(r%d,", ALLOCNO_NUM (conflict_allocno),
-		   ALLOCNO_REGNO (conflict_allocno));
-	  if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_allocno)->bb) != NULL)
-	    fprintf (ira_dump_file, "b%d)", bb->index);
-	  else
-	    fprintf (ira_dump_file, "l%d)",
-		     ALLOCNO_LOOP_TREE_NODE (conflict_allocno)->loop->num);
+	  fprintf (ira_dump_file, "\n      Conflicts:");
+	  for (i = 0; (conflict_allocno = allocno_vec [i]) != NULL; i++)
+	    {
+	      fprintf (ira_dump_file, " a%d(r%d,",
+		       ALLOCNO_NUM (conflict_allocno),
+		       ALLOCNO_REGNO (conflict_allocno));
+	      ira_assert
+		(ALLOCNO_LOOP_TREE_NODE (conflict_allocno)->bb == NULL);
+	      fprintf (ira_dump_file, "l%d)",
+		       ALLOCNO_LOOP_TREE_NODE (conflict_allocno)->loop->num);
+	    }
 	}
       fprintf (ira_dump_file, "\n");
     }
-  return cap;
+}
+
+
+/* Create and return allocno live range with give attributes.  */
+allocno_live_range_t
+create_allocno_live_range (allocno_t a, int start, int finish,
+			   allocno_live_range_t next)
+{
+  allocno_live_range_t p;
+
+  p = pool_alloc (allocno_live_range_pool);
+  p->allocno = a;
+  p->start = start;
+  p->finish = finish;
+  p->next = next;
+  return p;
+}
+
+/* Create and return allocno live range with give attributes.  */
+allocno_live_range_t
+copy_allocno_live_range (allocno_live_range_t r)
+{
+  allocno_live_range_t p;
+
+  p = pool_alloc (allocno_live_range_pool);
+  *p = *r;
+  return p;
+}
+
+/* Create and return allocno live range with give attributes.  */
+allocno_live_range_t
+copy_allocno_live_range_list (allocno_live_range_t r)
+{
+  allocno_live_range_t p, first, last;
+
+  if (r == NULL)
+    return NULL;
+  for (first = last = NULL; r != NULL; r = r->next)
+    {
+      p = copy_allocno_live_range (r);
+      if (first == NULL)
+	first = p;
+      else
+	last->next = p;
+      last = p;
+    }
+  return first;
+}
+
+/* Free allocno live range R.  */
+void
+finish_allocno_live_range (allocno_live_range_t r)
+{
+  pool_free (allocno_live_range_pool, r);
+}
+
+/* The function frees memory allocated for allocno A.  */
+static void
+finish_allocno (allocno_t a)
+{
+  allocno_live_range_t r, next_r;
+
+  if (ALLOCNO_CONFLICT_ALLOCNO_VEC (a) != NULL)
+    ira_free (ALLOCNO_CONFLICT_ALLOCNO_VEC (a));
+  if (ALLOCNO_HARD_REG_COSTS (a) != NULL)
+    ira_free (ALLOCNO_HARD_REG_COSTS (a));
+  if (ALLOCNO_CONFLICT_HARD_REG_COSTS (a) != NULL)
+    ira_free (ALLOCNO_CONFLICT_HARD_REG_COSTS (a));
+  if (ALLOCNO_UPDATED_HARD_REG_COSTS (a) != NULL)
+    ira_free (ALLOCNO_UPDATED_HARD_REG_COSTS (a));
+  if (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a) != NULL)
+    ira_free (ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a));
+  for (r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = next_r)
+    {
+      next_r = r->next;
+      finish_allocno_live_range (r);
+    }
+  pool_free (allocno_pool, a);
 }
 
 /* The function frees memory allocated for all allocnos.  */
@@ -572,23 +857,9 @@ static void
 finish_allocnos (void)
 {
   int i;
-  allocno_t a;
 
   for (i = 0; i < allocnos_num; i++)
-    {
-      a = allocnos [i];
-      if (ALLOCNO_CONFLICT_ALLOCNO_VEC (a) != NULL)
-	ira_free (ALLOCNO_CONFLICT_ALLOCNO_VEC (a));
-      if (ALLOCNO_HARD_REG_COSTS (a) != NULL)
-	ira_free (ALLOCNO_HARD_REG_COSTS (a));
-      if (ALLOCNO_CONFLICT_HARD_REG_COSTS (a) != NULL)
-	ira_free (ALLOCNO_CONFLICT_HARD_REG_COSTS (a));
-      if (ALLOCNO_CURR_HARD_REG_COSTS (a) != NULL)
-	ira_free (ALLOCNO_CURR_HARD_REG_COSTS (a));
-      if (ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (a) != NULL)
-	ira_free (ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (a));
-      ira_free (a);
-    }
+    finish_allocno (allocnos [i]);
   ira_free (regno_allocno_map);
   VARRAY_FREE (allocno_varray);
 }
@@ -608,25 +879,146 @@ initiate_copies (void)
   copies_num = 0;
 }
 
-/* The function creates and returns copy of allocnos FIRST and SECOND
-   with frequency FREQ and move insn MOVE_INSN.  */
+/* The function creates and returns created in LOOP_TREE_NODE copy of
+   allocnos FIRST and SECOND with frequency FREQ, move insn
+   MOVE_INSN.  */
 copy_t
-create_copy (allocno_t first, allocno_t second, int freq, rtx move_insn)
+create_copy (allocno_t first, allocno_t second, int freq, rtx move_insn,
+	     loop_tree_node_t loop_tree_node)
 {
   copy_t cp;
 
-  cp = ira_allocate (sizeof (struct allocno_copy));
+  cp = pool_alloc (copy_pool);
   cp->num = copies_num;
   cp->first = first;
   cp->second = second;
   cp->freq = freq;
   cp->move_insn = move_insn;
+  cp->loop_tree_node = loop_tree_node;
   VARRAY_PUSH_GENERIC_PTR (copy_varray, cp);
   copies = (copy_t *) &VARRAY_GENERIC_PTR (copy_varray, 0);
   copies_num = VARRAY_ACTIVE_SIZE (copy_varray);
   return cp;
 }
 
+/* The function attaches copy CP to allocnos involved into the copy.  */
+void
+add_allocno_copy_to_list (copy_t cp)
+{
+  allocno_t first = cp->first, second = cp->second;
+
+  cp->prev_first_allocno_copy = NULL;
+  cp->prev_second_allocno_copy = NULL;
+  cp->next_first_allocno_copy = ALLOCNO_COPIES (first);
+  if (cp->next_first_allocno_copy != NULL)
+    {
+      if (cp->next_first_allocno_copy->first == first)
+	cp->next_first_allocno_copy->prev_first_allocno_copy = cp;
+      else
+	cp->next_first_allocno_copy->prev_second_allocno_copy = cp;
+    }
+  cp->next_second_allocno_copy = ALLOCNO_COPIES (second);
+  if (cp->next_second_allocno_copy != NULL)
+    {
+      if (cp->next_second_allocno_copy->second == second)
+	cp->next_second_allocno_copy->prev_second_allocno_copy = cp;
+      else
+	cp->next_second_allocno_copy->prev_first_allocno_copy = cp;
+    }
+  ALLOCNO_COPIES (first) = cp;
+  ALLOCNO_COPIES (second) = cp;
+}
+
+/* The function detaches copy CP from allocnos involved into the copy.  */
+void
+remove_allocno_copy_from_list (copy_t cp)
+{
+  allocno_t first = cp->first, second = cp->second;
+  copy_t prev, next;
+
+  next = cp->next_first_allocno_copy;
+  prev = cp->prev_first_allocno_copy;
+  if (prev == NULL)
+    ALLOCNO_COPIES (first) = next;
+  else if (prev->first == first)
+    prev->next_first_allocno_copy = next;
+  else
+    prev->next_second_allocno_copy = next;
+  if (next != NULL)
+    {
+      if (next->first == first)
+	next->prev_first_allocno_copy = prev;
+      else
+	next->prev_second_allocno_copy = prev;
+    }
+  cp->prev_first_allocno_copy = cp->next_first_allocno_copy = NULL;
+
+  next = cp->next_second_allocno_copy;
+  prev = cp->prev_second_allocno_copy;
+  if (prev == NULL)
+    ALLOCNO_COPIES (second) = next;
+  else if (prev->second == second)
+    prev->next_second_allocno_copy = next;
+  else
+    prev->next_first_allocno_copy = next;
+  if (next != NULL)
+    {
+      if (next->second == second)
+	next->prev_second_allocno_copy = prev;
+      else
+	next->prev_first_allocno_copy = prev;
+    }
+  cp->prev_second_allocno_copy = cp->next_second_allocno_copy = NULL;
+}
+
+/* The function makes copy CP a canonical copy where number of the
+   first allocno is less than the second one.  */
+void
+swap_allocno_copy_ends_if_necessary (copy_t cp)
+{
+  allocno_t temp;
+  copy_t temp_cp;
+
+  if (ALLOCNO_NUM (cp->first) <= ALLOCNO_NUM (cp->second))
+    return;
+
+  temp = cp->first;
+  cp->first = cp->second;
+  cp->second = temp;
+
+  temp_cp = cp->prev_first_allocno_copy;
+  cp->prev_first_allocno_copy = cp->prev_second_allocno_copy;
+  cp->prev_second_allocno_copy = temp_cp;
+
+  temp_cp = cp->next_first_allocno_copy;
+  cp->next_first_allocno_copy = cp->next_second_allocno_copy;
+  cp->next_second_allocno_copy = temp_cp;
+}
+
+/* The function creates and returns new copy of allocnos FIRST and
+   SECOND with frequency FREQ corresponding to move insn INSN (if
+   any) and originated from LOOP_TREE_NODE.  */
+copy_t
+add_allocno_copy (allocno_t first, allocno_t second, int freq, rtx insn,
+		  loop_tree_node_t loop_tree_node)
+{
+  copy_t cp;
+
+  cp = create_copy (first, second, freq, insn, loop_tree_node);
+  ira_assert (first != NULL && second != NULL);
+  add_allocno_copy_to_list (cp);
+  swap_allocno_copy_ends_if_necessary (cp);
+  return cp;
+}
+
+/* The function frees memory allocated for copy CP.  */
+static void
+finish_copy (copy_t cp)
+{
+  pool_free (copy_pool, cp);
+}
+
+
 /* The function frees memory allocated for all copies.  */
 static void
 finish_copies (void)
@@ -634,38 +1026,60 @@ finish_copies (void)
   int i;
 
   for (i = 0; i < copies_num; i++)
-    ira_free (copies [i]);
+    finish_copy (copies [i]);
   VARRAY_FREE (copy_varray);
 }
 
 
 
-/* The current loop tree node.  */
-struct ira_loop_tree_node *ira_curr_loop_tree_node;
+/* The current loop tree node and its map.  */
+loop_tree_node_t ira_curr_loop_tree_node;
+allocno_t *ira_curr_regno_allocno_map;
 
 /* The recursive function traverses loop tree node with root LOOP_NODE
    calling non-null functions PREORDER_FUNC and POSTORDER_FUNC
    correspondingly in preorder and postorder.  The function sets up
-   IRA_CURR_LOOP_TREE_NODE.  */
+   IRA_CURR_LOOP_TREE_NODE.  If BB_FIRST_P, BB of LOOP_NODE is
+   processed before its subloops.  */
 void
-traverse_loop_tree (struct ira_loop_tree_node *loop_node,
-		    void (*preorder_func) (struct ira_loop_tree_node *),
-		    void (*postorder_func) (struct ira_loop_tree_node *))
+traverse_loop_tree (int bb_first_p, loop_tree_node_t loop_node,
+		    void (*preorder_func) (loop_tree_node_t),
+		    void (*postorder_func) (loop_tree_node_t))
 {
-  struct ira_loop_tree_node *subloop_node;
+  loop_tree_node_t subloop_node;
 
   if (loop_node->bb == NULL)
-    ira_curr_loop_tree_node = loop_node;
+    {
+      ira_curr_loop_tree_node = loop_node;
+      ira_curr_regno_allocno_map = ira_curr_loop_tree_node->regno_allocno_map;
+    }
   if (preorder_func != NULL)
     (*preorder_func) (loop_node);
   
   for (subloop_node = loop_node->inner;
        subloop_node != NULL;
        subloop_node = subloop_node->next)
-    {
-      traverse_loop_tree (subloop_node, preorder_func, postorder_func);
-      ira_curr_loop_tree_node = loop_node;
-    }
+    if (! bb_first_p || subloop_node->bb != NULL)
+      {
+	traverse_loop_tree (bb_first_p, subloop_node,
+			    preorder_func, postorder_func);
+	ira_curr_loop_tree_node = loop_node;
+	ira_curr_regno_allocno_map
+	  = ira_curr_loop_tree_node->regno_allocno_map;
+      }
+
+  if (bb_first_p)
+    for (subloop_node = loop_node->inner;
+	 subloop_node != NULL;
+	 subloop_node = subloop_node->next)
+      if (subloop_node->bb == NULL)
+	{
+	  traverse_loop_tree (bb_first_p, subloop_node,
+			      preorder_func, postorder_func);
+	  ira_curr_loop_tree_node = loop_node;
+	  ira_curr_regno_allocno_map
+	    = ira_curr_loop_tree_node->regno_allocno_map;
+	}
 
   if (postorder_func != NULL)
     (*postorder_func) (loop_node);
@@ -697,6 +1111,7 @@ create_insn_allocnos (rtx x, int output_
 	  if ((a = ira_curr_loop_tree_node->regno_allocno_map [regno]) == NULL)
 	    a = create_allocno (regno, FALSE, ira_curr_loop_tree_node);
 	  
+	  ALLOCNO_NREFS (a)++;
 	  ALLOCNO_FREQ (a) += REG_FREQ_FROM_BB (curr_bb);
 	  bitmap_set_bit (ira_curr_loop_tree_node->mentioned_allocnos,
 			  ALLOCNO_NUM (a));
@@ -744,7 +1159,7 @@ create_insn_allocnos (rtx x, int output_
    living in basic blocks represented by the corresponding loop tree
    node BB_NODE.  */
 static void
-create_bb_allocnos (struct ira_loop_tree_node *bb_node)
+create_bb_allocnos (loop_tree_node_t bb_node)
 {
   basic_block bb;
   rtx insn;
@@ -793,7 +1208,7 @@ create_loop_allocnos (edge e)
    living in loop represented by the corresponding loop tree node
    LOOP_NODE.  */
 static void
-create_loop_tree_node_allocnos (struct ira_loop_tree_node *loop_node)
+create_loop_tree_node_allocnos (loop_tree_node_t loop_node)
 {
   if (loop_node->bb != NULL)
     create_bb_allocnos (loop_node);
@@ -823,20 +1238,27 @@ create_allocnos (void)
 {
   int i;
   allocno_t a, father_a;
-  struct ira_loop_tree_node *father;
+  loop_tree_node_t father;
 
-  traverse_loop_tree (ira_loop_tree_root, create_loop_tree_node_allocnos, NULL);
+  /* We need to process BB first to correctly link allocnos by
+     next_regno_allocno field.  */
+  traverse_loop_tree (TRUE, ira_loop_tree_root,
+		      create_loop_tree_node_allocnos, NULL);
   if (flag_ira_algorithm != IRA_ALGORITHM_REGIONAL
       && flag_ira_algorithm != IRA_ALGORITHM_MIXED)
     return;
-  /* Propagate frequencies for regional register allocator.  */
+  /* Propagate number of references and frequencies for regional
+     register allocator.  */
   for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
     for (a = regno_allocno_map [i];
 	 a != NULL;
 	 a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
       if ((father = ALLOCNO_LOOP_TREE_NODE (a)->father) != NULL
 	  && (father_a = father->regno_allocno_map [i]) != NULL)
-	ALLOCNO_FREQ (father_a) += ALLOCNO_FREQ (a);
+	{
+	  ALLOCNO_NREFS (father_a) += ALLOCNO_NREFS (a);
+	  ALLOCNO_FREQ (father_a) += ALLOCNO_FREQ (a);
+	}
 }
 
 
@@ -847,13 +1269,11 @@ static bitmap local_allocnos_bitmap;
 /* The function creates caps representing allocnos living only inside
    the loop given by LOOP_NODE on higher loop level.  */
 static void
-create_loop_tree_node_caps (struct ira_loop_tree_node *loop_node)
+create_loop_tree_node_caps (loop_tree_node_t loop_node)
 {
   unsigned int i;
   bitmap_iterator bi;
-  allocno_t a, cap, another_a, father_a;
-  copy_t cp, next_cp;
-  struct ira_loop_tree_node *father;
+  loop_tree_node_t father;
 
   if (loop_node->bb != NULL || loop_node == ira_loop_tree_root)
     return;
@@ -863,60 +1283,587 @@ create_loop_tree_node_caps (struct ira_l
   EXECUTE_IF_SET_IN_BITMAP (local_allocnos_bitmap, 0, i, bi)
     if (father->regno_allocno_map [ALLOCNO_REGNO (allocnos [i])] == NULL)
       create_cap_allocno (allocnos [i]);
-  EXECUTE_IF_SET_IN_BITMAP (local_allocnos_bitmap, 0, i, bi)
+}
+
+/* The function propagate info to caps mentioned in LOOP_NODE.  */
+static void
+propagate_info_to_loop_tree_node_caps (loop_tree_node_t loop_node)
+{
+  unsigned int i;
+  bitmap_iterator bi;
+  allocno_t a;
+
+  if (loop_node->bb != NULL)
+    return;
+  EXECUTE_IF_SET_IN_BITMAP (loop_node->mentioned_allocnos, 0, i, bi)
     {
       a = allocnos [i];
-      cap = ALLOCNO_CAP (a);
-      if (cap == NULL)
-	continue;
-      for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp)
+      if (ALLOCNO_CAP_MEMBER (a) != NULL)
+	propagate_info_to_cap (a);
+    }
+}
+
+
+
+/* The function merges ranges R1 and R2 and returns the result.  */
+static allocno_live_range_t 
+merge_ranges (allocno_live_range_t r1, allocno_live_range_t r2)
+{
+  allocno_live_range_t first, last, temp;
+
+  if (r1 == NULL)
+    return r2;
+  if (r2 == NULL)
+    return r1;
+  for (first = last = NULL; r1 != NULL && r2 != NULL;)
+    {
+      if (r1->start < r2->start)
 	{
-	  if (cp->first == a)
+	  temp = r1;
+	  r1 = r2;
+	  r2 = temp;
+	}
+      if (r1->start <= r2->finish + 1)
+	{
+	  /* Intersected ranges: merge r1 and r2 into r1.  */
+	  r1->start = r2->start;
+	  if (r1->finish < r2->finish)
+	    r1->finish = r2->finish;
+	  temp = r2;
+	  r2 = r2->next;
+	  finish_allocno_live_range (temp);
+	  if (r2 == NULL)
 	    {
-	      next_cp = cp->next_first_allocno_copy;
-	      another_a = cp->second;
+	      /* To try to merge with subsequent ranges in r1.  */
+	      r2 = r1->next;
+	      r1->next = NULL;
 	    }
-	  else if (cp->second == a)
+	}
+      else
+	{
+	  /* Add r1 to the result.  */
+	  if (first == NULL)
+	    first = last = r1;
+	  else
 	    {
-	      next_cp = cp->next_second_allocno_copy;
-	      another_a = cp->first;
+	      last->next = r1;
+	      last = r1;
+	    }
+	  r1 = r1->next;
+	  if (r1 == NULL)
+	    {
+	      /* To try to merge with subsequent ranges in r2.  */
+	      r1 = r2->next;
+	      r2->next = NULL;
 	    }
-	  else
-	    gcc_unreachable ();
-	  father_a = father->regno_allocno_map [ALLOCNO_REGNO (another_a)];
-	  if (father_a != NULL)
-	    /* Upper level allocno might be not existing because it is
-	       not mentioned or lived on the border.  It is just
-	       living on bb start of the loop.  */
-	    add_allocno_copy (cap, father_a, cp->freq, cp->move_insn);
 	}
     }
+  if (r1 != NULL)
+    {
+      if (first == NULL)
+	first = r1;
+      else
+	last->next = r1;
+      ira_assert (r1->next == NULL);
+    }
+  else if (r2 != NULL)
+    {
+      if (first == NULL)
+	first = r2;
+      else
+	last->next = r2;
+      ira_assert (r2->next == NULL);
+    }
+  else
+    ira_assert (last->next == NULL);
+  return first;
 }
 
-
+/* The function returns immediate common dominator of two loop tree
+   nodes N1 and N2.  */
+static loop_tree_node_t
+common_loop_tree_node_dominator (loop_tree_node_t n1, loop_tree_node_t n2)
+{
+  ira_assert (n1 != NULL && n2 != NULL);
+  if (n1 == n2)
+    return n1;
+  if (n1->level < n2->level)
+    return common_loop_tree_node_dominator (n1, n2->father);
+  else if (n1->level > n2->level)
+    return common_loop_tree_node_dominator (n1->father, n2);
+  else
+    return common_loop_tree_node_dominator (n1->father, n2->father);
+}
+
+/* Map: regno -> allocnos which will finally represent the regno for
+   IR with one region.  */
+static allocno_t *regno_top_level_allocno_map;
 
-#ifdef ENABLE_IRA_CHECKING
-/* The function checks that there are no coalesced allocnos.  */
+
+/* The function check conflicts A with allocnos from CONFLICT_VECT and
+   add them (more accurately corresponding final IR allocnos) if it is
+   necessary.  */
 static void
-check_coalesced_allocnos (void)
+check_and_add_conflicts (allocno_t a, allocno_t *conflict_vec)
 {
+  allocno_t conflict_a;
   int i;
-  allocno_t a;
 
+  for (i = 0; (conflict_a = conflict_vec [i]) != NULL; i++)
+    {
+      conflict_a
+	= regno_top_level_allocno_map [REGNO (ALLOCNO_REG (conflict_a))];
+      if (allocno_conflict_p (conflict_a, a)
+	  && allocno_conflict_index (conflict_a, a) < 0)
+	{
+	  ira_assert (allocno_conflict_index (a, conflict_a) < 0);
+	  add_to_allocno_conflict_vec (conflict_a, a);
+	  add_to_allocno_conflict_vec (a, conflict_a);
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	    fprintf (ira_dump_file,
+		     "      Add underlying conflict a%dr%d-a%dr%d\n",
+		     ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a)),
+		     ALLOCNO_NUM (conflict_a),\
+		     REGNO (ALLOCNO_REG (conflict_a)));
+	}
+    }
+}
+
+/* This recursive function checks and adds (if necessary) conflicts
+   with A processing conflicts of allocnos corresponding to A in
+   subloops.  If GO_DEEPER_P is false, the function stops to go deeper
+   in loop tree when allocno which will represent allocno in final IR
+   is achieved. */
+static void
+add_conflict_with_underlying_allocnos (allocno_t a,
+				       loop_tree_node_t loop_node,
+				       int go_deeper_p)
+{
+  loop_tree_node_t subloop_node;
+  allocno_t subloop_a;
+
+  for (subloop_node = loop_node->inner;
+       subloop_node != NULL;
+       subloop_node = subloop_node->next)
+    {
+      if (subloop_node->bb != NULL)
+	continue;
+      subloop_a = subloop_node->regno_allocno_map [ALLOCNO_REGNO (a)];
+      if (subloop_a == NULL)
+	continue;
+      if (! go_deeper_p
+	  && subloop_a == regno_top_level_allocno_map [REGNO (ALLOCNO_REG
+							      (subloop_a))])
+	continue;
+      check_and_add_conflicts (a, ALLOCNO_CONFLICT_ALLOCNO_VEC (subloop_a));
+      add_conflict_with_underlying_allocnos (a, subloop_node, go_deeper_p);
+    }
+}
+
+/* The function flattens IR.  In other words, the function transforms
+   IR as it were build with one region (without loops).  We could make
+   it much simpler by rebuilding IR with one region, but unfortunately
+   it takes a lot of time.  */
+void
+ira_flattening (int max_regno_before_emit, int max_point_before_emit)
+{
+  int i, j, k, free, propagate_p, stop_p, keep_p, hard_regs_num;
+  unsigned int n;
+  enum reg_class cover_class;
+  rtx call, *allocno_calls;
+  allocno_t a, father_a, conflict_a, first, second, node_first, node_second;
+  allocno_t dominator_a, *allocno_vec;
+  copy_t cp;
+  loop_tree_node_t father, node, dominator;
+  allocno_live_range_t r;
+  bitmap live_allocnos;
+  bitmap_iterator bi;
+
+  regno_top_level_allocno_map
+    = ira_allocate (max_reg_num () * sizeof (allocno_t));
+  memset (regno_top_level_allocno_map, 0, max_reg_num () * sizeof (allocno_t));
+  expand_calls ();
+  /* Updating accumulated attributes.  */
+  for (i = max_regno_before_emit - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+    {
+      propagate_p = FALSE;
+      for (a = regno_allocno_map [i];
+	   a != NULL;
+	   a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
+	{
+	  if (ALLOCNO_CAP_MEMBER (a) == NULL
+	      && (unsigned int) ALLOCNO_REGNO (a) != REGNO (ALLOCNO_REG (a))
+	      && ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+	    {
+	      allocno_calls = (VEC_address (rtx,
+					    regno_calls [ALLOCNO_REGNO (a)])
+			       + ALLOCNO_CALLS_CROSSED_START (a));
+	      for (j = ALLOCNO_CALLS_CROSSED_NUM (a) - 1; j >= 0; j--)
+		{
+		  call = allocno_calls [j];
+		  if (call == NULL_RTX)
+		    continue;
+		  add_regno_call (REGNO (ALLOCNO_REG (a)), call);
+		  allocno_calls [j] = NULL_RTX;
+		}
+	    }
+	  if ((father = ALLOCNO_LOOP_TREE_NODE (a)->father) == NULL
+	      || (father_a = father->regno_allocno_map [ALLOCNO_REGNO (a)])
+	      == NULL)
+	    {
+	      ALLOCNO_COPIES (a) = NULL;
+	      regno_top_level_allocno_map [REGNO (ALLOCNO_REG (a))] = a;
+	      continue;
+	    }
+	  if (propagate_p)
+	    {
+	      COPY_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (father_a),
+				 ALLOCNO_CONFLICT_HARD_REGS (father_a));
+	      IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (father_a),
+				ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
+#ifdef STACK_REGS
+	      ALLOCNO_TOTAL_NO_STACK_REG_P (father_a)
+		= (ALLOCNO_NO_STACK_REG_P (father_a)
+		   || ALLOCNO_TOTAL_NO_STACK_REG_P (a));
+#endif
+	    }
+	  if (REGNO (ALLOCNO_REG (a)) == REGNO (ALLOCNO_REG (father_a)))
+	    {
+	      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+		{
+		  fprintf (ira_dump_file,
+			   "      Moving ranges of a%dr%d to a%dr%d: ",
+			   ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a)),
+			   ALLOCNO_NUM (father_a),
+			   REGNO (ALLOCNO_REG (father_a)));
+		  print_live_range_list (ira_dump_file,
+					 ALLOCNO_LIVE_RANGES (a));
+		}
+	      ALLOCNO_LIVE_RANGES (father_a)
+		= merge_ranges (ALLOCNO_LIVE_RANGES (a),
+				ALLOCNO_LIVE_RANGES (father_a));
+	      ALLOCNO_LIVE_RANGES (a) = NULL;
+	      ALLOCNO_MEM_OPTIMIZED_DEST_P (father_a)
+		= (ALLOCNO_MEM_OPTIMIZED_DEST_P (father_a)
+		   || ALLOCNO_MEM_OPTIMIZED_DEST_P (a));
+	      continue;
+	    }
+	  propagate_p = TRUE;
+	  first = ALLOCNO_MEM_OPTIMIZED_DEST (a) == NULL ? NULL : a;
+	  for (;;)
+	    {
+	      if (first == NULL
+		  && ALLOCNO_MEM_OPTIMIZED_DEST (father_a) != NULL)
+		first = father_a;
+	      ALLOCNO_NREFS (father_a) -= ALLOCNO_NREFS (a);
+	      ALLOCNO_FREQ (father_a) -= ALLOCNO_FREQ (a);
+	      ALLOCNO_CALL_FREQ (father_a) -= ALLOCNO_CALL_FREQ (a);
+	      cover_class = ALLOCNO_COVER_CLASS (father_a);
+	      hard_regs_num = class_hard_regs_num [cover_class];
+	      for (j = 0; j < hard_regs_num; j++)
+		{
+		  ALLOCNO_HARD_REG_COSTS (father_a) [j]
+		    -= ALLOCNO_HARD_REG_COSTS (a) [j];
+		  ALLOCNO_CONFLICT_HARD_REG_COSTS (father_a) [j]
+		    -= ALLOCNO_CONFLICT_HARD_REG_COSTS (a) [j];
+		}
+	      ALLOCNO_COVER_CLASS_COST (father_a)
+		-= ALLOCNO_COVER_CLASS_COST (a);
+	      ALLOCNO_MEMORY_COST (father_a) -= ALLOCNO_MEMORY_COST (a);
+	      if ((father = ALLOCNO_LOOP_TREE_NODE (father_a)->father) == NULL
+		  || (father_a = (father->regno_allocno_map
+				  [ALLOCNO_REGNO (father_a)])) == NULL)
+		break;
+	    }
+	  if (first != NULL)
+	    {
+	      father_a = ALLOCNO_MEM_OPTIMIZED_DEST (first);
+	      dominator = common_loop_tree_node_dominator
+		          (ALLOCNO_LOOP_TREE_NODE (father_a),
+			   ALLOCNO_LOOP_TREE_NODE (first));
+	      dominator_a = dominator->regno_allocno_map [ALLOCNO_REGNO (a)];
+	      ira_assert (father_a != NULL);
+	      stop_p = first != a;
+	      /* Remember that exit can be to a grandparent (not only
+		 a parent) or a child of grandparent.  */
+	      for (first = a;;)
+		{
+		  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+		    {
+		      fprintf
+			(ira_dump_file,
+			 "      Coping ranges of a%dr%d to a%dr%d: ",
+			 ALLOCNO_NUM (first), REGNO (ALLOCNO_REG (first)),
+			 ALLOCNO_NUM (father_a),
+			 REGNO (ALLOCNO_REG (father_a)));
+		      print_live_range_list (ira_dump_file,
+					     ALLOCNO_LIVE_RANGES (first));
+		    }
+		  ALLOCNO_LIVE_RANGES (father_a)
+		    = merge_ranges (copy_allocno_live_range_list
+				    (ALLOCNO_LIVE_RANGES (first)),
+				    ALLOCNO_LIVE_RANGES (father_a));
+		  if (stop_p)
+		    break;
+		  father = ALLOCNO_LOOP_TREE_NODE (first)->father;
+		  ira_assert (father != NULL);
+		  first = father->regno_allocno_map [ALLOCNO_REGNO (a)];
+		  ira_assert (first != NULL);
+		  if (first == dominator_a)
+		    break;
+		}
+	    }
+	  ALLOCNO_COPIES (a) = NULL;
+	  regno_top_level_allocno_map [REGNO (ALLOCNO_REG (a))] = a;
+	}
+    }
+  /* Fix final allocnos attributes concerning calls.  */
+  compress_calls ();
   for (i = 0; i < allocnos_num; i++)
     {
       a = allocnos [i];
-      ira_assert (ALLOCNO_FIRST_COALESCED_ALLOCNO (a) == a
-		  && ALLOCNO_NEXT_COALESCED_ALLOCNO (a) == a);
+      if (a != regno_top_level_allocno_map [REGNO (ALLOCNO_REG (a))]
+	  || ALLOCNO_CAP_MEMBER (a) != NULL)
+	continue;
+      ALLOCNO_CALLS_CROSSED_START (a) = 0;
+      ALLOCNO_CALLS_CROSSED_NUM (a)
+	= VEC_length (rtx, regno_calls [REGNO (ALLOCNO_REG (a))]);
+    }
+  /* Mark copies for removing and change allocnos in copies.  */
+  for (i = 0; i < copies_num; i++)
+    {
+      cp = copies [i];
+      if (ALLOCNO_CAP_MEMBER (cp->first) != NULL
+	  || ALLOCNO_CAP_MEMBER (cp->second) != NULL)
+	{
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	    fprintf
+	      (ira_dump_file, "      Remove cp%d:%c%dr%d-%c%dr%d\n",
+	       cp->num, ALLOCNO_CAP_MEMBER (cp->first) != NULL ? 'c' : 'a',
+	       ALLOCNO_NUM (cp->first), REGNO (ALLOCNO_REG (cp->first)),
+	       ALLOCNO_CAP_MEMBER (cp->second) != NULL ? 'c' : 'a',
+	       ALLOCNO_NUM (cp->second), REGNO (ALLOCNO_REG (cp->second)));
+	  cp->loop_tree_node = NULL;
+	  continue;
+	}
+      first = regno_top_level_allocno_map [REGNO (ALLOCNO_REG (cp->first))];
+      second = regno_top_level_allocno_map [REGNO (ALLOCNO_REG (cp->second))];
+      node = cp->loop_tree_node;
+      if (node == NULL)
+	keep_p = TRUE; /* It copy generated in ira-emit.c.  */
+      else
+	{
+	  /* Check that the copy was not propagated from level on
+	     which we will have different pseudos.  */
+	  node_first = node->regno_allocno_map [ALLOCNO_REGNO (cp->first)];
+	  node_second = node->regno_allocno_map [ALLOCNO_REGNO (cp->second)];
+	  keep_p = ((REGNO (ALLOCNO_REG (first))
+		     == REGNO (ALLOCNO_REG (node_first)))
+		     && (REGNO (ALLOCNO_REG (second))
+			 == REGNO (ALLOCNO_REG (node_second))));
+	}
+      if (keep_p)
+	{
+	  cp->loop_tree_node = ira_loop_tree_root;
+	  cp->first = first;
+	  cp->second = second;
+	}
+      else
+	{
+	  cp->loop_tree_node = NULL;
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	    fprintf (ira_dump_file, "      Remove cp%d:a%dr%d-a%dr%d\n",
+		     cp->num, ALLOCNO_NUM (cp->first),
+		     REGNO (ALLOCNO_REG (cp->first)), ALLOCNO_NUM (cp->second),
+		     REGNO (ALLOCNO_REG (cp->second)));
+	}
+    }
+  /* Add conflicting allocnos from lower levels.  If we have a situation
+        A1----conflict---B1
+        A2----conflict---B2
+
+     and A1 and A2 will be presented by themselves in final IR and B1
+     and B2 will be presented by B1, then we need to check conflict A2
+     and B1.
+   
+     There is another situation when we should check and add conflicts
+     too.  It should be done when we removed restoring allocno value
+     at the loop exits because the allocno value is stored in memory
+     and the value is not changed in the loop.  In this case the
+     allocno lives in the loop and can conflict with allocnos inside
+     the loop.  */
+  for (i = 0; i < allocnos_num; i++)
+    {
+      a = allocnos [i];
+      if (a != regno_top_level_allocno_map [REGNO (ALLOCNO_REG (a))]
+	  || ALLOCNO_CAP_MEMBER (a) != NULL)
+	continue;
+      add_conflict_with_underlying_allocnos (a, ALLOCNO_LOOP_TREE_NODE (a),
+					     FALSE);
+      if ((first = ALLOCNO_MEM_OPTIMIZED_DEST (a)) != NULL)
+	{
+	  first = regno_top_level_allocno_map [REGNO (ALLOCNO_REG (first))];
+	  check_and_add_conflicts
+	    (first, ALLOCNO_CONFLICT_ALLOCNO_VEC (a));
+	  add_conflict_with_underlying_allocnos
+	    (first, ALLOCNO_LOOP_TREE_NODE (a), TRUE);
+	}
+    }
+  /* Change allocnos regno, conflicting allocnos, and range allocnos.  */
+  for (i = 0; i < allocnos_num; i++)
+    {
+      a = allocnos [i];
+      if (a != regno_top_level_allocno_map [REGNO (ALLOCNO_REG (a))]
+	  || ALLOCNO_CAP_MEMBER (a) != NULL)
+	continue;
+      ALLOCNO_LOOP_TREE_NODE (a) = ira_loop_tree_root;
+      ALLOCNO_REGNO (a) = REGNO (ALLOCNO_REG (a));
+      allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
+      for (j = 0; (conflict_a = allocno_vec [j]) != NULL; j++)
+	allocno_vec [j]
+	  = regno_top_level_allocno_map [REGNO (ALLOCNO_REG (conflict_a))];
+      for (r = ALLOCNO_LIVE_RANGES (a); r != NULL; r = r->next)
+	r->allocno = a;
+    }
+  /* Remove allocnos on lower levels of the loop tree and
+     enumerate allocnos.  */
+  for (free = 0, i = 0; i < allocnos_num; i++)
+    {
+      a = allocnos [i];
+      if (ALLOCNO_LOOP_TREE_NODE (a) != ira_loop_tree_root
+	  || ALLOCNO_CAP_MEMBER (a) != NULL)
+	{
+	  if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	    fprintf (ira_dump_file, "      Remove a%dr%d\n",
+		     ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a)));
+	  finish_allocno (a);
+	  continue;
+	}
+      ALLOCNO_CAP (a) = NULL;
+      /* Remove conflicts.  */
+      allocno_vec = ALLOCNO_CONFLICT_ALLOCNO_VEC (a);
+      for (k = j = ALLOCNO_CONFLICT_ALLOCNOS_NUM (a);
+	   (conflict_a = allocno_vec [j]) != NULL;
+	   j++)
+	{
+	  if (allocno_conflict_p (a, conflict_a))
+	    allocno_vec [k++] = conflict_a;
+	  else
+	    {
+	      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+		fprintf (ira_dump_file,
+			 "      Remove conflict a%dr%d - a%dr%d\n",
+			 ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a)),
+			 ALLOCNO_NUM (conflict_a),
+			 REGNO (ALLOCNO_REG (conflict_a)));
+	      
+	    }
+	}
+      allocno_vec [k] = NULL;
+      ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM (a) = k;
+      if (i == free)
+	{
+	  free++;
+	  continue;
+	}
+      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	fprintf (ira_dump_file, "      Enumerate a%dr%d to a%d\n",
+		 ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a)), free);
+      ALLOCNO_NUM (a) = free;
+      allocnos [free++] = a;
+    }
+  for (i = free; i < allocnos_num; i++)
+    VARRAY_POP (allocno_varray);
+  allocnos = (allocno_t *) &VARRAY_GENERIC_PTR (allocno_varray, 0);
+  allocnos_num = VARRAY_ACTIVE_SIZE (allocno_varray);
+  /* Remove unnecessary copies, and enumerate copies.  */
+  for (free = i = 0; i < copies_num; i++)
+    {
+      cp = copies [i];
+      if (cp->loop_tree_node == NULL)
+	{
+	  finish_copy (cp);
+	  continue;
+	}
+      ira_assert
+	(ALLOCNO_LOOP_TREE_NODE (cp->first) == ira_loop_tree_root
+	 && ALLOCNO_LOOP_TREE_NODE (cp->second) == ira_loop_tree_root);
+      add_allocno_copy_to_list (cp);
+      swap_allocno_copy_ends_if_necessary (cp);
+      if (i == free)
+	{
+	  free++;
+	  continue;
+	}
+      if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+	fprintf (ira_dump_file,
+		 "      Enumerate cp%d to cp%d\n", cp->num, free);
+      cp->num = free;
+      copies [free++] = cp;
     }
+  for (i = free; i < copies_num; i++)
+    VARRAY_POP (copy_varray);
+  copies = (copy_t *) &VARRAY_GENERIC_PTR (copy_varray, 0);
+  copies_num = VARRAY_ACTIVE_SIZE (copy_varray);
+  rebuild_regno_allocno_maps ();
+  rebuild_start_finish_chains ();
+  ira_free (regno_top_level_allocno_map);
+  live_allocnos = ira_allocate_bitmap ();
+  for (i = max_point_before_emit; i < max_point; i++)
+    {
+      for (r = start_point_ranges [i]; r != NULL; r = r->start_next)
+	{
+	  a = r->allocno;
+	  j = ALLOCNO_NUM (a);
+	  EXECUTE_IF_SET_IN_BITMAP (live_allocnos, 0, n, bi)
+	    {
+	      if (n == (unsigned int) j)
+		continue;
+	      conflict_a = allocnos [n];
+	      if (ALLOCNO_COVER_CLASS (a) == ALLOCNO_COVER_CLASS (conflict_a))
+		{
+		  if (allocno_conflict_index (a, conflict_a) < 0)
+		    {
+		      if (internal_flag_ira_verbose > 3
+			  && ira_dump_file != NULL)
+			fprintf
+			  (ira_dump_file,
+			   "      Add a%dr%d to conflict vec of a%dr%d\n",
+			   ALLOCNO_NUM (conflict_a),
+			   REGNO (ALLOCNO_REG (conflict_a)),
+			   ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a)));
+		      add_to_allocno_conflict_vec (a, conflict_a);
+		    }
+		  if (allocno_conflict_index (conflict_a, a) < 0)
+		    {
+		      if (internal_flag_ira_verbose > 3
+			  && ira_dump_file != NULL)
+			fprintf
+			  (ira_dump_file,
+			   "      Add a%dr%d to conflict vec of a%dr%d\n",
+			   ALLOCNO_NUM (a), REGNO (ALLOCNO_REG (a)),
+			   ALLOCNO_NUM (conflict_a),
+			   REGNO (ALLOCNO_REG (conflict_a)));
+		      add_to_allocno_conflict_vec (conflict_a, a);
+		    }
+		}
+	    }
+	  bitmap_set_bit (live_allocnos, j);
+	}
+      
+      for (r = finish_point_ranges [i]; r != NULL; r = r->finish_next)
+	bitmap_clear_bit (live_allocnos, ALLOCNO_NUM (r->allocno));
+    }
+  ira_free_bitmap (live_allocnos);
 }
-#endif
+
+
 
 /* This entry function creates internal representation for IRA
    (allocnos, copies, loop tree nodes).  If LOOPS_P is zero the nodes
    corresponding to the loops (except the root which corresponds the
-   all function) and correspondingly allocnos for the loops will be not
-   created (it will be done only for basic blocks).  Such value is
+   all function) and correspondingly allocnos for the loops will be
+   not created (it will be done only for basic blocks).  Such value is
    used for Chaitin-Briggs and Chow's priority coloring.  The function
    returns nonzero if we generates loop structure (besides node
    representing all function) for regional allocation.  */
@@ -939,15 +1886,41 @@ ira_build (int loops_p)
   form_loop_tree ();
   create_allocnos ();
   ira_costs ();
-  ira_build_conflicts ();
-  tune_allocno_costs_and_cover_classes ();
   if (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
       || flag_ira_algorithm == IRA_ALGORITHM_MIXED)
     {
       local_allocnos_bitmap = ira_allocate_bitmap ();
-      traverse_loop_tree (ira_loop_tree_root, NULL,
+      traverse_loop_tree (FALSE, ira_loop_tree_root, NULL,
 			  create_loop_tree_node_caps);
       ira_free_bitmap (local_allocnos_bitmap);
+    }
+  create_allocno_live_ranges ();
+  ira_build_conflicts ();
+  if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
+    {
+      int i, n, nr;
+      allocno_live_range_t r;
+
+      for (nr = n = i = 0; i < allocnos_num; i++)
+	  n += ALLOCNO_TOTAL_CONFLICT_ALLOCNOS_NUM (allocnos [i]);
+      for (nr = i = 0; i < allocnos_num; i++)
+	for (r = ALLOCNO_LIVE_RANGES (allocnos [i]); r != NULL; r = r->next)
+	    nr++;
+      fprintf (ira_dump_file, "  regions=%d, blocks=%d, points=%d\n",
+	       VEC_length (loop_p, ira_loops.larray), n_basic_blocks,
+	       max_point);
+      fprintf (ira_dump_file,
+	       "    allocnos=%d, copies=%d, conflicts=%d, ranges=%d\n",
+	       allocnos_num, copies_num, n, nr);
+    }
+  if (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
+      || flag_ira_algorithm == IRA_ALGORITHM_MIXED)
+    traverse_loop_tree (FALSE, ira_loop_tree_root, NULL,
+			propagate_info_to_loop_tree_node_caps);
+  tune_allocno_costs_and_cover_classes ();
+  if (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
+      || flag_ira_algorithm == IRA_ALGORITHM_MIXED)
+    {
       for (i = 0; VEC_iterate (loop_p, ira_loops.larray, i, loop); i++)
 	if (ira_loop_nodes [i].regno_allocno_map != NULL
 	    && ira_loop_tree_root != &ira_loop_nodes [i])
@@ -963,7 +1936,9 @@ ira_destroy (void)
   basic_block bb;
 
   finish_loop_tree_nodes ();
+#if 0
   ira_assert  (current_loops == &ira_loops);
+#endif
   flow_loops_free (&ira_loops);
   free_dominance_info (CDI_DOMINATORS);
   FOR_ALL_BB (bb)
@@ -972,4 +1947,5 @@ ira_destroy (void)
   finish_copies ();
   finish_allocnos ();
   finish_calls ();
+  finish_allocno_live_ranges ();
 }
Index: common.opt
===================================================================
--- common.opt	(revision 129968)
+++ common.opt	(working copy)
@@ -433,6 +433,10 @@ fdump-noaddr
 Common Report Var(flag_dump_noaddr)
 Suppress output of addresses in debugging dumps
 
+fdump-simple-rtl
+Common Report Var(flag_dump_simple_rtl) Init(0)
+Switch on dumping simple RTL code
+
 fdump-unnumbered
 Common Report Var(flag_dump_unnumbered) VarExists
 Suppress output of instruction numbers, line number notes and addresses in debugging dumps
@@ -613,23 +617,15 @@ Perform matrix layout flattening and tra
 on profiling information.
 
 fira
-Common Report Var(flag_ira)
+Common Report Var(flag_ira) Init(0)
 Use integrated register allocator.
 
 fira-algorithm=
 Common Joined RejectNegative
 -fira-algorithm=[regional|CB|mixed|priority] Set the used IRA algorithm
 
-fira-assign-after-call-split
-Common Report Var(flag_ira_assign_after_call_split) Init(1)
-Assign hard regs to pseudos after splitting pseudo live range arround calls.
-
-fira-biased-coloring
-Common Report Var(flag_ira_biased_coloring)
-Use biased coloring for the integrated register allocator.
-
 fira-coalesce
-Common Report Var(flag_ira_coalesce)
+Common Report Var(flag_ira_coalesce) Init(0)
 Do optimistic coalescing.
 
 fira-ipra
@@ -652,9 +648,9 @@ fira-share-spill-slots
 Common Report Var(flag_ira_share_spill_slots) Init(1)
 Share stack slots for spilled pseudo-registers.
 
-fira-split-around-calls
-Common Report Var(flag_ira_split_around_calls) Init(1)
-Split pseudo live range arround calls.
+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
Index: ira.c
===================================================================
--- ira.c	(revision 129968)
+++ ira.c	(working copy)
@@ -55,7 +55,7 @@ Software Foundation, 51 Franklin Street,
      Graph Coloring Register Allocation.
 
    o David Callahan, Brian Koblenz.  Register allocation via
-     hierarchical graph coloring
+     hierarchical graph coloring.
 
    o Keith Cooper, Anshuman Dasgupta, Jason Eckhardt. Revisiting Graph
      Coloring Register Allocation: A Study of the Chaitin-Briggs and
@@ -109,13 +109,14 @@ static void print_class_cover (FILE *);
 static void find_reg_class_closure (void);
 static void setup_reg_class_nregs (void);
 static void setup_prohibited_class_mode_regs (void);
+static void setup_prohibited_mode_move_regs (void);
 static int insn_contains_asm_1 (rtx *, void *);
 static int insn_contains_asm (rtx);
 static void compute_regs_asm_clobbered (char *);
 static void setup_eliminable_regset (void);
 static void find_reg_equiv_invariant_const (void);
-static void setup_reg_renumber (int, int);
-static int setup_allocno_assignment_from_reg_renumber (void);
+static void setup_reg_renumber (void);
+static void setup_allocno_assignment_flags (void);
 static void calculate_allocation_cost (void);
 #ifdef ENABLE_IRA_CHECKING
 static void check_allocation (void);
@@ -130,9 +131,15 @@ static void expand_reg_info (int);
 static bool gate_ira (void);
 static unsigned int rest_of_handle_ira (void);
 
+/* The flag value used internally.  */
+int internal_flag_ira_verbose;
+
 /* Dump file for IRA.  */
 FILE *ira_dump_file;
 
+/* Pools for allocnos, copies, allocno live ranges.  */
+alloc_pool allocno_pool, copy_pool, allocno_live_range_pool;
+
 /* The number of elements in the following array.  */
 int spilled_reg_stack_slots_num;
 
@@ -365,7 +372,7 @@ setup_alloc_regs (int use_hard_frame_p)
 
 /* Define the following macro if allocation through malloc if
    preferable.  */
-/*#define IRA_NO_OBSTACK*/
+#define IRA_NO_OBSTACK
 
 #ifndef IRA_NO_OBSTACK
 /* Obstack used for storing all dynamic data (except bitmaps) of the
@@ -390,6 +397,20 @@ ira_allocate (size_t len)
   return res;
 }
 
+/* The function reallocates memory PTR of size LEN for IRA data.  */
+void *
+ira_reallocate (void *ptr, size_t len)
+{
+  void *res;
+
+#ifndef IRA_NO_OBSTACK
+  res = obstack_alloc (&ira_obstack, len);
+#else
+  res = xrealloc (ptr, len);
+#endif
+  return res;
+}
+
 /* The function free memory ADDR allocated for IRA data.  */
 void
 ira_free (void *addr ATTRIBUTE_UNUSED)
@@ -462,7 +483,9 @@ print_disposition (FILE *f)
   fprintf (f, "Disposition:");
   max_regno = max_reg_num ();
   for (n = 0, i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
-    for (a = regno_allocno_map [i]; a != NULL; a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
+    for (a = regno_allocno_map [i];
+	 a != NULL;
+	 a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
       {
 	if (n % 4 == 0)
 	  fprintf (f, "\n");
@@ -543,10 +566,14 @@ enum reg_class reg_class_cover [N_REG_CL
 /* The value is number of elements in the subsequent array.  */
 int important_classes_num;
 
-/* The array containing classes which are subclasses of a cover
-   class.  */
+/* The array containing classes which are subclasses of cover
+   classes.  */
 enum reg_class important_classes [N_REG_CLASSES];
 
+/* The array containing order numbers of important classes (they are
+   subclasses of cover classes).  */
+enum reg_class important_class_nums [N_REG_CLASSES];
+
 #ifdef IRA_COVER_CLASSES
 
 /* The function checks IRA_COVER_CLASSES and sets the two global
@@ -578,7 +605,10 @@ setup_cover_classes (void)
 	for (j = 0; j < reg_class_cover_size; j++)
 	  if (hard_reg_set_subset_p (reg_class_contents [cl],
 				     reg_class_contents [reg_class_cover [j]]))
-	    important_classes [important_classes_num++] = cl;
+	    {
+	      important_class_nums [cl] = important_classes_num;
+	      important_classes [important_classes_num++] = cl;
+	    }
     }
 }
 #endif
@@ -777,6 +807,60 @@ init_ira_once (void)
   init_ira_costs_once ();
 }
 
+/* Function called once at the end of compiler work.  */
+void
+finish_ira_once (void)
+{
+  finish_ira_costs_once ();
+}
+
+
+
+/* Array whose values are hard regset of hard registers for which
+   move of the hard register in given mode into itself is
+   prohibited.  */
+HARD_REG_SET prohibited_mode_move_regs [NUM_MACHINE_MODES];
+
+/* Flag of that the above array has been initialized.  */
+static int prohibited_mode_move_regs_initialized_p = FALSE;
+
+/* The function setting up PROHIBITED_MODE_MOVE_REGS.  */
+static void
+setup_prohibited_mode_move_regs (void)
+{
+  int i, j;
+  rtx test_reg1, test_reg2, move_pat, move_insn;
+
+  if (prohibited_mode_move_regs_initialized_p)
+    return;
+  prohibited_mode_move_regs_initialized_p = TRUE;
+  test_reg1 = gen_rtx_REG (VOIDmode, 0);
+  test_reg2 = gen_rtx_REG (VOIDmode, 0);
+  move_pat = gen_rtx_SET (VOIDmode, test_reg1, test_reg2);
+  move_insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, 0, 0, move_pat, -1, 0);
+  for (i = 0; i < NUM_MACHINE_MODES; i++)
+    {
+      SET_HARD_REG_SET (prohibited_mode_move_regs [i]);
+      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+	{
+	  if (! HARD_REGNO_MODE_OK (j, i))
+	    continue;
+	  SET_REGNO (test_reg1, j);
+	  PUT_MODE (test_reg1, i);
+	  SET_REGNO (test_reg2, j);
+	  PUT_MODE (test_reg2, i);
+	  INSN_CODE (move_insn) = -1;
+	  recog_memoized (move_insn);
+	  if (INSN_CODE (move_insn) < 0)
+	    continue;
+	  extract_insn (move_insn);
+	  if (! constrain_operands (1))
+	    continue;
+	  CLEAR_HARD_REG_BIT (prohibited_mode_move_regs [i], j);
+	}
+    }
+}
+
 
 
 /* Function specific hard registers excluded from the allocation.  */
@@ -974,12 +1058,9 @@ find_reg_equiv_invariant_const (void)
 
 
 /* The function sets up REG_RENUMBER and CALLER_SAVE_NEEDED used by
-   reload from the allocation found by IRA.  If AFTER_EMIT_P, the
-   function is called after emitting the move insns, otherwise if
-   AFTER_CALL_P, the function is called right after splitting allocnos
-   around calls.  */
+   reload from the allocation found by IRA.  */
 static void
-setup_reg_renumber (int after_emit_p, int after_call_p)
+setup_reg_renumber (void)
 {
   int i, regno, hard_regno;
   allocno_t a;
@@ -988,52 +1069,50 @@ setup_reg_renumber (int after_emit_p, in
   for (i = 0; i < allocnos_num; i++)
     {
       a = allocnos [i];
-      if (ALLOCNO_CAP_MEMBER (a) != NULL)
-	/* It is a cap. */
-	continue;
+      /* There are no caps at this point.  */
+      ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
       if (! ALLOCNO_ASSIGNED_P (a))
 	ALLOCNO_ASSIGNED_P (a) = TRUE;
       ira_assert (ALLOCNO_ASSIGNED_P (a));
       hard_regno = ALLOCNO_HARD_REGNO (a);
-      regno = after_emit_p ? (int) REGNO (ALLOCNO_REG (a)) : ALLOCNO_REGNO (a);
+      regno = (int) REGNO (ALLOCNO_REG (a));
       reg_renumber [regno] = (hard_regno < 0 ? -1 : hard_regno);
       if (hard_regno >= 0 && ALLOCNO_CALLS_CROSSED_NUM (a) != 0
 	  && ! hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a),
 				      call_used_reg_set))
 	{
-	  ira_assert
-	    ((! after_call_p && flag_caller_saves)
-	     || (flag_caller_saves && ! flag_ira_split_around_calls)
-	     || reg_equiv_const [regno] || reg_equiv_invariant_p [regno]);
+	  ira_assert (flag_caller_saves || reg_equiv_const [regno]
+		      || reg_equiv_invariant_p [regno]);
 	  caller_save_needed = 1;
 	}
     }
 }
 
-/* The function sets up allocno assignment from reg_renumber.  If the
-   cover class of a allocno does not correspond to the hard register,
-   return TRUE and mark the allocno as unassigned.  */
-static int
-setup_allocno_assignment_from_reg_renumber (void)
+/* The function sets up allocno assignment flags for further
+   allocation improvements.  */
+static void
+setup_allocno_assignment_flags (void)
 {
   int i, hard_regno;
   allocno_t a;
-  int result = FALSE;
 
   for (i = 0; i < allocnos_num; i++)
     {
       a = allocnos [i];
-      hard_regno = ALLOCNO_HARD_REGNO (a) = reg_renumber [ALLOCNO_REGNO (a)];
-      ira_assert (! ALLOCNO_ASSIGNED_P (a));
-      if (hard_regno >= 0
-	  && hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a),
-				    reg_class_contents
-				    [ALLOCNO_COVER_CLASS (a)]))
-	result = TRUE;
-      else
-	ALLOCNO_ASSIGNED_P (a) = TRUE;
+      hard_regno = ALLOCNO_HARD_REGNO (a);
+      /* Don't assign hard registers to allocnos which are destination
+	 of removed store at the end of loop.  It has a few sense to
+	 keep the same value in different hard registers.  It is also
+	 impossible to assign hard registers correctly to such
+	 allocnos because the cost info and info about intersected
+	 calls are incorrect for them.  */
+      ALLOCNO_ASSIGNED_P (a) = (hard_regno >= 0
+				|| ALLOCNO_MEM_OPTIMIZED_DEST_P (a));
+      ira_assert (hard_regno < 0
+		  || ! hard_reg_not_in_set_p (hard_regno, ALLOCNO_MODE (a),
+					      reg_class_contents
+					      [ALLOCNO_COVER_CLASS (a)]));
     }
-  return result;
 }
 
 /* The function evaluates overall allocation cost and costs for using
@@ -1056,7 +1135,7 @@ calculate_allocation_cost (void)
 			reg_class_contents [ALLOCNO_COVER_CLASS (a)])); 
       if (hard_regno < 0)
 	{
-	  cost = ALLOCNO_MEMORY_COST (a);
+	  cost = ALLOCNO_UPDATED_MEMORY_COST (a);
 	  mem_cost += cost;
 	}
       else
@@ -1069,7 +1148,7 @@ calculate_allocation_cost (void)
       overall_cost += cost;
     }
 
-  if (ira_dump_file != NULL)
+  if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
     {
       fprintf (ira_dump_file,
 	       "+++Costs: overall %d, reg %d, mem %d, ld %d, st %d, move %d\n",
@@ -1189,9 +1268,11 @@ print_redundant_copies (void)
 	else
 	  {
 	    next_cp = cp->next_second_allocno_copy;
-	    if (ira_dump_file != NULL && cp->move_insn != NULL_RTX
+	    if (internal_flag_ira_verbose > 4 && ira_dump_file != NULL
+		&& cp->move_insn != NULL_RTX
 		&& ALLOCNO_HARD_REGNO (cp->first) == hard_regno)
-	      fprintf (ira_dump_file, "move %d(freq %d):%d\n",
+	      fprintf (ira_dump_file,
+		       "        Redundant move %d(freq %d):%d\n",
 		       INSN_UID (cp->move_insn), cp->freq, hard_regno);
 	  }
     }
@@ -1235,24 +1316,27 @@ expand_reg_info (int old_size)
 
 
 
-/* The value of max_regn_num () correspondingly before the allocator
-   and before splitting allocnos around calls.  */
-int ira_max_regno_before;
-int ira_max_regno_call_before;
-
-/* Flags for each regno (existing before the splitting allocnos around
-   calls) about that the corresponding register crossed a call.  */
-char *original_regno_call_crossed_p;
 
 /* This is the main entry of IRA.  */
 void
 ira (FILE *f)
 {
-  int i, overall_cost_before, loops_p, allocated_size;
+  int overall_cost_before, loops_p, allocated_reg_info_size;
+  int max_regno_before_ira, max_point_before_emit;
   int rebuild_p;
-  allocno_t a;
 
-  ira_dump_file = f;
+  if (flag_ira_verbose < 10)
+    {
+      internal_flag_ira_verbose = flag_ira_verbose;
+      ira_dump_file = f;
+    }
+  else
+    {
+      internal_flag_ira_verbose = flag_ira_verbose - 10;
+      ira_dump_file = stderr;
+    }
+
+  setup_prohibited_mode_move_regs ();
 
   df_note_add_problem ();
 
@@ -1266,6 +1350,11 @@ ira (FILE *f)
 
   df_clear_flags (DF_NO_INSN_RESCAN);
 
+  allocno_pool = create_alloc_pool ("allocnos", sizeof (struct allocno), 100);
+  copy_pool = create_alloc_pool ("copies", sizeof (struct allocno_copy), 100);
+  allocno_live_range_pool
+    = create_alloc_pool ("allocno live ranges",
+			 sizeof (struct allocno_live_range), 100);
   regstat_init_n_sets_and_refs ();
   regstat_compute_ri ();
   rebuild_p = update_equiv_regs ();
@@ -1277,11 +1366,11 @@ ira (FILE *f)
 #endif
   bitmap_obstack_initialize (&ira_bitmap_obstack);
 
-  ira_max_regno_call_before = ira_max_regno_before = max_reg_num ();
-  reg_equiv_invariant_p = ira_allocate (max_reg_num () * sizeof (int));
-  memset (reg_equiv_invariant_p, 0, max_reg_num () * sizeof (int));
-  reg_equiv_const = ira_allocate (max_reg_num () * sizeof (rtx));
-  memset (reg_equiv_const, 0, max_reg_num () * sizeof (rtx));
+  max_regno = max_reg_num ();
+  reg_equiv_invariant_p = ira_allocate (max_regno * sizeof (int));
+  memset (reg_equiv_invariant_p, 0, max_regno * sizeof (int));
+  reg_equiv_const = ira_allocate (max_regno * sizeof (rtx));
+  memset (reg_equiv_const, 0, max_regno * sizeof (rtx));
   find_reg_equiv_invariant_const ();
   if (rebuild_p)
     {
@@ -1290,7 +1379,7 @@ ira (FILE *f)
       purge_all_dead_edges ();
       timevar_pop (TV_JUMP);
     }
-  allocated_size = max_reg_num ();
+  max_regno_before_ira = allocated_reg_info_size = max_reg_num ();
   allocate_reg_info ();
   setup_eliminable_regset ();
 
@@ -1300,61 +1389,42 @@ ira (FILE *f)
   overall_cost = reg_cost = mem_cost = 0;
   load_cost = store_cost = shuffle_cost = 0;
   move_loops_num = additional_jumps_num = 0;
+  if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
+    fprintf (ira_dump_file, "Building IRA IR\n");
   loops_p = ira_build (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
 		       || flag_ira_algorithm == IRA_ALGORITHM_MIXED);
   ira_color ();
 
-  ira_emit ();
+  max_point_before_emit = max_point;
+
+  ira_emit (loops_p);
 
   max_regno = max_reg_num ();
   
-  expand_reg_info (allocated_size);
-  allocated_size = max_regno;
- 
-  setup_reg_renumber (TRUE, FALSE);
-
   if (loops_p)
     {
-      /* Even if new registers are not created rebuild IRA internal
-	 representation to use correct regno allocno map.  */
-      ira_destroy ();
-      ira_build (FALSE);
-      if (setup_allocno_assignment_from_reg_renumber ())
-	{
-	  reassign_conflict_allocnos (max_regno, FALSE);
-	  setup_reg_renumber (FALSE, FALSE);
-	}
-    }
-
-  original_regno_call_crossed_p = ira_allocate (max_regno * sizeof (char));
+      expand_reg_info (allocated_reg_info_size);
+      allocated_reg_info_size = max_regno;
+ 
+      if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
+	fprintf (ira_dump_file, "Flattening IR\n");
+      ira_flattening (max_regno_before_ira, max_point_before_emit);
+      /* New insns were generated: add notes and recaclulate live
+	 info.  */
+      df_analyze ();
+      {
+	basic_block bb;
 
-  for (i = 0; i < allocnos_num; i++)
-    {
-      a = allocnos [i];
-      ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
-      original_regno_call_crossed_p [ALLOCNO_REGNO (a)]
-	= ALLOCNO_CALLS_CROSSED_NUM (a) != 0;
-    }
-  ira_max_regno_call_before = max_reg_num ();
-  if (flag_caller_saves && flag_ira_split_around_calls)
-    {
-      if (split_around_calls ())
-	{
-	  ira_destroy ();
-	  max_regno = max_reg_num ();
-	  expand_reg_info (allocated_size);
-	  allocated_size = max_regno;
-	  for (i = ira_max_regno_call_before; i < max_regno; i++)
-	    reg_renumber [i] = -1;
-	  ira_build (FALSE);
-	  setup_allocno_assignment_from_reg_renumber ();
-	  reassign_conflict_allocnos ((flag_ira_assign_after_call_split
-				      ? ira_max_regno_call_before
-				      : max_reg_num ()), TRUE);
-  	  setup_reg_renumber (FALSE, TRUE);
-	}
+	FOR_ALL_BB (bb)
+	  bb->loop_father = NULL;
+	current_loops = NULL;
+      }
+      setup_allocno_assignment_flags ();
+      reassign_conflict_allocnos (max_regno, FALSE);
     }
 
+  setup_reg_renumber ();
+
   calculate_allocation_cost ();
 
 #ifdef ENABLE_IRA_CHECKING
@@ -1363,8 +1433,7 @@ ira (FILE *f)
 
   setup_preferred_alternate_classes ();
 
-  max_regno = max_reg_num ();
-  delete_trivially_dead_insns (get_insns (), max_regno);
+  delete_trivially_dead_insns (get_insns (), max_reg_num ());
   max_regno = max_reg_num ();
   
   /* Determine if the current function is a leaf before running IRA
@@ -1401,7 +1470,8 @@ ira (FILE *f)
 
   ira_free (spilled_reg_stack_slots);
 
-  if (ira_dump_file != NULL && overall_cost_before != overall_cost)
+  if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL
+      && overall_cost_before != overall_cost)
     fprintf (ira_dump_file, "+++Overall after reload %d\n", overall_cost);
 
   ira_destroy ();
@@ -1411,10 +1481,13 @@ ira (FILE *f)
   regstat_free_ri ();
   regstat_free_n_sets_and_refs ();
 
-  ira_free (original_regno_call_crossed_p);
   ira_free (reg_equiv_invariant_p);
   ira_free (reg_equiv_const);
   
+  free_alloc_pool (allocno_live_range_pool);
+  free_alloc_pool (copy_pool);
+  free_alloc_pool (allocno_pool);
+
   bitmap_obstack_release (&ira_bitmap_obstack);
 #ifndef IRA_NO_OBSTACK
   obstack_free (&ira_obstack, NULL);
Index: ira.h
===================================================================
--- ira.h	(revision 129968)
+++ ira.h	(working copy)
@@ -54,6 +54,7 @@ extern rtx *reg_equiv_address;
 extern rtx *reg_equiv_mem;
 
 extern void init_ira_once (void);
+extern void finish_ira_once (void);
 extern rtx ira_eliminate_regs (rtx, enum machine_mode);
 
 extern void ira (FILE *);
Index: ira-costs.c
===================================================================
--- ira-costs.c	(revision 129968)
+++ ira-costs.c	(working copy)
@@ -45,19 +45,19 @@ Software Foundation, 51 Franklin Street,
 struct costs;
 
 static void record_reg_classes (int, int, rtx *, enum machine_mode *,
-				const char **, rtx, struct costs *,
+				const char **, rtx, struct costs **,
 				enum reg_class *);
 static inline int ok_for_index_p_nonstrict (rtx);
 static inline int ok_for_base_p_nonstrict (rtx, enum machine_mode,
 					   enum rtx_code, enum rtx_code);
 static void record_address_regs (enum machine_mode, rtx x, int,
 				 enum rtx_code, enum rtx_code, int scale);
-static void record_operand_costs (rtx, struct costs *, enum reg_class *);
+static void record_operand_costs (rtx, struct costs **, enum reg_class *);
 static rtx scan_one_insn (rtx);
 static void print_costs (FILE *);
-static void process_bb_node_for_costs (struct ira_loop_tree_node *);
+static void process_bb_node_for_costs (loop_tree_node_t);
 static void find_allocno_class_costs (void);
-static void process_bb_node_for_hard_reg_moves (struct ira_loop_tree_node *);
+static void process_bb_node_for_hard_reg_moves (loop_tree_node_t);
 static void setup_allocno_cover_class_and_costs (void);
 
 #ifdef FORBIDDEN_INC_DEC_CLASSES
@@ -71,16 +71,33 @@ static char *in_inc_dec;
    to set up register and costs.  */
 struct costs
 {
-  int cost [N_REG_CLASSES];
   int mem_cost;
+  /* Costs for important register classes start here.  */
+  int cost [1];
 };
 
-/* Record the cost of each class for each allocno.  */
-static struct costs *costs;
+/* Initialized once.  It is a size of the allocated struct costs.  */
+static int struct_costs_size;
 
-/* Initialized once, and used to initialize cost values for each
-   insn.  */
-static struct costs init_cost;
+/* Allocated and initialized once, and used to initialize cost values
+   for each insn.  */
+static struct costs *init_cost;
+
+/* Allocated once, and used for temporary purposes.  */
+static struct costs *temp_costs;
+
+/* Allocated once, and used for the cost calculation.  */
+static struct costs *op_costs [MAX_RECOG_OPERANDS];
+static struct costs *this_op_costs [MAX_RECOG_OPERANDS];
+
+/* Record the initial and accumulated cost of each class for each
+   allocno.  */
+static struct costs *total_costs;
+
+/* Return pointer to structure containing costs of allocno with given
+   NUM in array ARR.  */
+#define COSTS_OF_ALLOCNO(arr, num) \
+  ((struct costs *) ((char *) (arr) + (num) * struct_costs_size))
 
 /* Record register class preferences of each allocno.  */
 static enum reg_class *allocno_pref;
@@ -91,9 +108,6 @@ static enum reg_class *allocno_pref_buff
 /* Frequency of executions of the current insn.  */
 static int frequency;
 
-/* Map regno->allocno for the current loop.  */
-static allocno_t *curr_regno_allocno_map;
-
 /* Compute the cost of loading X into (if TO_P is nonzero) or from (if
    TO_P is zero) a register of class CLASS in mode MODE.  X must not
    be a pseudo register.  */
@@ -167,7 +181,7 @@ copy_cost (rtx x, enum machine_mode mode
 static void
 record_reg_classes (int n_alts, int n_ops, rtx *ops,
 		    enum machine_mode *modes, const char **constraints,
-		    rtx insn, struct costs *op_costs,
+		    rtx insn, struct costs **op_costs,
 		    enum reg_class *allocno_pref)
 {
   int alt;
@@ -178,7 +192,6 @@ record_reg_classes (int n_alts, int n_op
      with the cost for each operand in that alternative.  */
   for (alt = 0; alt < n_alts; alt++)
     {
-      struct costs this_op_costs [MAX_RECOG_OPERANDS];
       enum reg_class classes [MAX_RECOG_OPERANDS];
       int allows_mem [MAX_RECOG_OPERANDS];
       int class;
@@ -203,7 +216,7 @@ record_reg_classes (int n_alts, int n_op
 	  if (*p == 0)
 	    {
 	      if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
-		memset (&this_op_costs [i], 0, sizeof this_op_costs [i]);
+		memset (this_op_costs [i], 0, struct_costs_size);
 	      continue;
 	    }
 
@@ -264,7 +277,7 @@ record_reg_classes (int n_alts, int n_op
 		     other operand since move costs are not symmetric.
 		     Moreover, if we cannot tie them, this alternative
 		     needs to do a copy, which is one instruction.  */
-		  struct costs *pp = &this_op_costs [i];
+		  struct costs *pp = this_op_costs [i];
 
 		  if (move_cost [mode] == NULL)
 		    init_move_cost (mode);
@@ -272,7 +285,7 @@ record_reg_classes (int n_alts, int n_op
 		  for (k = 0; k < important_classes_num; k++)
 		    {
 		      class = important_classes [k];
-		      pp->cost [class]
+		      pp->cost [k]
 			= ((recog_data.operand_type [i] != OP_OUT
 			    ? may_move_in_cost [mode] [class] [classes [i]]
 			    : 0)
@@ -299,11 +312,25 @@ record_reg_classes (int n_alts, int n_op
 		     cover class here but it is less accurate
 		     approximation.  */
 		  if (allocno_pref)
-		    alt_cost
-		      += (may_move_in_cost [mode]
-			  [allocno_pref [ALLOCNO_NUM
-					(curr_regno_allocno_map [REGNO (op)])]]
-			  [classes [i]]);
+		    {
+		      enum reg_class pref_class
+			= allocno_pref [ALLOCNO_NUM
+					(ira_curr_regno_allocno_map
+					 [REGNO (op)])];
+
+		      if (pref_class == NO_REGS)
+			alt_cost
+			  += ((recog_data.operand_type [i] != OP_IN
+			       ? memory_move_cost [mode] [classes [i]] [0]
+			       : 0)
+			      + (recog_data.operand_type [i] != OP_OUT
+				 ? memory_move_cost [mode] [classes [i]] [1]
+				 : 0));
+		      else
+			alt_cost
+			  += (may_move_in_cost
+			      [mode] [pref_class] [classes [i]]);
+		    }
 		  if (REGNO (ops [i]) != REGNO (ops [j])
 		      && ! find_reg_note (insn, REG_DEAD, op))
 		    alt_cost += 2;
@@ -499,7 +526,7 @@ record_reg_classes (int n_alts, int n_op
 		}
 	      else
 		{
-		  struct costs *pp = &this_op_costs [i];
+		  struct costs *pp = this_op_costs [i];
 
 		  if (move_cost [mode] == NULL)
 		    init_move_cost (mode);
@@ -507,7 +534,7 @@ record_reg_classes (int n_alts, int n_op
 		  for (k = 0; k < important_classes_num; k++)
 		    {
 		      class = important_classes [k];
-		      pp->cost [class]
+		      pp->cost [k]
 			= ((recog_data.operand_type [i] != OP_OUT
 			    ? may_move_in_cost [mode] [class] [classes [i]]
 			    : 0)
@@ -534,11 +561,25 @@ record_reg_classes (int n_alts, int n_op
 		     cover class here but it is less accurate
 		     approximation.  */
 		  if (allocno_pref)
-		    alt_cost
-		      += (may_move_in_cost [mode]
-			  [allocno_pref [ALLOCNO_NUM
-					(curr_regno_allocno_map [REGNO (op)])]]
-			  [classes [i]]);
+		    {
+		      enum reg_class pref_class
+			= allocno_pref [ALLOCNO_NUM
+					(ira_curr_regno_allocno_map
+					 [REGNO (op)])];
+
+		      if (pref_class == NO_REGS)
+			alt_cost
+			  += ((recog_data.operand_type [i] != OP_IN
+			       ? memory_move_cost [mode] [classes [i]] [0]
+			       : 0)
+			      + (recog_data.operand_type [i] != OP_OUT
+				 ? memory_move_cost [mode] [classes [i]] [1]
+				 : 0));
+		      else
+			alt_cost
+			  += (may_move_in_cost
+			      [mode] [pref_class] [classes [i]]);
+		    }
 		}
 	    }
 
@@ -579,18 +620,15 @@ record_reg_classes (int n_alts, int n_op
 	if (REG_P (ops [i])
 	    && REGNO (ops [i]) >= FIRST_PSEUDO_REGISTER)
 	  {
-	    struct costs *pp = &op_costs [i], *qq = &this_op_costs [i];
+	    struct costs *pp = op_costs [i], *qq = this_op_costs [i];
 	    int scale = 1 + (recog_data.operand_type [i] == OP_INOUT);
 
 	    pp->mem_cost = MIN (pp->mem_cost,
 				(qq->mem_cost + alt_cost) * scale);
 
 	    for (k = 0; k < important_classes_num; k++)
-	      {
-		class = important_classes [k];
-		pp->cost [class] = MIN (pp->cost [class],
-					(qq->cost [class] + alt_cost) * scale);
-	      }
+	      pp->cost [k] = MIN (pp->cost [k],
+				  (qq->cost [k] + alt_cost) * scale);
 	  }
     }
 
@@ -627,12 +665,14 @@ record_reg_classes (int n_alts, int n_op
 	      /* We could use cover class here but it is less accurate
 		 approximation. */
 	      pref
-		= allocno_pref [ALLOCNO_NUM (curr_regno_allocno_map [regno])];
+		= allocno_pref [ALLOCNO_NUM (ira_curr_regno_allocno_map
+					     [regno])];
 
-	      if ((reg_class_size [pref]
-		   == (unsigned) CLASS_MAX_NREGS (pref, mode))
+	      if (pref != NO_REGS
+		  && (reg_class_size [pref]
+		      == (unsigned) CLASS_MAX_NREGS (pref, mode))
 		  && register_move_cost [mode] [pref] [pref] < 10 * 2)
-		op_costs [i].cost [pref] = -1;
+		op_costs [i]->cost [important_class_nums [pref]] = -1;
 	    }
 	  else if (regno < FIRST_PSEUDO_REGISTER)
 	    for (k = 0; k < important_classes_num; k++)
@@ -643,7 +683,7 @@ record_reg_classes (int n_alts, int n_op
 			== (unsigned) CLASS_MAX_NREGS (class, mode)))
 		  {
 		    if (reg_class_size [class] == 1)
-		      op_costs [i].cost [class] = -1;
+		      op_costs [i]->cost [k] = -1;
 		    else
 		      {
 			for (nr = 0;
@@ -654,7 +694,7 @@ record_reg_classes (int n_alts, int n_op
 			    break;
 			
 			if (nr == (unsigned) hard_regno_nregs [regno] [mode])
-			  op_costs [i].cost [class] = -1;
+			  op_costs [i]->cost [k] = -1;
 		      }
 		  }
 	      }
@@ -836,8 +876,8 @@ record_address_regs (enum machine_mode m
 #ifdef FORBIDDEN_INC_DEC_CLASSES
       if (REG_P (XEXP (x, 0))
 	  && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER)
-	in_inc_dec [ALLOCNO_NUM (curr_regno_allocno_map [REGNO (XEXP (x, 0))])]
-	  = 1;
+	in_inc_dec [ALLOCNO_NUM (ira_curr_regno_allocno_map
+				 [REGNO (XEXP (x, 0))])] = 1;
 #endif
       record_address_regs (mode, XEXP (x, 0), 0, code, SCRATCH, 2 * scale);
       break;
@@ -850,14 +890,16 @@ record_address_regs (enum machine_mode m
 	if (REGNO (x) < FIRST_PSEUDO_REGISTER)
 	  break;
 
-	pp = &costs [ALLOCNO_NUM (curr_regno_allocno_map [REGNO (x)])];
+	pp = COSTS_OF_ALLOCNO (total_costs,
+			       ALLOCNO_NUM (ira_curr_regno_allocno_map
+					    [REGNO (x)]));
 	pp->mem_cost += (memory_move_cost [Pmode] [class] [1] * scale) / 2;
 	if (move_cost [Pmode] == NULL)
 	  init_move_cost (Pmode);
 	for (k = 0; k < important_classes_num; k++)
 	  {
 	    i = important_classes [k];
-	    pp->cost [i] += (may_move_in_cost [Pmode] [i] [class] * scale) / 2;
+	    pp->cost [k] += (may_move_in_cost [Pmode] [i] [class] * scale) / 2;
 	  }
       }
       break;
@@ -878,7 +920,7 @@ record_address_regs (enum machine_mode m
 
 /* Calculate the costs of insn operands.  */
 static void
-record_operand_costs (rtx insn, struct costs *op_costs,
+record_operand_costs (rtx insn, struct costs **op_costs,
 		      enum reg_class *allocno_pref)
 {
   const char *constraints [MAX_RECOG_OPERANDS];
@@ -898,7 +940,7 @@ record_operand_costs (rtx insn, struct c
      commutative.  */
   for (i = 0; i < recog_data.n_operands; i++)
     {
-      op_costs [i] = init_cost;
+      memmove (op_costs [i], init_cost, struct_costs_size);
 
       if (GET_CODE (recog_data.operand [i]) == SUBREG)
 	recog_data.operand [i] = SUBREG_REG (recog_data.operand [i]);
@@ -949,8 +991,7 @@ scan_one_insn (rtx insn)
 {
   enum rtx_code pat_code;
   rtx set, note;
-  int i, j, k;
-  struct costs op_costs [MAX_RECOG_OPERANDS];
+  int i, k;
 
   if (!INSN_P (insn))
     return insn;
@@ -970,8 +1011,9 @@ scan_one_insn (rtx insn)
       && (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != NULL_RTX
       && MEM_P (XEXP (note, 0)))
     {
-      costs [ALLOCNO_NUM (curr_regno_allocno_map
-			 [REGNO (SET_DEST (set))])].mem_cost
+      COSTS_OF_ALLOCNO (total_costs,
+			ALLOCNO_NUM (ira_curr_regno_allocno_map
+				     [REGNO (SET_DEST (set))]))->mem_cost
 	-= (memory_move_cost [GET_MODE (SET_DEST (set))] [GENERAL_REGS] [1]
 	    * frequency);
       record_address_regs (GET_MODE (SET_SRC (set)), XEXP (SET_SRC (set), 0),
@@ -988,15 +1030,15 @@ scan_one_insn (rtx insn)
 	&& REGNO (recog_data.operand [i]) >= FIRST_PSEUDO_REGISTER)
       {
 	int regno = REGNO (recog_data.operand [i]);
-	struct costs *p = &costs [ALLOCNO_NUM (curr_regno_allocno_map [regno])];
-	struct costs *q = &op_costs [i];
+	struct costs *p
+	  = COSTS_OF_ALLOCNO (total_costs,
+			      ALLOCNO_NUM (ira_curr_regno_allocno_map
+					   [regno]));
+	struct costs *q = op_costs [i];
 
 	p->mem_cost += q->mem_cost * frequency;
 	for (k = 0; k < important_classes_num; k++)
-	  {
-	    j = important_classes [k];
-	    p->cost [j] += q->cost [j] * frequency;
-	  }
+	  p->cost [k] += q->cost [k] * frequency;
       }
 
   return insn;
@@ -1015,14 +1057,14 @@ print_costs (FILE *f)
     {
       int class;
       basic_block bb;
-      allocno_t p = allocnos [i];
-      int regno = ALLOCNO_REGNO (p);
+      allocno_t a = allocnos [i];
+      int regno = ALLOCNO_REGNO (a);
 
-      fprintf (f, "  p%d(r%d,", i, regno);
-      if ((bb = ALLOCNO_LOOP_TREE_NODE (p)->bb) != NULL)
+      fprintf (f, "  a%d(r%d,", i, regno);
+      if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
 	fprintf (f, "b%d", bb->index);
       else
-	fprintf (f, "l%d", ALLOCNO_LOOP_TREE_NODE (p)->loop->num);
+	fprintf (f, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
       fprintf (f, ") costs:");
       for (k = 0; k < important_classes_num; k++)
 	{
@@ -1037,16 +1079,16 @@ print_costs (FILE *f)
 #endif
 	      )
 	    fprintf (f, " %s:%d", reg_class_names [class],
-		     costs [i].cost [class]);
+		     COSTS_OF_ALLOCNO (total_costs, i)->cost [k]);
 	}
-      fprintf (f, " MEM:%i\n", costs [i].mem_cost);
+      fprintf (f, " MEM:%i\n", COSTS_OF_ALLOCNO (total_costs, i)->mem_cost);
     }
 }
 
 /* The function traverses basic blocks represented by LOOP_TREE_NODE
    to find the costs of the allocnos.  */
 static void
-process_bb_node_for_costs (struct ira_loop_tree_node *loop_tree_node)
+process_bb_node_for_costs (loop_tree_node_t loop_tree_node)
 {
   basic_block bb;
   rtx insn;
@@ -1057,13 +1099,12 @@ process_bb_node_for_costs (struct ira_lo
   frequency = REG_FREQ_FROM_BB (bb);
   if (frequency == 0)
     frequency = 1;
-  curr_regno_allocno_map = ira_curr_loop_tree_node->regno_allocno_map;
   FOR_BB_INSNS (bb, insn)
     insn = scan_one_insn (insn);
 }
 
-/* Entry function to find costs of each class cost for pesudos and
-   their best classes. */
+/* Entry function to find costs of each class for pesudos and their
+   best classes. */
 static void
 find_allocno_class_costs (void)
 {
@@ -1083,67 +1124,64 @@ find_allocno_class_costs (void)
      classes to guide the selection.  */
   for (pass = 0; pass <= flag_expensive_optimizations; pass++)
     {
-      if (ira_dump_file)
-	fprintf (ira_dump_file, "\nPass %i\n\n",pass);
+      if (internal_flag_ira_verbose > 0 && ira_dump_file)
+	fprintf (ira_dump_file, "\nPass %i for finding allocno costs\n\n",
+		 pass);
       /* Zero out our accumulation of the cost of each class for each
 	 allocno.  */
-      memset (costs, 0, allocnos_num * sizeof (struct costs));
+      memset (total_costs, 0, allocnos_num * struct_costs_size);
 #ifdef FORBIDDEN_INC_DEC_CLASSES
       memset (in_inc_dec, 0, allocnos_num * sizeof (char));
 #endif
 
       /* Scan the instructions and record each time it would save code
 	 to put a certain allocno in a certain class.  */
-      traverse_loop_tree (ira_loop_tree_root, process_bb_node_for_costs, NULL);
+      traverse_loop_tree (FALSE, ira_loop_tree_root,
+			  process_bb_node_for_costs, NULL);
 
       /* Now for each allocno look at how desirable each class is and
-	 find which class is preferred.  Store that in
-	 `prefclass'.  */
+	 find which class is preferred.  */
       if (pass == 0)
 	allocno_pref = allocno_pref_buffer;
 
       for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
 	{
-	  allocno_t p, father_p;
-	  int class, p_num, father_p_num;
-	  struct ira_loop_tree_node *father;
+	  allocno_t a, father_a;
+	  int class, a_num, father_a_num;
+	  loop_tree_node_t father;
 	  int best_cost;
 	  enum reg_class best, common_class;
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 	  int inc_dec_p = FALSE;
 #endif
-	  struct costs reg_costs;
 
 	  if (regno_allocno_map [i] == NULL)
 	    continue;
-	  memset (&reg_costs, 0, sizeof (struct costs));
-	  for (p = regno_allocno_map [i];
-	       p != NULL;
-	       p = ALLOCNO_NEXT_REGNO_ALLOCNO (p))
+	  memset (temp_costs, 0, struct_costs_size);
+	  for (a = regno_allocno_map [i];
+	       a != NULL;
+	       a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
 	    {
-	      p_num = ALLOCNO_NUM (p);
+	      a_num = ALLOCNO_NUM (a);
 	      if ((flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
 		   || flag_ira_algorithm == IRA_ALGORITHM_MIXED)
-		  && (father = ALLOCNO_LOOP_TREE_NODE (p)->father) != NULL
-		  && (father_p = father->regno_allocno_map [i]) != NULL)
+		  && (father = ALLOCNO_LOOP_TREE_NODE (a)->father) != NULL
+		  && (father_a = father->regno_allocno_map [i]) != NULL)
 		{
-		  father_p_num = ALLOCNO_NUM (father_p);
+		  father_a_num = ALLOCNO_NUM (father_a);
 		  for (k = 0; k < important_classes_num; k++)
-		    {
-		      class = important_classes [k];
-		      costs [father_p_num].cost [class]
-			+= costs [p_num].cost [class];
-		    }
-		  costs [father_p_num].mem_cost += costs [p_num].mem_cost;
+		    COSTS_OF_ALLOCNO (total_costs, father_a_num)->cost [k]
+		      += COSTS_OF_ALLOCNO (total_costs, a_num)->cost [k];
+		  COSTS_OF_ALLOCNO (total_costs, father_a_num)->mem_cost
+		    += COSTS_OF_ALLOCNO (total_costs, a_num)->mem_cost;
 		}
-		  for (k = 0; k < important_classes_num; k++)
-		    {
-		      class = important_classes [k];
-		      reg_costs.cost [class] += costs [p_num].cost [class];
-		    }
-	      reg_costs.mem_cost += costs [p_num].mem_cost;
+	      for (k = 0; k < important_classes_num; k++)
+		temp_costs->cost [k]
+		  += COSTS_OF_ALLOCNO (total_costs, a_num)->cost [k];
+	      temp_costs->mem_cost
+		+= COSTS_OF_ALLOCNO (total_costs, a_num)->mem_cost;
 #ifdef FORBIDDEN_INC_DEC_CLASSES
-	      if (in_inc_dec [p_num])
+	      if (in_inc_dec [a_num])
 		inc_dec_p = TRUE;
 #endif
 	    }
@@ -1164,67 +1202,84 @@ find_allocno_class_costs (void)
 #endif
 		  )
 		;
-	      else if (reg_costs.cost [class] < best_cost)
+	      else if (temp_costs->cost [k] < best_cost)
 		{
-		  best_cost = reg_costs.cost [class];
+		  best_cost = temp_costs->cost [k];
 		  best = (enum reg_class) class;
 		}
-	      else if (reg_costs.cost [class] == best_cost)
+	      else if (temp_costs->cost [k] == best_cost)
 		best = reg_class_subunion [best] [class];
 	    }
-	  common_class = best;
-	  if (class_subset_p [best] [class_translate [best]])
-	    common_class = class_translate [best];
-	  for (p = regno_allocno_map [i];
-	       p != NULL;
-	       p = ALLOCNO_NEXT_REGNO_ALLOCNO (p))
+	  if (best_cost > temp_costs->mem_cost)
+	    common_class = NO_REGS;
+	  else
 	    {
-	      p_num = ALLOCNO_NUM (p);
-	      /* Finding best class which is cover class for the
-		 register.  */
-	      best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
-	      best = ALL_REGS;
-	      for (k = 0; k < important_classes_num; k++)
-		{
-		  class = important_classes [k];
-		  if (! class_subset_p [class] [common_class])
-		    continue;
-		  /* Ignore classes that are too small for this operand or
-		     invalid for an operand that was auto-incremented.  */
-		  if (! contains_reg_of_mode  [class] [PSEUDO_REGNO_MODE (i)]
+	      common_class = best;
+	      if (class_subset_p [best] [class_translate [best]])
+		common_class = class_translate [best];
+	    }
+	  for (a = regno_allocno_map [i];
+	       a != NULL;
+	       a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
+	    {
+	      a_num = ALLOCNO_NUM (a);
+	      if (common_class == NO_REGS)
+		  best = NO_REGS;
+	      else
+		{	      
+		  /* Finding best class which is cover class for the
+		     register.  */
+		  best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
+		  best = ALL_REGS;
+		  for (k = 0; k < important_classes_num; k++)
+		    {
+		      class = important_classes [k];
+		      if (! class_subset_p [class] [common_class])
+			continue;
+		      /* Ignore classes that are too small for this
+			 operand or invalid for an operand that was
+			 auto-incremented.  */
+		      if (! contains_reg_of_mode [class] [PSEUDO_REGNO_MODE
+							  (i)]
 #ifdef FORBIDDEN_INC_DEC_CLASSES
-		      || (inc_dec_p && forbidden_inc_dec_class [class])
+			  || (inc_dec_p && forbidden_inc_dec_class [class])
 #endif
 #ifdef CANNOT_CHANGE_MODE_CLASS
-		      || invalid_mode_change_p (i, (enum reg_class) class,
-						PSEUDO_REGNO_MODE (i)))
-		    ;
-		  else if (costs [p_num].cost [class] < best_cost)
-		    {
-		      best_cost = costs [p_num].cost [class];
-		      best = (enum reg_class) class;
+			  || invalid_mode_change_p (i, (enum reg_class) class,
+						    PSEUDO_REGNO_MODE (i))
+#endif
+			  )
+			;
+		      else if (COSTS_OF_ALLOCNO (total_costs, a_num)->cost [k]
+			       < best_cost)
+			{
+			  best_cost
+			    = COSTS_OF_ALLOCNO (total_costs, a_num)->cost [k];
+			  best = (enum reg_class) class;
+			}
+		      else if (COSTS_OF_ALLOCNO (total_costs, a_num)->cost [k]
+			       == best_cost)
+			best = reg_class_subunion [best] [class];
 		    }
-		  else if (costs [p_num].cost [class] == best_cost)
-		    best = reg_class_subunion [best] [class];
 		}
-#endif
-	      if (ira_dump_file && (pass == 0 || allocno_pref [p_num] != best))
+	      if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL
+		  && (pass == 0 || allocno_pref [a_num] != best))
 		{
-		  fprintf (ira_dump_file, "  p%d (r%d,", p_num, i);
-		  if ((bb = ALLOCNO_LOOP_TREE_NODE (p)->bb) != NULL)
+		  fprintf (ira_dump_file, "    a%d (r%d,", a_num, i);
+		  if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
 		    fprintf (ira_dump_file, "b%d", bb->index);
 		  else
 		    fprintf (ira_dump_file, "l%d",
-			     ALLOCNO_LOOP_TREE_NODE (p)->loop->num);
+			     ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
 		  fprintf (ira_dump_file, ") best %s, cover %s\n",
 			   reg_class_names [best],
 			   reg_class_names [class_translate [best]]);
 		}
-	      allocno_pref [p_num] = best;
+	      allocno_pref [a_num] = best;
 	    }
 	}
       
-      if (ira_dump_file)
+      if (internal_flag_ira_verbose > 4 && ira_dump_file)
 	{
 	  print_costs (ira_dump_file);
 	  fprintf (ira_dump_file,"\n");
@@ -1244,10 +1299,10 @@ find_allocno_class_costs (void)
    register are already taken into account slightly in class costs for
    the allocno.  */
 static void
-process_bb_node_for_hard_reg_moves (struct ira_loop_tree_node *loop_tree_node)
+process_bb_node_for_hard_reg_moves (loop_tree_node_t loop_tree_node)
 {
   int i, freq, cost, src_regno, dst_regno, hard_regno, to_p;
-  allocno_t p;
+  allocno_t a;
   enum reg_class class, hard_reg_class;
   enum machine_mode mode;
   basic_block bb;
@@ -1259,7 +1314,6 @@ process_bb_node_for_hard_reg_moves (stru
   freq = REG_FREQ_FROM_BB (bb);
   if (freq == 0)
     freq = 1;
-  curr_regno_allocno_map = ira_curr_loop_tree_node->regno_allocno_map;
   FOR_BB_INSNS (bb, insn)
     {
       if (! INSN_P (insn))
@@ -1278,48 +1332,48 @@ process_bb_node_for_hard_reg_moves (stru
 	{
 	  hard_regno = src_regno;
 	  to_p = TRUE;
-	  p = curr_regno_allocno_map [dst_regno];
+	  a = ira_curr_regno_allocno_map [dst_regno];
 	}
       else if (src_regno >= FIRST_PSEUDO_REGISTER
 	       && dst_regno < FIRST_PSEUDO_REGISTER)
 	{
 	  hard_regno = dst_regno;
 	  to_p = FALSE;
-	  p = curr_regno_allocno_map [src_regno];
+	  a = ira_curr_regno_allocno_map [src_regno];
 	}
       else
 	continue;
-      class = ALLOCNO_COVER_CLASS (p);
+      class = ALLOCNO_COVER_CLASS (a);
       if (! TEST_HARD_REG_BIT (reg_class_contents [class], hard_regno))
 	continue;
       i = class_hard_reg_index [class] [hard_regno];
       if (i < 0)
 	continue;
-      mode = ALLOCNO_MODE (p);
+      mode = ALLOCNO_MODE (a);
       hard_reg_class = REGNO_REG_CLASS (hard_regno);
       cost = (to_p ? register_move_cost [mode] [hard_reg_class] [class]
 	      : register_move_cost [mode] [class] [hard_reg_class]) * freq;
-      ALLOCNO_HARD_REG_COSTS (p) [i] -= cost;
-      ALLOCNO_CONFLICT_HARD_REG_COSTS (p) [i] -= cost;
-      ALLOCNO_COVER_CLASS_COST (p) = MIN (ALLOCNO_COVER_CLASS_COST (p),
-					 ALLOCNO_HARD_REG_COSTS (p) [i]);
+      ALLOCNO_HARD_REG_COSTS (a) [i] -= cost;
+      ALLOCNO_CONFLICT_HARD_REG_COSTS (a) [i] -= cost;
+      ALLOCNO_COVER_CLASS_COST (a) = MIN (ALLOCNO_COVER_CLASS_COST (a),
+					  ALLOCNO_HARD_REG_COSTS (a) [i]);
       if (flag_ira_algorithm == IRA_ALGORITHM_REGIONAL
 	  || flag_ira_algorithm == IRA_ALGORITHM_MIXED)
 	{
-	  struct ira_loop_tree_node *father;
-	  int regno = ALLOCNO_REGNO (p);
+	  loop_tree_node_t father;
+	  int regno = ALLOCNO_REGNO (a);
 	  
 	  for (;;)
 	    {
-	      if ((father = ALLOCNO_LOOP_TREE_NODE (p)->father) == NULL)
+	      if ((father = ALLOCNO_LOOP_TREE_NODE (a)->father) == NULL)
 	        break;
-	      if ((p = father->regno_allocno_map [regno]) == NULL)
+	      if ((a = father->regno_allocno_map [regno]) == NULL)
 		break;
-	      ALLOCNO_HARD_REG_COSTS (p) [i] -= cost;
-	      ALLOCNO_CONFLICT_HARD_REG_COSTS (p) [i] -= cost;
-	      ALLOCNO_COVER_CLASS_COST (p)
-		= MIN (ALLOCNO_COVER_CLASS_COST (p),
-		       ALLOCNO_HARD_REG_COSTS (p) [i]);
+	      ALLOCNO_HARD_REG_COSTS (a) [i] -= cost;
+	      ALLOCNO_CONFLICT_HARD_REG_COSTS (a) [i] -= cost;
+	      ALLOCNO_COVER_CLASS_COST (a)
+		= MIN (ALLOCNO_COVER_CLASS_COST (a),
+		       ALLOCNO_HARD_REG_COSTS (a) [i]);
 	    }
 	}
     }
@@ -1331,45 +1385,46 @@ process_bb_node_for_hard_reg_moves (stru
 static void
 setup_allocno_cover_class_and_costs (void)
 {
-  int i, j, n, regno, cost, min_cost;
-  int *reg_costs, *reg_conflict_costs;
+  int i, j, n, regno;
+  int *reg_costs;
+  int *reg_conflict_costs;
   enum reg_class cover_class, class;
   enum machine_mode mode;
-  allocno_t p;
+  allocno_t a;
 
   for (i = 0; i < allocnos_num; i++)
     {
-      p = allocnos [i];
-      mode = ALLOCNO_MODE (p);
+      a = allocnos [i];
+      mode = ALLOCNO_MODE (a);
       cover_class = class_translate [allocno_pref [i]];
       ira_assert (allocno_pref [i] == NO_REGS || cover_class != NO_REGS);
-      ALLOCNO_ORIGINAL_MEMORY_COST (p)
-	= ALLOCNO_MEMORY_COST (p) = costs [i].mem_cost;
-      ALLOCNO_COVER_CLASS (p) = cover_class;
-      ALLOCNO_BEST_CLASS (p) = allocno_pref [i];
+      ALLOCNO_MEMORY_COST (a) = ALLOCNO_UPDATED_MEMORY_COST (a)
+	= COSTS_OF_ALLOCNO (total_costs, i)->mem_cost;
+      ALLOCNO_COVER_CLASS (a) = cover_class;
+      ALLOCNO_BEST_CLASS (a) = allocno_pref [i];
       if (cover_class == NO_REGS)
 	continue;
-      ALLOCNO_AVAILABLE_REGS_NUM (p) = available_class_regs [cover_class];
-      min_cost = costs [i].cost [allocno_pref [i]];
-      ALLOCNO_COVER_CLASS_COST (p) = min_cost;
+      ALLOCNO_AVAILABLE_REGS_NUM (a) = available_class_regs [cover_class];
+      ALLOCNO_COVER_CLASS_COST (a)
+	= (COSTS_OF_ALLOCNO (total_costs, i)
+	   ->cost [important_class_nums [allocno_pref [i]]]);
       n = class_hard_regs_num [cover_class];
-      ALLOCNO_HARD_REG_COSTS (p) = reg_costs = ira_allocate (n * sizeof (int));
-      ALLOCNO_CONFLICT_HARD_REG_COSTS (p)
+      ALLOCNO_HARD_REG_COSTS (a) = reg_costs = ira_allocate (n * sizeof (int));
+      ALLOCNO_CONFLICT_HARD_REG_COSTS (a)
 	= reg_conflict_costs = ira_allocate (n * sizeof (int));
-      ALLOCNO_CURR_HARD_REG_COSTS (p) = ira_allocate (n * sizeof (int));
-      ALLOCNO_CURR_CONFLICT_HARD_REG_COSTS (p)
+      ALLOCNO_UPDATED_HARD_REG_COSTS (a) = ira_allocate (n * sizeof (int));
+      ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (a)
 	= ira_allocate (n * sizeof (int));
       memset (reg_conflict_costs, 0, n * sizeof (int));
       for (j = n - 1; j >= 0; j--)
 	{
 	  regno = class_hard_regs [cover_class] [j];
 	  class = REGNO_REG_CLASS (regno);
-	  /* ??? what is cost AREG when DImode.  Should be ok.  */
-	  cost = costs [i].cost [class];
-	  reg_costs [j] = cost;
+	  reg_costs [j] = (COSTS_OF_ALLOCNO (total_costs, i)
+			   ->cost [important_class_nums [class]]);
 	}
     }
-  traverse_loop_tree (ira_loop_tree_root,
+  traverse_loop_tree (FALSE, ira_loop_tree_root,
 		      process_bb_node_for_hard_reg_moves, NULL);
 }
 
@@ -1382,9 +1437,33 @@ init_ira_costs_once (void)
 {
   int i;
 
-  init_cost.mem_cost = 10000;
-  for (i = 0; i < N_REG_CLASSES; i++)
-    init_cost.cost [i] = 10000;
+  struct_costs_size
+    = sizeof (struct costs) + sizeof (int) * (important_classes_num - 1);
+  init_cost = xmalloc (struct_costs_size);
+  init_cost->mem_cost = 10000;
+  for (i = 0; i < important_classes_num; i++)
+    init_cost->cost [i] = 10000;
+  for (i = 0; i < MAX_RECOG_OPERANDS; i++)
+    {
+      op_costs [i] = xmalloc (struct_costs_size);
+      this_op_costs [i] = xmalloc (struct_costs_size);
+    }
+  temp_costs = xmalloc (struct_costs_size);
+}
+
+/* Function called once at the end of compiler work.  */
+void
+finish_ira_costs_once (void)
+{
+  int i;
+
+  free (temp_costs);
+  for (i = MAX_RECOG_OPERANDS - 1; i >= 0; i--)
+    {
+      free (this_op_costs [i]);
+      free (op_costs [i]);
+    }
+  free (init_cost);
 }
 
 
@@ -1394,12 +1473,12 @@ init_ira_costs_once (void)
 void
 ira_costs (void)
 {
-  costs = ira_allocate (sizeof (struct costs) * allocnos_num);
+  total_costs = ira_allocate (struct_costs_size * allocnos_num);
   allocno_pref_buffer = ira_allocate (sizeof (enum reg_class) * allocnos_num);
   find_allocno_class_costs ();
   setup_allocno_cover_class_and_costs ();
   ira_free (allocno_pref_buffer);
-  ira_free (costs);
+  ira_free (total_costs);
 }
 
 
@@ -1410,24 +1489,25 @@ ira_costs (void)
 void
 tune_allocno_costs_and_cover_classes (void)
 {
-  int i, j, k, n, regno, cost, min_cost, *reg_costs, freq;
+  int i, j, k, n, regno, freq;
+  int cost, min_cost, *reg_costs;
   enum reg_class cover_class, class;
   enum machine_mode mode;
-  allocno_t p;
+  allocno_t a;
   rtx call, *allocno_calls;
   HARD_REG_SET clobbered_regs;
 
   for (i = 0; i < allocnos_num; i++)
     {
-      p = allocnos [i];
-      cover_class = ALLOCNO_COVER_CLASS (p);
+      a = allocnos [i];
+      cover_class = ALLOCNO_COVER_CLASS (a);
       if (cover_class == NO_REGS)
 	continue;
-      mode = ALLOCNO_MODE (p);
+      mode = ALLOCNO_MODE (a);
       n = class_hard_regs_num [cover_class];
-      reg_costs = ALLOCNO_HARD_REG_COSTS (p);
+      reg_costs = ALLOCNO_HARD_REG_COSTS (a);
       min_cost = INT_MAX;
-      if (ALLOCNO_CALLS_CROSSED_NUM (p) != 0)
+      if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
 	for (j = n - 1; j >= 0; j--)
 	  {
 	    regno = class_hard_regs [cover_class] [j];
@@ -1437,17 +1517,19 @@ tune_allocno_costs_and_cover_classes (vo
 	      {
 		/* ??? If only part is call clobbered.  */
 		if (! hard_reg_not_in_set_p (regno, mode, call_used_reg_set))
-		  cost += (ALLOCNO_CALL_FREQ (p)
-			   * (memory_move_cost [mode] [class] [0]
-			      + memory_move_cost [mode] [class] [1]));
+		  {
+		    cost += (ALLOCNO_CALL_FREQ (a)
+			     * (memory_move_cost [mode] [class] [0]
+				+ memory_move_cost [mode] [class] [1]));
+		  }
 	      }
 	    else
 	      {
 		allocno_calls
-		  = (VEC_address (rtx, regno_calls [ALLOCNO_REGNO (p)])
-		     + ALLOCNO_CALLS_CROSSED_START (p));
+		  = (VEC_address (rtx, regno_calls [ALLOCNO_REGNO (a)])
+		     + ALLOCNO_CALLS_CROSSED_START (a));
 		ira_assert (allocno_calls != NULL); 
-		for (k = ALLOCNO_CALLS_CROSSED_NUM (p) - 1; k >= 0; k--)
+		for (k = ALLOCNO_CALLS_CROSSED_NUM (a) - 1; k >= 0; k--)
 		  {
 		    call = allocno_calls [k];
 		    freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (call));
@@ -1457,21 +1539,22 @@ tune_allocno_costs_and_cover_classes (vo
 						    FALSE);
 		    /* ??? If only part is call clobbered.  */
 		    if (! hard_reg_not_in_set_p (regno, mode, clobbered_regs))
-		      cost += freq * (memory_move_cost [mode] [class] [0]
-				      + memory_move_cost [mode] [class] [1]);
+		      cost
+			+= freq * (memory_move_cost [mode] [class] [0]
+				   + memory_move_cost [mode] [class] [1]);
 		  }
 	      }
 #ifdef IRA_HARD_REGNO_ADD_COST_MULTIPLIER
 	    cost += ((memory_move_cost [mode] [class] [0]
-		      + memory_move_cost [mode] [class] [1]) * ALLOCNO_FREQ (p)
+		      + memory_move_cost [mode] [class] [1])
+		     * ALLOCNO_FREQ (a)
 		     * IRA_HARD_REGNO_ADD_COST_MULTIPLIER (regno) / 2);
 #endif
 	    reg_costs [j] += cost;
 	    if (min_cost > reg_costs [j])
 	      min_cost = reg_costs [j];
 	  }
-      if (min_cost == INT_MAX)
-	continue;
-      ALLOCNO_COVER_CLASS_COST (p) = min_cost;
+      if (min_cost != INT_MAX)
+	ALLOCNO_COVER_CLASS_COST (a) = min_cost;
     }
 }
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 129968)
+++ Makefile.in	(working copy)
@@ -833,7 +833,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)
+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
 
@@ -1068,11 +1068,11 @@ OBJS-common = \
 	intl.o \
 	ira.o \
 	ira-build.o \
-	ira-call.o \
 	ira-costs.o \
 	ira-conflicts.o \
 	ira-color.o \
 	ira-emit.o \
+	ira-lives.o \
 	jump.o \
 	lambda-code.o \
 	lambda-mat.o \
@@ -2760,10 +2760,6 @@ ira-build.o: ira-build.c $(CONFIG_H) $(S
    $(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) $(IRA_INT_H)
-ira-call.o: ira-call.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
-   $(TARGET_H) $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) errors.h \
-   $(BASIC_BLOCK_H) $(TM_P_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 \
@@ -2781,6 +2777,10 @@ ira-emit.o: ira-emit.c $(CONFIG_H) $(SYS
    $(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) $(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) \

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