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]

[PATCH] flow.c cleanup


Hello,

the patch below is cleanup of flow.c; it splits more or less unrelated
tasks (log links creation, pre/post modify transformation, ...) out
of liveness analysis.

This results in more passes though insns and significant slow down of
compiler (about 20%). To counter this, I extract the neccesary
information about insn (set and used registers, ...) and recompute this
information only if the insn changes. The loss of speed is thus reduced
to about 4% (measured on Pentium 4 with -O2). The code to verify
actuality of these extracts is enabled by --enable-checking=insninfo
(while it would be a good idea to check it always, as there probably
are more places where insns are altered than I found, the overhead of
20% for the check seems too much for me to be turned on by default).

I have bootstrapped and regtested it on Pentium 4. It also compiles
as ia64 crosscompiler (to test pre/post modify transformation &
conditional execution) and the output produced for medium sized
program (gap from spec2000) is byte-to-byte identical with unpatched
gcc.

Zdenek Dvorak

Changelog:

	* Makefile.in (rtlanal.o): Add regs.h and function.h dependency.
	* configure.in (ac_insninfo_checking): New.
	* basic-block.h (enum update_life_extent): Deleted.
	(PROP_DEATH_NOTES, PROP_LOG_LINKS, PROP_REG_INFO, PROP_AUTOINC,
	PROP_EQUAL_NOTES): Deleted.
	(update_life_info, update_life_info_in_dirty_blocks): Declaration
	changed.
	(compute_death_notes, create_log_links, pre_post_modify_transformation):
	Declare.
	* rtl.h (struct insn_extract, enum insn_extract_flags): New.
	(cached_insn_extracts): New global variable declaration.
	(initialize_cached_insn_extracts, initialize_insn_info,
	extract_insn_info, release_insn_info, invalidate_insn_extracts,
	invalidate_insn_extracts_regs_altered, invalidate_insn_extract,
	debug_insn_extract): Declare.
	(recompute_reg_usage): Renamed to ...
	(compute_reg_usage): Declare.
	* rtlanal.c: Include function.h and regs.h.
	(cached_insn_extracts): New global variable.
	(record_set_regs, record_set_1, record_used_regs, record_used_reg,
	insn_extract_elems_hash, insn_info_hash, debug_insn_extract_elems):
	New static functions.
	(initialize_cached_insn_extracts, initialize_insn_info,
	extract_insn_info, release_insn_info, invalidate_insn_extracts,
	invalidate_insn_extracts_regs_altered, invalidate_insn_extract,
	debug_insn_extract): New.
	* flow.c (mark_set_regs, mark_set_1, mark_used_reg, mark_used_regs):
	Deleted.
	(insn_dead_p, attempt_auto_inc, find_auto_inc,
	life_analysis, update_life_info, update_life_info_in_dirty_blocks,
	init_propagate_block_info, free_propagate_block_info, propagate_block,
	libcall_dead_p, add_to_mem_set_list, invalidate_mems_from_set):
	Modified.
	(recompute_reg_usage): Modified and renamed to compute_reg_usage.
	(propagate_one_insn): Stuff unrelated to liveness analysis moved
	elsewhere.
	(autoinc_transform, kill_dead_insn, set_up_log_links,
	update_next_use_sets, update_next_use_uses, update_live_by_sets,
	update_live_by_uses, update_mems_by_sets, update_mems_by_uses,
	create_unused_notes, create_dead_notes, count_register_info_for_sets,
	count_register_info_for_uses): New functions.
	* toplev.c (rest_of_compilation): Use new functions.
	* cfgcleanup.c (cleanup_cfg): Ditto.
	* cfgrtl.c (purge_all_dead_edges): Ditto.
	* ifcvt.c (if_convert): Ditto.
	* lcm.v (optimize_mode_switching): Ditto.
	* ra.c (reg_alloc): Ditto.
	* reg-stack.c (reg_to_stack): Ditto.
	* sched-rgn.c (schedule_insns): Ditto.
	* ssa.c (convert_from_ssa): Ditto.
	* config/ia64/ia64.c (ia64_reorg): Ditto.
	* config/ip2k/ip2k.c (machine_dependent_reorg): Ditto.
	* config/m68hc11/m68hc11.c (m68hc11_reorg): Ditto.
	* combine.c (combine_instructions): Ditto.
	(try_combine): Update insn extracts.
	* regrename.c (regrename_optimize, copyprop_hardreg_forward):
	Use new functions.
	(copyprop_hardreg_forward_1, do_replace): Update insn extracts.
	* recog.c (apply_change_group): Update insn extracts.
	(split_all_insns, peephole2_optimize): Use new functions.
	* emit-rtl.c (renumber_insns, try_split): Update insn extracts.
	* reload1.c (reload_as_needed): Ditto.
	* reg-stack.c (replace_reg, move_for_stack_reg, compare_for_stack_reg,
	subst_stack_regs_pat, subst_asm_stack_regs): Ditto.
	* regmove.c (copy_src_to_dest): Comment update.
	(optimize_reg_copy_2): Update insn extracts.
	* varray.c (element_size, uses_ggc): Support new types.
	* varray.h (enum varray_data_enum, varray_data_tag): Ditto.
	(VARRAY_IE_ELEM_INIT, VARRAY_IE_INIT, VARRAY_IE_ELEM, VARRAY_IE,
	VARRAY_PUSH_IE_ELEM, VARRAY_PUSH_IE, VARRAY_TOP_IE_ELEM,
	VARRAY_TOP_IE): New.
	(struct insn_extract_elem): New.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.961
diff -c -3 -p -r1.961 Makefile.in
*** Makefile.in	19 Dec 2002 15:53:46 -0000	1.961
--- Makefile.in	29 Dec 2002 20:25:14 -0000
*************** rtl.o : rtl.c $(CONFIG_H) $(SYSTEM_H) co
*** 1419,1425 ****
  print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
      hard-reg-set.h $(BASIC_BLOCK_H) real.h
  rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h $(RTL_H) \
!    hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) real.h flags.h
  
  errors.o : errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) errors.h
  	$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
--- 1419,1426 ----
  print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
      hard-reg-set.h $(BASIC_BLOCK_H) real.h
  rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h $(RTL_H) \
!    hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) real.h flags.h \
!    $(REGS_H) function.h
  
  errors.o : errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) errors.h
  	$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.163
diff -c -3 -p -r1.163 basic-block.h
*** basic-block.h	19 Dec 2002 02:59:15 -0000	1.163
--- basic-block.h	29 Dec 2002 20:25:17 -0000
*************** int find_edge_index			PARAMS ((struct ed
*** 619,646 ****
  						 basic_block, basic_block));
  
  
- enum update_life_extent
- {
-   UPDATE_LIFE_LOCAL = 0,
-   UPDATE_LIFE_GLOBAL = 1,
-   UPDATE_LIFE_GLOBAL_RM_NOTES = 2
- };
- 
  /* Flags for life_analysis and update_life_info.  */
  
! #define PROP_DEATH_NOTES	1	/* Create DEAD and UNUSED notes.  */
! #define PROP_LOG_LINKS		2	/* Create LOG_LINKS.  */
! #define PROP_REG_INFO		4	/* Update regs_ever_live et al.  */
! #define PROP_KILL_DEAD_CODE	8	/* Remove dead code.  */
! #define PROP_SCAN_DEAD_CODE	16	/* Scan for dead code.  */
! #define PROP_ALLOW_CFG_CHANGES	32	/* Allow the CFG to be changed
  					   by dead code removal.  */
! #define PROP_AUTOINC		64	/* Create autoinc mem references.  */
! #define PROP_EQUAL_NOTES	128	/* Take into account REG_EQUAL notes.  */
! #define PROP_SCAN_DEAD_STORES	256	/* Scan for dead code.  */
! #define PROP_FINAL		(PROP_DEATH_NOTES | PROP_LOG_LINKS  \
! 				 | PROP_REG_INFO | PROP_KILL_DEAD_CODE  \
! 				 | PROP_SCAN_DEAD_CODE | PROP_AUTOINC \
  				 | PROP_ALLOW_CFG_CHANGES \
  				 | PROP_SCAN_DEAD_STORES)
  
--- 619,633 ----
  						 basic_block, basic_block));
  
  
  /* Flags for life_analysis and update_life_info.  */
  
! #define PROP_KILL_DEAD_CODE	1	/* Remove dead code.  */
! #define PROP_SCAN_DEAD_CODE	2	/* Scan for dead code.  */
! #define PROP_ALLOW_CFG_CHANGES	4	/* Allow the CFG to be changed
  					   by dead code removal.  */
! #define PROP_SCAN_DEAD_STORES	8	/* Scan for dead code.  */
! #define PROP_FINAL		(PROP_KILL_DEAD_CODE  \
! 				 | PROP_SCAN_DEAD_CODE \
  				 | PROP_ALLOW_CFG_CHANGES \
  				 | PROP_SCAN_DEAD_STORES)
  
*************** enum update_life_extent
*** 667,676 ****
  #define LOOP_ALL	       15	/* All of the above  */
  
  extern void life_analysis	PARAMS ((rtx, FILE *, int));
! extern int update_life_info	PARAMS ((sbitmap, enum update_life_extent,
! 					 int));
! extern int update_life_info_in_dirty_blocks PARAMS ((enum update_life_extent,
! 						      int));
  extern int count_or_remove_death_notes	PARAMS ((sbitmap, int));
  extern int propagate_block	PARAMS ((basic_block, regset, regset, regset,
  					 int));
--- 654,662 ----
  #define LOOP_ALL	       15	/* All of the above  */
  
  extern void life_analysis	PARAMS ((rtx, FILE *, int));
! extern int update_life_info	PARAMS ((sbitmap, int));
! extern int update_life_info_in_dirty_blocks PARAMS ((int, sbitmap *));
! extern void compute_death_notes	PARAMS ((sbitmap));
  extern int count_or_remove_death_notes	PARAMS ((sbitmap, int));
  extern int propagate_block	PARAMS ((basic_block, regset, regset, regset,
  					 int));
*************** extern rtx propagate_one_insn	PARAMS ((s
*** 680,685 ****
--- 666,675 ----
  extern struct propagate_block_info *init_propagate_block_info
    PARAMS ((basic_block, regset, regset, regset, int));
  extern void free_propagate_block_info PARAMS ((struct propagate_block_info *));
+ extern void create_log_links	PARAMS ((sbitmap));
+ #ifdef AUTO_INC_DEC
+ extern void pre_post_modify_transformation	PARAMS ((sbitmap));
+ #endif
  
  /* In lcm.c */
  extern struct edge_list *pre_edge_lcm	PARAMS ((FILE *, int, sbitmap *,
Index: cfgcleanup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgcleanup.c,v
retrieving revision 1.69
diff -c -3 -p -r1.69 cfgcleanup.c
*** cfgcleanup.c	16 Dec 2002 18:19:07 -0000	1.69
--- cfgcleanup.c	29 Dec 2002 20:25:23 -0000
*************** cleanup_cfg (mode)
*** 1790,1803 ****
        delete_unreachable_blocks (), changed = true;
        if (mode & CLEANUP_UPDATE_LIFE)
  	{
  	  /* Cleaning up CFG introduces more oppurtunities for dead code
  	     removal that in turn may introduce more oppurtunities for
  	     cleaning up the CFG.  */
! 	  if (!update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
! 						 PROP_DEATH_NOTES
! 						 | PROP_SCAN_DEAD_CODE
! 						 | PROP_KILL_DEAD_CODE
! 						 | PROP_LOG_LINKS))
  	    break;
  	}
        else if (!(mode & (CLEANUP_NO_INSN_DEL | CLEANUP_PRE_SIBCALL))
--- 1790,1808 ----
        delete_unreachable_blocks (), changed = true;
        if (mode & CLEANUP_UPDATE_LIFE)
  	{
+ 	  int dead_code_removed;
+ 	  sbitmap dirty_blocks;
+ 
  	  /* Cleaning up CFG introduces more oppurtunities for dead code
  	     removal that in turn may introduce more oppurtunities for
  	     cleaning up the CFG.  */
! 	  dead_code_removed =
! 	    update_life_info_in_dirty_blocks (PROP_SCAN_DEAD_CODE
! 					      | PROP_KILL_DEAD_CODE,
! 					      &dirty_blocks);
! 	  compute_death_notes (dirty_blocks);
! 	  sbitmap_free (dirty_blocks);
! 	  if (!dead_code_removed)
  	    break;
  	}
        else if (!(mode & (CLEANUP_NO_INSN_DEL | CLEANUP_PRE_SIBCALL))
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.62
diff -c -3 -p -r1.62 cfgrtl.c
*** cfgrtl.c	16 Dec 2002 18:19:07 -0000	1.62
--- cfgrtl.c	29 Dec 2002 20:25:28 -0000
*************** purge_all_dead_edges (update_life_p)
*** 2295,2303 ****
      }
  
    if (update_life_p && purged)
!     update_life_info (blocks, UPDATE_LIFE_GLOBAL,
! 		      PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
! 		      | PROP_KILL_DEAD_CODE);
  
    if (update_life_p)
      sbitmap_free (blocks);
--- 2295,2304 ----
      }
  
    if (update_life_p && purged)
!     {
!       update_life_info (blocks, PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE);
!       compute_death_notes (blocks);
!     }
  
    if (update_life_p)
      sbitmap_free (blocks);
Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.326
diff -c -3 -p -r1.326 combine.c
*** combine.c	16 Dec 2002 18:19:08 -0000	1.326
--- combine.c	29 Dec 2002 20:26:06 -0000
*************** combine_instructions (f, nregs)
*** 508,513 ****
--- 508,514 ----
    rtx links, nextlinks;
  
    int new_direct_jump_p = 0;
+   sbitmap dirty_blocks;
  
    combine_attempts = 0;
    combine_merges = 0;
*************** combine_instructions (f, nregs)
*** 735,743 ****
    new_direct_jump_p |= purge_all_dead_edges (0);
    delete_noop_moves (f);
  
!   update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
! 				    PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
! 				    | PROP_KILL_DEAD_CODE);
  
    /* Clean up.  */
    sbitmap_free (refresh_blocks);
--- 736,745 ----
    new_direct_jump_p |= purge_all_dead_edges (0);
    delete_noop_moves (f);
  
!   update_life_info_in_dirty_blocks (PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE,
! 				    &dirty_blocks);
!   compute_death_notes (dirty_blocks);
!   sbitmap_free (dirty_blocks);
  
    /* Clean up.  */
    sbitmap_free (refresh_blocks);
*************** try_combine (i3, i2, i1, new_direct_jump
*** 2846,2851 ****
--- 2848,2861 ----
  	&& SET_DEST (newpat) == pc_rtx)
        *new_direct_jump_p = 1;
    }
+ 
+   /* Invalidate insn_extracts.  */
+   if (undobuf.other_insn != NULL_RTX)
+     invalidate_insn_extract (undobuf.other_insn);
+   invalidate_insn_extract (i3);
+   invalidate_insn_extract (i2);
+   if (i1)
+     invalidate_insn_extract (i1);
  
    combine_successes++;
    undo_commit ();
Index: configure.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/configure.in,v
retrieving revision 1.631
diff -c -3 -p -r1.631 configure.in
*** configure.in	28 Dec 2002 20:51:33 -0000	1.631
--- configure.in	29 Dec 2002 20:26:35 -0000
*************** AC_ARG_ENABLE(checking,
*** 269,280 ****
  [  --enable-checking[=LIST]
  			  enable expensive run-time checks.  With LIST,
  			  enable only specific categories of checks.
! 			  Categories are: misc,tree,rtl,rtlflag,gc,gcac;
! 			  default is misc,tree,gc,rtlflag],
  [ac_checking=
  ac_tree_checking=
  ac_rtl_checking=
  ac_rtlflag_checking=
  ac_gc_checking=
  ac_gc_always_collect=
  case "${enableval}" in
--- 269,281 ----
  [  --enable-checking[=LIST]
  			  enable expensive run-time checks.  With LIST,
  			  enable only specific categories of checks.
! 			  Categories are: misc,tree,rtl,rtlflag,gc,gcac,
! 			  valgrind,insninfo; default is misc,tree,gc,rtlflag],
  [ac_checking=
  ac_tree_checking=
  ac_rtl_checking=
  ac_rtlflag_checking=
+ ac_insninfo_checking=
  ac_gc_checking=
  ac_gc_always_collect=
  case "${enableval}" in
*************** no)	;;
*** 290,295 ****
--- 291,297 ----
  		misc)	ac_checking=1 ;;
  		tree)	ac_tree_checking=1 ;;
  		rtlflag)	ac_rtlflag_checking=1 ;;
+ 		insninfo)	ac_insninfo_checking=1 ;;
  		rtl)	ac_rtl_checking=1 ;;
  		gc)	ac_gc_checking=1 ;;
  		gcac)	ac_gc_always_collect=1 ;;
*************** if test x$ac_rtl_checking != x ; then
*** 321,326 ****
--- 323,333 ----
  [Define if you want all operations on RTL (the basic data structure
     of the optimizer and back end) to be checked for dynamic type safety
     at runtime.  This is quite expensive.])
+ fi
+ if test x$ac_insninfo_checking != x ; then
+   AC_DEFINE(ENABLE_INSNINFO_CHECKING, 1,
+ [Define if you want to check actuality of insn extracts. This is
+    moderately expensive.])
  fi
  if test x$ac_rtlflag_checking != x ; then
    AC_DEFINE(ENABLE_RTL_FLAG_CHECKING, 1,
Index: emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.304
diff -c -3 -p -r1.304 emit-rtl.c
*** emit-rtl.c	16 Dec 2002 18:19:24 -0000	1.304
--- emit-rtl.c	29 Dec 2002 20:26:46 -0000
*************** renumber_insns (stream)
*** 2885,2890 ****
--- 2885,2892 ----
       FILE *stream;
  {
    rtx insn;
+   struct insn_extract **old_insn_extracts = NULL;
+   unsigned i, n = 0;
  
    /* If we're not supposed to renumber instructions, don't.  */
    if (!flag_renumber_insns)
*************** renumber_insns (stream)
*** 2897,2909 ****
--- 2899,2942 ----
  
    cur_insn_uid = 1;
  
+   if (cached_insn_extracts)
+     {
+       n = VARRAY_SIZE (cached_insn_extracts);
+       old_insn_extracts = xmalloc (sizeof (struct insn_extract *) * n);
+       for (i = 0; i < n; i++)
+ 	{
+ 	  old_insn_extracts[i] = VARRAY_IE (cached_insn_extracts, i);
+ 	  VARRAY_IE (cached_insn_extracts, i) = NULL;
+ 	}
+     }
+ 
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      {
        if (stream)
  	fprintf (stream, "Renumbering insn %d to %d\n",
  		 INSN_UID (insn), cur_insn_uid);
+       if (cached_insn_extracts && (unsigned) INSN_UID (insn) < n)
+ 	{
+ 	  if ((unsigned) cur_insn_uid >= n)
+ 	    VARRAY_GROW (cached_insn_extracts, cur_insn_uid + 1);
+ 	  VARRAY_IE (cached_insn_extracts, cur_insn_uid) =
+ 	    old_insn_extracts[INSN_UID (insn)];
+ 	  old_insn_extracts[INSN_UID (insn)] = NULL;
+ 	}
        INSN_UID (insn) = cur_insn_uid++;
      }
+ 
+   if (cached_insn_extracts)
+     {
+       /* Release the remaining extracts.  */
+       for (i = 0; i < n; i++)
+ 	if (old_insn_extracts[i])
+ 	  {
+ 	    release_insn_info (old_insn_extracts[i]);
+ 	    free (old_insn_extracts[i]);
+ 	  }
+       free (old_insn_extracts);
+     }
  }
  
  /* Return the next insn.  If it is a SEQUENCE, return the first insn
*************** try_split (pat, trial, last)
*** 3377,3382 ****
--- 3410,3416 ----
        else
  	{
  	  PATTERN (trial) = PATTERN (seq);
+ 	  invalidate_insn_extract (trial);
  	  INSN_CODE (trial) = -1;
  	  try_split (PATTERN (trial), trial, last);
  	}
Index: flow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.543
diff -c -3 -p -r1.543 flow.c
*** flow.c	20 Dec 2002 01:18:41 -0000	1.543
--- flow.c	29 Dec 2002 20:26:57 -0000
*************** Software Foundation, 59 Temple Place - S
*** 114,121 ****
     Split out from life_analysis:
  	- local property discovery (bb->local_live, bb->local_set)
  	- global property computation
- 	- log links creation
- 	- pre/post modify transformation
  */
  
  #include "config.h"
--- 114,119 ----
*************** static void calculate_global_regs_live	P
*** 298,311 ****
  static void propagate_block_delete_insn PARAMS ((rtx));
  static rtx propagate_block_delete_libcall PARAMS ((rtx, rtx));
  static int insn_dead_p			PARAMS ((struct propagate_block_info *,
! 						 rtx, int, rtx));
  static int libcall_dead_p		PARAMS ((struct propagate_block_info *,
  						 rtx, rtx));
- static void mark_set_regs		PARAMS ((struct propagate_block_info *,
- 						 rtx, rtx));
- static void mark_set_1			PARAMS ((struct propagate_block_info *,
- 						 enum rtx_code, rtx, rtx,
- 						 rtx, int));
  static int find_regno_partial		PARAMS ((rtx *, void *));
  
  #ifdef HAVE_conditional_execution
--- 296,305 ----
  static void propagate_block_delete_insn PARAMS ((rtx));
  static rtx propagate_block_delete_libcall PARAMS ((rtx, rtx));
  static int insn_dead_p			PARAMS ((struct propagate_block_info *,
! 						 struct insn_extract *,
! 						 int, rtx));
  static int libcall_dead_p		PARAMS ((struct propagate_block_info *,
  						 rtx, rtx));
  static int find_regno_partial		PARAMS ((rtx *, void *));
  
  #ifdef HAVE_conditional_execution
*************** static rtx not_reg_cond			PARAMS ((rtx))
*** 321,338 ****
  static rtx and_reg_cond			PARAMS ((rtx, rtx, int));
  #endif
  #ifdef AUTO_INC_DEC
! static void attempt_auto_inc		PARAMS ((struct propagate_block_info *,
  						 rtx, rtx, rtx, rtx, rtx));
! static void find_auto_inc		PARAMS ((struct propagate_block_info *,
  						 rtx, rtx));
  static int try_pre_increment_1		PARAMS ((struct propagate_block_info *,
  						 rtx));
  static int try_pre_increment		PARAMS ((rtx, rtx, HOST_WIDE_INT));
  #endif
- static void mark_used_reg		PARAMS ((struct propagate_block_info *,
- 						 rtx, rtx, rtx));
- static void mark_used_regs		PARAMS ((struct propagate_block_info *,
- 						 rtx, rtx, rtx));
  void dump_flow_info			PARAMS ((FILE *));
  void debug_flow_info			PARAMS ((void));
  static void add_to_mem_set_list		PARAMS ((struct propagate_block_info *,
--- 315,330 ----
  static rtx and_reg_cond			PARAMS ((rtx, rtx, int));
  #endif
  #ifdef AUTO_INC_DEC
! static int attempt_auto_inc		PARAMS ((struct propagate_block_info *,
  						 rtx, rtx, rtx, rtx, rtx));
! static int find_auto_inc		PARAMS ((struct propagate_block_info *,
  						 rtx, rtx));
  static int try_pre_increment_1		PARAMS ((struct propagate_block_info *,
  						 rtx));
  static int try_pre_increment		PARAMS ((rtx, rtx, HOST_WIDE_INT));
+ static int autoinc_transform		PARAMS ((struct propagate_block_info *,
+ 						 struct insn_extract *, rtx));
  #endif
  void dump_flow_info			PARAMS ((FILE *));
  void debug_flow_info			PARAMS ((void));
  static void add_to_mem_set_list		PARAMS ((struct propagate_block_info *,
*************** static int invalidate_mems_from_autoinc 
*** 341,346 ****
--- 333,364 ----
  static void invalidate_mems_from_set	PARAMS ((struct propagate_block_info *,
  						 rtx));
  static void clear_log_links		PARAMS ((sbitmap));
+ static rtx kill_dead_insn		PARAMS ((struct propagate_block_info *,
+ 					      	 rtx, int, rtx));
+ static void set_up_log_links		PARAMS ((rtx,
+ 						 struct propagate_block_info *,
+ 					   	 struct insn_extract *));
+ static void update_next_use_sets	PARAMS ((struct propagate_block_info *,
+ 						 struct insn_extract *));
+ static void update_next_use_uses	PARAMS ((rtx,
+ 						 struct propagate_block_info *,
+ 						 struct insn_extract *));
+ static void update_live_by_sets		PARAMS ((struct propagate_block_info *,
+ 						 struct insn_extract *));
+ static void update_live_by_uses		PARAMS ((struct propagate_block_info *,
+ 						 struct insn_extract *));
+ static void update_mems_by_sets		PARAMS ((struct propagate_block_info *,
+ 					    	 struct insn_extract *));
+ static void update_mems_by_uses		PARAMS ((struct propagate_block_info *,
+ 					    	 struct insn_extract *));
+ static void create_unused_notes		PARAMS ((struct propagate_block_info *,
+ 						 struct insn_extract *, rtx));
+ static void create_dead_notes		PARAMS ((struct propagate_block_info *,
+ 						 struct insn_extract *, rtx));
+ static void count_register_info_for_sets PARAMS ((struct propagate_block_info *,
+ 						  struct insn_extract *));
+ static void count_register_info_for_uses PARAMS ((struct propagate_block_info *,
+ 						  struct insn_extract *));
  
  
  void
*************** life_analysis (f, file, flags)
*** 433,460 ****
    SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
  #endif
  
- 
- #ifdef CANNOT_CHANGE_MODE_CLASS
-   if (flags & PROP_REG_INFO)
-     for (i=0; i < NUM_MACHINE_MODES; ++i)
-       INIT_REG_SET (&subregs_of_mode[i]);
- #endif
- 
    if (! optimize)
!     flags &= ~(PROP_LOG_LINKS | PROP_AUTOINC | PROP_ALLOW_CFG_CHANGES);
! 
!   /* The post-reload life analysis have (on a global basis) the same
!      registers live as was computed by reload itself.  elimination
!      Otherwise offsets and such may be incorrect.
! 
!      Reload will make some registers as live even though they do not
!      appear in the rtl.
! 
!      We don't want to create new auto-incs after reload, since they
!      are unlikely to be useful and can cause problems with shared
!      stack slots.  */
!   if (reload_completed)
!     flags &= ~(PROP_REG_INFO | PROP_AUTOINC);
  
    /* We want alias analysis information for local dead store elimination.  */
    if (optimize && (flags & PROP_SCAN_DEAD_STORES))
--- 451,458 ----
    SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
  #endif
  
    if (! optimize)
!     flags &= ~PROP_ALLOW_CFG_CHANGES;
  
    /* We want alias analysis information for local dead store elimination.  */
    if (optimize && (flags & PROP_SCAN_DEAD_STORES))
*************** life_analysis (f, file, flags)
*** 481,490 ****
    /* "Update" life info from zero.  It'd be nice to begin the
       relaxation with just the exit and noreturn blocks, but that set
       is not immediately handy.  */
! 
!   if (flags & PROP_REG_INFO)
!     memset (regs_ever_live, 0, sizeof (regs_ever_live));
!   update_life_info (NULL, UPDATE_LIFE_GLOBAL, flags);
  
    /* Clean up.  */
    if (optimize && (flags & PROP_SCAN_DEAD_STORES))
--- 479,485 ----
    /* "Update" life info from zero.  It'd be nice to begin the
       relaxation with just the exit and noreturn blocks, but that set
       is not immediately handy.  */
!   update_life_info (NULL, flags);
  
    /* Clean up.  */
    if (optimize && (flags & PROP_SCAN_DEAD_STORES))
*************** verify_local_live_at_start (new_live_at_
*** 607,775 ****
  }
  
  /* Updates life information starting with the basic blocks set in BLOCKS.
!    If BLOCKS is null, consider it to be the universal set.
! 
!    If EXTENT is UPDATE_LIFE_LOCAL, such as after splitting or peepholeing,
!    we are only expecting local modifications to basic blocks.  If we find
!    extra registers live at the beginning of a block, then we either killed
!    useful data, or we have a broken split that wants data not provided.
!    If we find registers removed from live_at_start, that means we have
!    a broken peephole that is killing a register it shouldn't.
! 
!    ??? This is not true in one situation -- when a pre-reload splitter
!    generates subregs of a multi-word pseudo, current life analysis will
!    lose the kill.  So we _can_ have a pseudo go live.  How irritating.
! 
!    Including PROP_REG_INFO does not properly refresh regs_ever_live
!    unless the caller resets it to zero.  */
  
  int
! update_life_info (blocks, extent, prop_flags)
       sbitmap blocks;
-      enum update_life_extent extent;
       int prop_flags;
  {
    regset tmp;
    regset_head tmp_head;
-   int i;
-   int stabilized_prop_flags = prop_flags;
    basic_block bb;
  
    tmp = INITIALIZE_REG_SET (tmp_head);
    ndead = 0;
  
!   timevar_push ((extent == UPDATE_LIFE_LOCAL || blocks)
! 		? TV_LIFE_UPDATE : TV_LIFE);
! 
!   /* Changes to the CFG are only allowed when
!      doing a global update for the entire CFG.  */
!   if ((prop_flags & PROP_ALLOW_CFG_CHANGES)
!       && (extent == UPDATE_LIFE_LOCAL || blocks))
!     abort ();
! 
!   /* For a global update, we go through the relaxation process again.  */
!   if (extent != UPDATE_LIFE_LOCAL)
!     {
!       for ( ; ; )
! 	{
! 	  int changed = 0;
! 
! 	  calculate_global_regs_live (blocks, blocks,
! 				prop_flags & (PROP_SCAN_DEAD_CODE
! 					      | PROP_SCAN_DEAD_STORES
! 					      | PROP_ALLOW_CFG_CHANGES));
! 
! 	  if ((prop_flags & (PROP_KILL_DEAD_CODE | PROP_ALLOW_CFG_CHANGES))
! 	      != (PROP_KILL_DEAD_CODE | PROP_ALLOW_CFG_CHANGES))
! 	    break;
! 
! 	  /* Removing dead code may allow the CFG to be simplified which
! 	     in turn may allow for further dead code detection / removal.  */
! 	  FOR_EACH_BB_REVERSE (bb)
! 	    {
! 	      COPY_REG_SET (tmp, bb->global_live_at_end);
! 	      changed |= propagate_block (bb, tmp, NULL, NULL,
! 				prop_flags & (PROP_SCAN_DEAD_CODE
! 					      | PROP_SCAN_DEAD_STORES
! 					      | PROP_KILL_DEAD_CODE));
! 	    }
! 
! 	  /* Don't pass PROP_SCAN_DEAD_CODE or PROP_KILL_DEAD_CODE to
! 	     subsequent propagate_block calls, since removing or acting as
! 	     removing dead code can affect global register liveness, which
! 	     is supposed to be finalized for this call after this loop.  */
! 	  stabilized_prop_flags
! 	    &= ~(PROP_SCAN_DEAD_CODE | PROP_SCAN_DEAD_STORES
! 		 | PROP_KILL_DEAD_CODE);
! 
! 	  if (! changed)
! 	    break;
! 
! 	  /* We repeat regardless of what cleanup_cfg says.  If there were
! 	     instructions deleted above, that might have been only a
! 	     partial improvement (see MAX_MEM_SET_LIST_LEN usage).
! 	     Further improvement may be possible.  */
! 	  cleanup_cfg (CLEANUP_EXPENSIVE);
! 	}
! 
!       /* If asked, remove notes from the blocks we'll update.  */
!       if (extent == UPDATE_LIFE_GLOBAL_RM_NOTES)
! 	count_or_remove_death_notes (blocks, 1);
!     }
! 
!   /* Clear log links in case we are asked to (re)compute them.  */
!   if (prop_flags & PROP_LOG_LINKS)
!     clear_log_links (blocks);
  
!   if (blocks)
      {
!       EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i,
! 	{
! 	  bb = BASIC_BLOCK (i);
  
! 	  COPY_REG_SET (tmp, bb->global_live_at_end);
! 	  propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags);
  
! 	  if (extent == UPDATE_LIFE_LOCAL)
! 	    verify_local_live_at_start (tmp, bb);
! 	});
!     }
!   else
!     {
        FOR_EACH_BB_REVERSE (bb)
  	{
  	  COPY_REG_SET (tmp, bb->global_live_at_end);
  
! 	  propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags);
  
! 	  if (extent == UPDATE_LIFE_LOCAL)
! 	    verify_local_live_at_start (tmp, bb);
! 	}
      }
  
    FREE_REG_SET (tmp);
  
!   if (prop_flags & PROP_REG_INFO)
!     {
!       /* The only pseudos that are live at the beginning of the function
! 	 are those that were not set anywhere in the function.  local-alloc
! 	 doesn't know how to handle these correctly, so mark them as not
! 	 local to any one basic block.  */
!       EXECUTE_IF_SET_IN_REG_SET (ENTRY_BLOCK_PTR->global_live_at_end,
! 				 FIRST_PSEUDO_REGISTER, i,
! 				 { REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; });
! 
!       /* We have a problem with any pseudoreg that lives across the setjmp.
! 	 ANSI says that if a user variable does not change in value between
! 	 the setjmp and the longjmp, then the longjmp preserves it.  This
! 	 includes longjmp from a place where the pseudo appears dead.
! 	 (In principle, the value still exists if it is in scope.)
! 	 If the pseudo goes in a hard reg, some other value may occupy
! 	 that hard reg where this pseudo is dead, thus clobbering the pseudo.
! 	 Conclusion: such a pseudo must not go in a hard reg.  */
!       EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
! 				 FIRST_PSEUDO_REGISTER, i,
! 				 {
! 				   if (regno_reg_rtx[i] != 0)
! 				     {
! 				       REG_LIVE_LENGTH (i) = -1;
! 				       REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
! 				     }
! 				 });
!     }
!   timevar_pop ((extent == UPDATE_LIFE_LOCAL || blocks)
! 	       ? TV_LIFE_UPDATE : TV_LIFE);
    if (ndead && rtl_dump_file)
      fprintf (rtl_dump_file, "deleted %i dead insns\n", ndead);
    return ndead;
  }
  
! /* Update life information in all blocks where BB_DIRTY is set.  */
  
  int
! update_life_info_in_dirty_blocks (extent, prop_flags)
!      enum update_life_extent extent;
       int prop_flags;
  {
    sbitmap update_life_blocks = sbitmap_alloc (last_basic_block);
    int n = 0;
--- 602,671 ----
  }
  
  /* Updates life information starting with the basic blocks set in BLOCKS.
!    If BLOCKS is null, consider it to be the universal set.  */
  
  int
! update_life_info (blocks, prop_flags)
       sbitmap blocks;
       int prop_flags;
  {
    regset tmp;
    regset_head tmp_head;
    basic_block bb;
  
    tmp = INITIALIZE_REG_SET (tmp_head);
    ndead = 0;
  
!   timevar_push (blocks ? TV_LIFE_UPDATE : TV_LIFE);
  
!   for ( ; ; )
      {
!       int changed = 0;
  
!       calculate_global_regs_live (blocks, blocks,
!   				  prop_flags & (PROP_SCAN_DEAD_CODE
!   						| PROP_SCAN_DEAD_STORES));
  
!       /* Removing dead code may allow the CFG to be simplified which
! 	 in turn may allow for further dead code detection / removal.  */
        FOR_EACH_BB_REVERSE (bb)
  	{
  	  COPY_REG_SET (tmp, bb->global_live_at_end);
+ 	  changed |= propagate_block (bb, tmp, NULL, NULL,
+       				      prop_flags & (PROP_SCAN_DEAD_CODE
+       						    | PROP_SCAN_DEAD_STORES
+       						    | PROP_KILL_DEAD_CODE));
+ 	}
+ 
+       if (! changed)
+ 	break;
  
!       if (! (prop_flags & PROP_ALLOW_CFG_CHANGES))
! 	break;
  
!       /* We repeat regardless of what cleanup_cfg says.  If there were
! 	 instructions deleted above, that might have been only a
! 	 partial improvement (see MAX_MEM_SET_LIST_LEN usage).
! 	 Further improvement may be possible.  */
!       cleanup_cfg (CLEANUP_EXPENSIVE);
      }
  
    FREE_REG_SET (tmp);
  
!   timevar_pop (blocks ? TV_LIFE_UPDATE : TV_LIFE);
    if (ndead && rtl_dump_file)
      fprintf (rtl_dump_file, "deleted %i dead insns\n", ndead);
    return ndead;
  }
  
! /* Update life information in all blocks where BB_DIRTY is set;
!    returns them and other blocks with altered liveness info
!    in DIRTY_BLOCKS.  */
  
  int
! update_life_info_in_dirty_blocks (prop_flags, dirty_blocks)
       int prop_flags;
+      sbitmap *dirty_blocks;
  {
    sbitmap update_life_blocks = sbitmap_alloc (last_basic_block);
    int n = 0;
*************** update_life_info_in_dirty_blocks (extent
*** 779,806 ****
    sbitmap_zero (update_life_blocks);
    FOR_EACH_BB (bb)
      {
!       if (extent == UPDATE_LIFE_LOCAL)
! 	{
! 	  if (bb->flags & BB_DIRTY)
! 	    {
! 	      SET_BIT (update_life_blocks, bb->index);
! 	      n++;
! 	    }
! 	}
!       else
! 	{
! 	  /* ??? Bootstrap with -march=pentium4 fails to terminate
! 	     with only a partial life update.  */
! 	  SET_BIT (update_life_blocks, bb->index);
! 	  if (bb->flags & BB_DIRTY)
! 	    n++;
! 	}
      }
  
    if (n)
!     retval = update_life_info (update_life_blocks, extent, prop_flags);
  
!   sbitmap_free (update_life_blocks);
    return retval;
  }
  
--- 675,699 ----
    sbitmap_zero (update_life_blocks);
    FOR_EACH_BB (bb)
      {
!       /* ??? Bootstrap with -march=pentium4 fails to terminate
! 	 with only a partial life update.  */
!       SET_BIT (update_life_blocks, bb->index);
!       if (bb->flags & BB_DIRTY)
! 	n++;
      }
  
    if (n)
!     {
!       count_or_remove_death_notes (update_life_blocks, 1);
!       retval = update_life_info (update_life_blocks, prop_flags);
!     }
!   else
!     sbitmap_zero (update_life_blocks);  /* See the hack above.  */
  
!   if (dirty_blocks)
!     *dirty_blocks = update_life_blocks;
!   else
!     sbitmap_free (update_life_blocks);
    return retval;
  }
  
*************** propagate_block_delete_libcall ( insn, n
*** 1598,1931 ****
    return before;
  }
  
! /* Update the life-status of regs for one insn.  Return the previous insn.  */
! 
! rtx
! propagate_one_insn (pbi, insn)
       struct propagate_block_info *pbi;
       rtx insn;
  {
    rtx prev = PREV_INSN (insn);
-   int flags = pbi->flags;
-   int insn_is_dead = 0;
-   int libcall_is_dead = 0;
-   rtx note;
-   int i;
  
!   if (! INSN_P (insn))
!     return prev;
  
!   note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
!   if (flags & PROP_SCAN_DEAD_CODE)
      {
!       insn_is_dead = insn_dead_p (pbi, PATTERN (insn), 0, REG_NOTES (insn));
!       libcall_is_dead = (insn_is_dead && note != 0
! 			 && libcall_dead_p (pbi, note, insn));
!     }
  
!   /* If an instruction consists of just dead store(s) on final pass,
!      delete it.  */
!   if ((flags & PROP_KILL_DEAD_CODE) && insn_is_dead)
!     {
!       /* If we're trying to delete a prologue or epilogue instruction
! 	 that isn't flagged as possibly being dead, something is wrong.
! 	 But if we are keeping the stack pointer depressed, we might well
! 	 be deleting insns that are used to compute the amount to update
! 	 it by, so they are fine.  */
!       if (reload_completed
! 	  && !(TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
! 		&& (TYPE_RETURNS_STACK_DEPRESSED
! 		    (TREE_TYPE (current_function_decl))))
! 	  && (((HAVE_epilogue || HAVE_prologue)
! 	       && prologue_epilogue_contains (insn))
! 	      || (HAVE_sibcall_epilogue
! 		  && sibcall_epilogue_contains (insn)))
! 	  && find_reg_note (insn, REG_MAYBE_DEAD, NULL_RTX) == 0)
! 	fatal_insn ("Attempt to delete prologue/epilogue insn:", insn);
! 
!       /* Record sets.  Do this even for dead instructions, since they
! 	 would have killed the values if they hadn't been deleted.  */
!       mark_set_regs (pbi, PATTERN (insn), insn);
! 
!       /* CC0 is now known to be dead.  Either this insn used it,
! 	 in which case it doesn't anymore, or clobbered it,
! 	 so the next insn can't use it.  */
!       pbi->cc0_live = 0;
  
!       if (libcall_is_dead)
! 	prev = propagate_block_delete_libcall ( insn, note);
!       else
  	{
  
! 	/* If INSN contains a RETVAL note and is dead, but the libcall
! 	   as a whole is not dead, then we want to remove INSN, but
! 	   not the whole libcall sequence.
! 
! 	   However, we need to also remove the dangling REG_LIBCALL	
! 	   note so that we do not have mis-matched LIBCALL/RETVAL
! 	   notes.  In theory we could find a new location for the
! 	   REG_RETVAL note, but it hardly seems worth the effort. 
! 
! 	   NOTE at this point will be the RETVAL note if it exists.  */
! 	  if (note)
! 	    {
! 	      rtx libcall_note;
! 	 
! 	      libcall_note
! 		= find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX);
! 	      remove_note (XEXP (note, 0), libcall_note);
! 	    }
! 
! 	  /* Similarly if INSN contains a LIBCALL note, remove the
! 	     dnagling REG_RETVAL note.  */
! 	  note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
! 	  if (note)
! 	    {
! 	      rtx retval_note;
  
! 	      retval_note
! 		= find_reg_note (XEXP (note, 0), REG_RETVAL, NULL_RTX);
! 	      remove_note (XEXP (note, 0), retval_note);
! 	    }
  
! 	  /* Now delete INSN.  */
! 	  propagate_block_delete_insn (insn);
  	}
  
!       return prev;
      }
  
!   /* See if this is an increment or decrement that can be merged into
!      a following memory address.  */
! #ifdef AUTO_INC_DEC
!   {
!     rtx x = single_set (insn);
! 
!     /* Does this instruction increment or decrement a register?  */
!     if ((flags & PROP_AUTOINC)
! 	&& x != 0
! 	&& GET_CODE (SET_DEST (x)) == REG
! 	&& (GET_CODE (SET_SRC (x)) == PLUS
! 	    || GET_CODE (SET_SRC (x)) == MINUS)
! 	&& XEXP (SET_SRC (x), 0) == SET_DEST (x)
! 	&& GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
! 	/* Ok, look for a following memory ref we can combine with.
! 	   If one is found, change the memory ref to a PRE_INC
! 	   or PRE_DEC, cancel this insn, and return 1.
! 	   Return 0 if nothing has been done.  */
! 	&& try_pre_increment_1 (pbi, insn))
!       return prev;
!   }
! #endif /* AUTO_INC_DEC */
  
!   CLEAR_REG_SET (pbi->new_set);
  
!   /* If this is not the final pass, and this insn is copying the value of
!      a library call and it's dead, don't scan the insns that perform the
!      library call, so that the call's arguments are not marked live.  */
!   if (libcall_is_dead)
      {
!       /* Record the death of the dest reg.  */
!       mark_set_regs (pbi, PATTERN (insn), insn);
  
!       insn = XEXP (note, 0);
!       return PREV_INSN (insn);
!     }
!   else if (GET_CODE (PATTERN (insn)) == SET
! 	   && SET_DEST (PATTERN (insn)) == stack_pointer_rtx
! 	   && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS
! 	   && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx
! 	   && GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == CONST_INT)
!     /* We have an insn to pop a constant amount off the stack.
!        (Such insns use PLUS regardless of the direction of the stack,
!        and any insn to adjust the stack by a constant is always a pop.)
!        These insns, if not dead stores, have no effect on life, though
!        they do have an effect on the memory stores we are tracking.  */
!     invalidate_mems_from_set (pbi, stack_pointer_rtx);
!   else
!     {
!       rtx note;
!       /* Any regs live at the time of a call instruction must not go
! 	 in a register clobbered by calls.  Find all regs now live and
! 	 record this for them.  */
! 
!       if (GET_CODE (insn) == CALL_INSN && (flags & PROP_REG_INFO))
! 	EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
! 				   { REG_N_CALLS_CROSSED (i)++; });
! 
!       /* Record sets.  Do this even for dead instructions, since they
! 	 would have killed the values if they hadn't been deleted.  */
!       mark_set_regs (pbi, PATTERN (insn), insn);
  
!       if (GET_CODE (insn) == CALL_INSN)
! 	{
! 	  int i;
! 	  rtx note, cond;
  
! 	  cond = NULL_RTX;
! 	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
! 	    cond = COND_EXEC_TEST (PATTERN (insn));
  
! 	  /* Non-constant calls clobber memory, constant calls do not
! 	     clobber memory, though they may clobber outgoing arguments
! 	     on the stack.  */
! 	  if (! CONST_OR_PURE_CALL_P (insn))
! 	    {
! 	      free_EXPR_LIST_list (&pbi->mem_set_list);
! 	      pbi->mem_set_list_len = 0;
! 	    }
! 	  else
! 	    invalidate_mems_from_set (pbi, stack_pointer_rtx);
  
! 	  /* There may be extra registers to be clobbered.  */
! 	  for (note = CALL_INSN_FUNCTION_USAGE (insn);
! 	       note;
! 	       note = XEXP (note, 1))
! 	    if (GET_CODE (XEXP (note, 0)) == CLOBBER)
! 	      mark_set_1 (pbi, CLOBBER, XEXP (XEXP (note, 0), 0),
! 			  cond, insn, pbi->flags);
  
! 	  /* Calls change all call-used and global registers.  */
! 	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
! 	    if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
! 	      {
! 		/* We do not want REG_UNUSED notes for these registers.  */
! 		mark_set_1 (pbi, CLOBBER, regno_reg_rtx[i], cond, insn,
! 			    pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
! 	      }
! 	}
  
!       /* If an insn doesn't use CC0, it becomes dead since we assume
! 	 that every insn clobbers it.  So show it dead here;
! 	 mark_used_regs will set it live if it is referenced.  */
!       pbi->cc0_live = 0;
! 
!       /* Record uses.  */
!       if (! insn_is_dead)
! 	mark_used_regs (pbi, PATTERN (insn), NULL_RTX, insn);
!       if ((flags & PROP_EQUAL_NOTES)
! 	  && ((note = find_reg_note (insn, REG_EQUAL, NULL_RTX))
! 	      || (note = find_reg_note (insn, REG_EQUIV, NULL_RTX))))
! 	mark_used_regs (pbi, XEXP (note, 0), NULL_RTX, insn);
  
!       /* Sometimes we may have inserted something before INSN (such as a move)
! 	 when we make an auto-inc.  So ensure we will scan those insns.  */
! #ifdef AUTO_INC_DEC
!       prev = PREV_INSN (insn);
! #endif
  
!       if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
! 	{
! 	  int i;
! 	  rtx note, cond;
  
! 	  cond = NULL_RTX;
! 	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
! 	    cond = COND_EXEC_TEST (PATTERN (insn));
! 
! 	  /* Calls use their arguments.  */
! 	  for (note = CALL_INSN_FUNCTION_USAGE (insn);
! 	       note;
! 	       note = XEXP (note, 1))
! 	    if (GET_CODE (XEXP (note, 0)) == USE)
! 	      mark_used_regs (pbi, XEXP (XEXP (note, 0), 0),
! 			      cond, insn);
  
! 	  /* The stack ptr is used (honorarily) by a CALL insn.  */
! 	  SET_REGNO_REG_SET (pbi->reg_live, STACK_POINTER_REGNUM);
  
! 	  /* Calls may also reference any of the global registers,
! 	     so they are made live.  */
! 	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
! 	    if (global_regs[i])
! 	      mark_used_reg (pbi, regno_reg_rtx[i], cond, insn);
! 	}
!     }
  
!   /* On final pass, update counts of how many insns in which each reg
!      is live.  */
!   if (flags & PROP_REG_INFO)
!     EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
! 			       { REG_LIVE_LENGTH (i)++; });
  
!   return prev;
  }
  
! /* Initialize a propagate_block_info struct for public consumption.
!    Note that the structure itself is opaque to this file, but that
!    the user can use the regsets provided here.  */
! 
! struct propagate_block_info *
! init_propagate_block_info (bb, live, local_set, cond_local_set, flags)
!      basic_block bb;
!      regset live, local_set, cond_local_set;
!      int flags;
  {
!   struct propagate_block_info *pbi = xmalloc (sizeof (*pbi));
! 
!   pbi->bb = bb;
!   pbi->reg_live = live;
!   pbi->mem_set_list = NULL_RTX;
!   pbi->mem_set_list_len = 0;
!   pbi->local_set = local_set;
!   pbi->cond_local_set = cond_local_set;
!   pbi->cc0_live = 0;
!   pbi->flags = flags;
! 
!   if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
!     pbi->reg_next_use = (rtx *) xcalloc (max_reg_num (), sizeof (rtx));
!   else
!     pbi->reg_next_use = NULL;
! 
!   pbi->new_set = BITMAP_XMALLOC ();
! 
  #ifdef HAVE_conditional_execution
!   pbi->reg_cond_dead = splay_tree_new (splay_tree_compare_ints, NULL,
! 				       free_reg_cond_life_info);
!   pbi->reg_cond_reg = BITMAP_XMALLOC ();
  
!   /* If this block ends in a conditional branch, for each register live
!      from one side of the branch and not the other, record the register
!      as conditionally dead.  */
!   if (GET_CODE (bb->end) == JUMP_INSN
!       && any_condjump_p (bb->end))
!     {
!       regset_head diff_head;
!       regset diff = INITIALIZE_REG_SET (diff_head);
!       basic_block bb_true, bb_false;
!       rtx cond_true, cond_false, set_src;
!       int i;
  
!       /* Identify the successor blocks.  */
!       bb_true = bb->succ->dest;
!       if (bb->succ->succ_next != NULL)
  	{
! 	  bb_false = bb->succ->succ_next->dest;
  
! 	  if (bb->succ->flags & EDGE_FALLTHRU)
  	    {
! 	      basic_block t = bb_false;
! 	      bb_false = bb_true;
! 	      bb_true = t;
  	    }
- 	  else if (! (bb->succ->succ_next->flags & EDGE_FALLTHRU))
- 	    abort ();
- 	}
-       else
- 	{
- 	  /* This can happen with a conditional jump to the next insn.  */
- 	  if (JUMP_LABEL (bb->end) != bb_true->head)
- 	    abort ();
- 
- 	  /* Simplest way to do nothing.  */
- 	  bb_false = bb_true;
- 	}
  
!       /* Extract the condition from the branch.  */
!       set_src = SET_SRC (pc_set (bb->end));
!       cond_true = XEXP (set_src, 0);
!       cond_false = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)),
! 				   GET_MODE (cond_true), XEXP (cond_true, 0),
  				   XEXP (cond_true, 1));
        if (GET_CODE (XEXP (set_src, 1)) == PC)
  	{
--- 1491,2440 ----
    return before;
  }
  
! /* Kill the dead INSN; return the previous one.  */
! static rtx
! kill_dead_insn (pbi, insn, libcall_is_dead, note)
       struct propagate_block_info *pbi;
       rtx insn;
+      int libcall_is_dead;
+      rtx note;
  {
    rtx prev = PREV_INSN (insn);
  
!   /* If we're trying to delete a prologue or epilogue instruction
!      that isn't flagged as possibly being dead, something is wrong.
!      But if we are keeping the stack pointer depressed, we might well
!      be deleting insns that are used to compute the amount to update
!      it by, so they are fine.  */
!   if (reload_completed
!       && !(TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
! 	   && (TYPE_RETURNS_STACK_DEPRESSED
! 	       (TREE_TYPE (current_function_decl))))
!       && (((HAVE_epilogue || HAVE_prologue)
! 	   && prologue_epilogue_contains (insn))
! 	  || (HAVE_sibcall_epilogue
! 	      && sibcall_epilogue_contains (insn)))
!       && find_reg_note (insn, REG_MAYBE_DEAD, NULL_RTX) == 0)
!     fatal_insn ("Attempt to delete prologue/epilogue insn:", insn);
! 
!   /* CC0 is now known to be dead.  Either this insn used it,
!      in which case it doesn't anymore, or clobbered it,
!      so the next insn can't use it.  */
!   pbi->cc0_live = 0;
  
!   if (libcall_is_dead)
!     prev = propagate_block_delete_libcall ( insn, note);
!   else
      {
!       /* If INSN contains a RETVAL note and is dead, but the libcall
! 	 as a whole is not dead, then we want to remove INSN, but
! 	 not the whole libcall sequence.
  
! 	 However, we need to also remove the dangling REG_LIBCALL	
! 	 note so that we do not have mis-matched LIBCALL/RETVAL
! 	 notes.  In theory we could find a new location for the
! 	 REG_RETVAL note, but it hardly seems worth the effort. 
  
! 	 NOTE at this point will be the RETVAL note if it exists.  */
!       if (note)
  	{
+ 	  rtx libcall_note;
  
! 	  libcall_note
!   		  = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX);
! 	  remove_note (XEXP (note, 0), libcall_note);
! 	}
  
!       /* Similarly if INSN contains a LIBCALL note, remove the
! 	 dnagling REG_RETVAL note.  */
!       note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
!       if (note)
! 	{
! 	  rtx retval_note;
  
! 	  retval_note
!   		  = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL_RTX);
! 	  remove_note (XEXP (note, 0), retval_note);
  	}
  
!       /* Now delete INSN.  */
!       propagate_block_delete_insn (insn);
      }
  
!   return prev;
! }
  
! /* Set up log links to INSN.  */
! static void
! set_up_log_links (insn, pbi, insn_info)
!      rtx insn;
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
! {
!   rtx freg;
!   rtx y;
!   unsigned r;
  
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->registers_set); r++)
      {
!       freg = VARRAY_IE_ELEM (insn_info->registers_set, r).elem;
!       y = pbi->reg_next_use[REGNO (freg)];
  
!       /* Do not make a log link for frame pointer.  */
!       if (REGNO (freg) == FRAME_POINTER_REGNUM
! 	  && (! reload_completed || frame_pointer_needed))
! 	continue;
! #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
!       if (REGNO (freg) == HARD_FRAME_POINTER_REGNUM
! 	  && (! reload_completed || frame_pointer_needed))
! 	continue;
! #endif
! #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
!       if (REGNO (freg) == ARG_POINTER_REGNUM && fixed_regs[REGNO (freg)])
! 	continue;
! #endif
  
!       /* Make a logical link from the next following insn
! 	 that uses this register, back to this insn.
! 	 The following insns have already been processed.
! 
! 	 We don't build a LOG_LINK for hard registers containing
! 	 in ASM_OPERANDs.  If these registers get replaced,
! 	 we might wind up changing the semantics of the insn,
! 	 even if reload can make what appear to be valid
! 	 assignments later.  */
!       if (!y || BLOCK_FOR_INSN (y) != BLOCK_FOR_INSN (insn))
! 	continue;
  
!       if (REGNO (freg) < FIRST_PSEUDO_REGISTER
! 	  && asm_noperands (PATTERN (y)) >= 0)
! 	continue;
!       
!       LOG_LINKS (y) = alloc_INSN_LIST (insn, LOG_LINKS (y));
!     }
! }
  
! /* Update PBI->reg_next_use by sets and clobbers.  */
! static void
! update_next_use_sets (pbi, insn_info)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
! {
!   varray_type lists[2];
!   int i, j, regno_first, regno_last;
!   unsigned r;
! 
!   lists[0] = insn_info->registers_set;
!   lists[1] = insn_info->registers_altered;
! 
!   /* Remove set or clobbered registers.  */
!   for (i = 0; i < 2; i++)
!     for (r = 0; r < VARRAY_ACTIVE_SIZE (lists[i]); r++)
!       {
! 	regno_first = VARRAY_IE_ELEM (lists[i], r).regno_first;
! 	regno_last = VARRAY_IE_ELEM (lists[i], r).regno_last;
  
! 	for (j = regno_first; j <= regno_last; j++)
! 	  pbi->reg_next_use[j] = NULL_RTX;
!       }
! }
  
! /* Update PBI->reg_next_use by uses.  */
! static void
! update_next_use_uses (insn, pbi, insn_info)
!      rtx insn;
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
! {
!   rtx freg;
!   int flags;
!   unsigned r;
  
!   /* Add used registers.  */
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->registers_used); r++)
!     {
!       flags = VARRAY_IE_ELEM (insn_info->registers_used, r).flags;
!       freg = VARRAY_IE_ELEM (insn_info->registers_used, r).elem;
  
!       if (flags & IIF_CALL_STACK_USAGE)
! 	continue;
!       pbi->reg_next_use[REGNO (freg)] = insn;
!     }
! }
  
! /* Update live status by sets in the insn.  */
! static void
! update_live_by_sets (pbi, insn_info)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
! {
!   rtx freg, cond;
!   varray_type lists[2];
!   int i, j, regno_first, regno_last;
!   unsigned r;
! 
!   lists[0] = insn_info->registers_set;
!   lists[1] = insn_info->registers_altered;
! 
!   /* If an insn doesn't use CC0, it becomes dead since we assume
!      that every insn clobbers it.  So show it dead here;
!      mark_used_regs will set it live if it is referenced.  */
!   pbi->cc0_live = 0;
  
!   /* Remove set or clobbered registers.  */
!   for (i = 0; i < 2; i++)
!     for (r = 0; r < VARRAY_ACTIVE_SIZE (lists[i]); r++)
!       {
! 	cond = VARRAY_IE_ELEM (lists[i], r).cond;
! 	freg = VARRAY_IE_ELEM (lists[i], r).elem;
! 	regno_first = VARRAY_IE_ELEM (lists[i], r).regno_first;
! 	regno_last = VARRAY_IE_ELEM (lists[i], r).regno_last;
  
!       	if (REGNO (freg) == FRAME_POINTER_REGNUM
! 	    && (! reload_completed || frame_pointer_needed))
! 	  continue;
! #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
! 	if (REGNO (freg) == HARD_FRAME_POINTER_REGNUM
! 	    && (! reload_completed || frame_pointer_needed))
! 	  continue;
! #endif
! #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
! 	if (REGNO (freg) == ARG_POINTER_REGNUM && fixed_regs[REGNO (freg)])
! 	  continue;
! #endif
! 	for (j = regno_first; j <= regno_last; j++)
! 	  {
! 	    if (pbi->local_set)
! 	      {
! 	      	/* Order of the set operation matters here since both
! 	  	   sets may be the same.  */
! 	    	CLEAR_REGNO_REG_SET (pbi->cond_local_set, j);
! 		if (cond != NULL_RTX
! 		    && ! REGNO_REG_SET_P (pbi->local_set, j))
! 		  SET_REGNO_REG_SET (pbi->cond_local_set, j);
! 		else
! 		  SET_REGNO_REG_SET (pbi->local_set, j);
! 	      }
! 	    if (lists[i] == insn_info->registers_set)
! 	      SET_REGNO_REG_SET (pbi->new_set, j);
  
! 	    /* The stack pointer is never dead.  Well, not strictly true,
! 	       but it's very difficult to tell from here.  Hopefully
! 	       combine_stack_adjustments will fix up the most egregious
! 	       errors.  */
! 	    if (REGNO (freg) == STACK_POINTER_REGNUM)
! 	      continue;
  
! #ifdef HAVE_conditional_execution
! 	    /* Consider conditional death.  */
! 	    if (! mark_regno_cond_dead (pbi, j, cond))
! 	      continue;
! #endif
  
! 	    /* The register is dead now.  */
! 	    CLEAR_REGNO_REG_SET (pbi->reg_live, j);
! 	  }
!       }
  }
  
! /* Update live status by uses in the insn.  */
! static void
! update_live_by_uses (pbi, insn_info)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
  {
!   rtx freg, cond;
!   int j, regno_first, regno_last;
!   unsigned r;
  #ifdef HAVE_conditional_execution
!   int this_was_live;
!   splay_tree_node node;
!   struct reg_cond_life_info *rcli;
!   rtx ncond;
! #endif
  
! #ifdef HAVE_cc0
!   if (insn_info->uses_cc0)
!     pbi->cc0_live = 1;
! #endif
!     
!   /* Add used registers.  */
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->registers_used); r++)
!     {
!       cond = VARRAY_IE_ELEM (insn_info->registers_used, r).cond;
!       freg = VARRAY_IE_ELEM (insn_info->registers_used, r).elem;
!       regno_first = VARRAY_IE_ELEM (insn_info->registers_used, r).regno_first;
!       regno_last = VARRAY_IE_ELEM (insn_info->registers_used, r).regno_last;
  
!       /* Mark the register as being live.  */
!       for (j = regno_first; j <= regno_last; j++)
  	{
! #ifdef HAVE_conditional_execution
! 	  this_was_live = REGNO_REG_SET_P (pbi->reg_live, j);
! #endif
! 	  SET_REGNO_REG_SET (pbi->reg_live, j);
  
! #ifdef HAVE_conditional_execution
! 	  if (cond == NULL_RTX)
  	    {
! 	      /* Not a conditional use.  */
! 	      if (this_was_live)
! 		{
! 		  /* The register may have been conditionally live previously,
! 		     but is now unconditionally live.  Remove it from the
! 		     conditionally dead list, so that a conditional set won't
! 		     cause us to think it dead.  */
! 		  splay_tree_remove (pbi->reg_cond_dead, j);
! 		}
! 	      continue;
  	    }
  
! 	  /* A conditional use. Record that fact; if it is later
!     	     conditionally set, we'll know to kill the register.  */
! 	  if (this_was_live)
!     	    {
! 	      node = splay_tree_lookup (pbi->reg_cond_dead, j);
! 	      if (node == NULL)
! 		{
! 		  /* The register was unconditionally live previously.
! 		     No need to do anything.  */
! 		}
! 	      else
! 		{
! 		  /* The register was conditionally live previously.
! 		     Subtract the new life cond from the old death cond.  */
! 		  rcli = (struct reg_cond_life_info *) node->value;
! 		  ncond = rcli->condition;
! 		  ncond = and_reg_cond (ncond, not_reg_cond (cond), 1);
! 
! 		  /* If the register is now unconditionally live,
! 		     remove the entry in the splay_tree.  */
! 		  if (ncond == const0_rtx)
! 		    splay_tree_remove (pbi->reg_cond_dead, j);
! 		  else
! 		    {
! 		      rcli->condition = ncond;
! 		      SET_REGNO_REG_SET (pbi->reg_cond_reg,
! 					 REGNO (XEXP (cond, 0)));
! 		    }
! 		}
! 	    }
! 	  else
! 	    {
! 	      /* The register was not previously live at all.  Record
! 		 the condition under which it is still dead.  */
! 	      rcli = (struct reg_cond_life_info *) xmalloc (sizeof (*rcli));
! 	      rcli->condition = not_reg_cond (cond);
! 	      rcli->stores = const0_rtx;
! 	      rcli->orig_condition = const0_rtx;
! 	      splay_tree_insert (pbi->reg_cond_dead, j,
! 				 (splay_tree_value) rcli);
! 
! 	      SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0)));
! 	    }
! #endif
! 	}
!     }
! }
! 
! /* Update traced mems by sets in the insn.  */
! static void
! update_mems_by_sets (pbi, insn_info)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
! {
!   rtx freg, cond, mem;
!   varray_type lists[2];
!   int i;
!   unsigned r;
! 
!   if (insn_info->all_mems_altered)
!     {
!       /* All MEMs are clobbered by a non-constant call.  */
!       free_EXPR_LIST_list (&pbi->mem_set_list);
!       pbi->mem_set_list_len = 0;
!     }
!   else
!     {
!       if (insn_info->contains_call)
! 	{
! 	  /* The call must be const or pure; constant calls do not
! 	     clobber memory, though they may clobber outgoing arguments
! 	     on the stack.  */
! 	  if (insn_info->contains_impure_call)
! 	    abort ();
! 	  invalidate_mems_from_set (pbi, stack_pointer_rtx);
! 	}
!       
!       lists[0] = insn_info->registers_set;
!       lists[1] = insn_info->registers_altered;
! 
!       /* Invalidate MEMs using set or clobbered registers.  */
!       for (i = 0; i < 2; i++)
! 	for (r = 0; r < VARRAY_ACTIVE_SIZE (lists[i]); r++)
! 	  {
! 	    cond = VARRAY_IE_ELEM (lists[i], r).cond;
! 	    freg = VARRAY_IE_ELEM (lists[i], r).elem;
! 
! 	    invalidate_mems_from_set (pbi, freg);
! 	  }
!     }
!   
!   /* Record new MEMs.  */
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->mems_set); r++)
!     {
!       cond = VARRAY_IE_ELEM (insn_info->mems_set, r).cond;
!       mem = VARRAY_IE_ELEM (insn_info->mems_set, r).elem;
!       
!       /* If the memory reference had embedded side effects (autoincrement
! 	 address modes.  Then we may need to kill some entries on the
! 	 memory set list.  */
!       for_each_rtx (&mem, invalidate_mems_from_autoinc, pbi);
! 
!       if (! side_effects_p (mem)
! 	  /* ??? With more effort we could track conditional memory life.  */
! 	  && ! cond)
! 	add_to_mem_set_list (pbi, canon_rtx (mem));
!     }
! }
! 
! /* Update traced mems by uses in the insn.  */
! static void
! update_mems_by_uses (pbi, insn_info)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
! {
!   rtx mem, cond;
!   unsigned r;
! 
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->mems_used); r++)
!     {
!       cond = VARRAY_IE_ELEM (insn_info->mems_used, r).cond;
!       mem = VARRAY_IE_ELEM (insn_info->mems_used, r).elem;
! 
!       /* Invalidate the data for the last MEM stored, but only if MEM is
! 	 something that can be stored into.  */
!       if (GET_CODE (XEXP (mem, 0)) == SYMBOL_REF
! 	  && CONSTANT_POOL_ADDRESS_P (XEXP (mem, 0)))
! 	/* Needn't clear the memory set list.  */
! 	;
!       else
! 	{
! 	  rtx temp = pbi->mem_set_list;
! 	  rtx prev = NULL_RTX;
! 	  rtx next;
! 
! 	  while (temp)
! 	    {
! 	      next = XEXP (temp, 1);
! 	      if (anti_dependence (XEXP (temp, 0), mem))
! 		{
! 		  /* Splice temp out of the list.  */
! 		  if (prev)
! 		    XEXP (prev, 1) = next;
! 		  else
! 	    	    pbi->mem_set_list = next;
!     		  free_EXPR_LIST_node (temp);
! 		  pbi->mem_set_list_len--;
! 		}
! 	      else
! 		prev = temp;
! 	      temp = next;
! 	    }
! 	}
! 
!       /* If the memory reference had embedded side effects (autoincrement
! 	 address modes.  Then we may need to kill some entries on the
! 	 memory set list.  */
!       for_each_rtx (&mem, invalidate_mems_from_autoinc, pbi);
!     }
! }
! 
! /* Create REG_UNUSED notes for sets in the INSN.  */
! static void
! create_unused_notes (pbi, insn_info, insn)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
!      rtx insn;
! {
!   rtx freg, cond;
!   varray_type lists[3];
!   int i;
!   int all_dead, flags;
!   int j, regno_first, regno_last;
!   unsigned r;
! 
!   lists[0] = insn_info->scratches;
!   lists[1] = insn_info->registers_set;
!   lists[2] = insn_info->registers_altered;
! 
!   /* Add notes for dead registers.  */
!   for (i = 2; i >= 0; i--)
!     for (r = 0; r < VARRAY_ACTIVE_SIZE (lists[i]); r++)
!       {
! 	flags = VARRAY_IE_ELEM (lists[i], r).flags;
! 	cond = VARRAY_IE_ELEM (lists[i], r).cond;
! 	freg = VARRAY_IE_ELEM (lists[i], r).elem;
! 	regno_first = VARRAY_IE_ELEM (lists[i], r).regno_first;
! 	regno_last = VARRAY_IE_ELEM (lists[i], r).regno_last;
! 
! 	/* We do not want to add REG_UNUSED notes for global registers
! 	   (implicitly) clobbered by a call.  */
! 	if (flags & IIF_CALL_CLOBBERED_GLOBAL)
! 	  continue;
! 
! 	all_dead = 1;
! 	for (j = regno_first; j <= regno_last; j++)
! 	  if (REGNO_REG_SET_P (pbi->reg_live, j))
! 	    {
!       	      all_dead = 0;
! 	      break;
! 	    }
! 
! 	/* Mark the dead store.  */
! 	if (all_dead)
! 	  {
! 	    REG_NOTES (insn) = alloc_EXPR_LIST (REG_UNUSED,
! 	  					freg,
! 	  					REG_NOTES (insn));
! 	  }
! 	else
! 	  {
! 	    /* This is a case where we have a multi-word hard register
!   	       and some, but not all, of the words of the register are
! 	       needed in subsequent insns.  Write REG_UNUSED notes
! 	       for those parts that were not needed.  This case should
! 	       be rare.  */
! 	    for (j = regno_first; j <= regno_last; j++)
! 	      {
! 		if (REGNO_REG_SET_P (pbi->reg_live, j))
! 		  continue;
! 
! 	      	REG_NOTES (insn) = alloc_EXPR_LIST (REG_UNUSED,
!       						    regno_reg_rtx[j],
! 						    REG_NOTES (insn));
! 	      }
! 	  }
!       }
! }
! 
! /* Create REG_DEAD notes for uses in the INSN.  */
! static void
! create_dead_notes (pbi, insn_info, insn)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
!      rtx insn;
! {
!   rtx freg;
!   int all_live, all_dead, all_set, alive, set;
!   int j, regno_first, regno_last;
!   unsigned r;
! 
!   /* Add notes for dead registers.  */
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->registers_used); r++)
!     {
!       freg = VARRAY_IE_ELEM (insn_info->registers_used, r).elem;
!       regno_first = VARRAY_IE_ELEM (insn_info->registers_used, r).regno_first;
!       regno_last = VARRAY_IE_ELEM (insn_info->registers_used, r).regno_last;
! 
!       all_live = all_dead = 1;
!       all_set = 1;
!       for (j = regno_first; j <= regno_last; j++)
! 	{
! 	  alive = REGNO_REG_SET_P (pbi->reg_live, j);
! 	  set = REGNO_REG_SET_P (pbi->new_set, j);
! 
! 	  /* Find out if any of this register is live after this instruction.  */
! 	  all_live &= alive;
! 	  all_dead &= ! alive;
! 	  
!       	  /* Find out if all of the register was set by this insn.  */
! 	  all_set &= set;
!       
!       	  /* Check for the case where the register dying partially
! 	     overlaps the register set by this insn.  */
! 	  all_dead &= !set;
! 	}
! 
!       /* Record and count the insns in which a reg dies.  If it is used in
! 	 this insn and was dead below the insn then it dies in this insn.
! 	 If it was set in this insn, we do not make a REG_DEAD note;
! 	 likewise if we already made such a note.  */
!       if (all_live || all_set)
! 	continue;
! 
!       /* If none of the words in X is needed, make a REG_DEAD note.
! 	 Otherwise, we must make partial REG_DEAD notes.  */
!       if (all_dead)
! 	{
! 	  if (! find_regno_note (insn, REG_DEAD, regno_first))
! 	    REG_NOTES (insn)
! 		    = alloc_EXPR_LIST (REG_DEAD, freg, REG_NOTES (insn));
! 
! 	  continue;
! 	}
! 	
!       /* Don't make a REG_DEAD note for a part of a register
! 	 that is set in the insn.  */
!       for (j = regno_first; j <= regno_last; j++)
! 	if (! REGNO_REG_SET_P (pbi->reg_live, j)
! 	    && ! dead_or_set_regno_p (insn, j))
! 	  REG_NOTES (insn)
! 		  = alloc_EXPR_LIST (REG_DEAD,
! 				     regno_reg_rtx[j],
! 				     REG_NOTES (insn));
!     }
! }
! 
! /* Counts register info for sets in insn.  */
! static void
! count_register_info_for_sets (pbi, insn_info)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
! {
!   rtx freg, cond;
!   varray_type lists[2];
!   int i;
!   int all_dead, flags;
!   int j, regno_first, regno_last;
!   unsigned r;
! 
!   lists[0] = insn_info->registers_set;
!   lists[1] = insn_info->registers_altered;
! 
!   /* Count the info.  */
!   for (i = 1; i >= 0; i--)
!     for (r = 0; r < VARRAY_ACTIVE_SIZE (lists[i]); r++)
!       {
! 	flags = VARRAY_IE_ELEM (lists[i], r).flags;
! 	cond = VARRAY_IE_ELEM (lists[i], r).cond;
! 	freg = VARRAY_IE_ELEM (lists[i], r).elem;
! 	regno_first = VARRAY_IE_ELEM (lists[i], r).regno_first;
! 	regno_last = VARRAY_IE_ELEM (lists[i], r).regno_last;
! 
!       	if (regno_first == FRAME_POINTER_REGNUM
! 	    && (! reload_completed || frame_pointer_needed))
! 	  continue;
! #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
! 	if (regno_first == HARD_FRAME_POINTER_REGNUM
! 	    && (! reload_completed || frame_pointer_needed))
! 	  continue;
! #endif
! #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
! 	if (regno_first == ARG_POINTER_REGNUM && fixed_regs[regno_first])
! 	  continue;
! #endif
! 
! 	/* We do not want to track global registers (implicitly) clobbered
! 	   by a call.  */
! 	if (flags & IIF_CALL_CLOBBERED_GLOBAL)
! 	  continue;
! 
! 	all_dead = 1;
! 
! 	for (j = regno_first; j <= regno_last; j++)
! 	  {
! 	    if (REGNO_REG_SET_P (pbi->reg_live, j))
! 	      {
! 		all_dead = 0;
! 		break;
! 	      }
! 	  }
! 
! 	for (j = regno_first; j <= regno_last; j++)
! 	  {
! 	    /* Count (weighted) references, stores, etc.  This counts a
!   	       register twice if it is modified, but that is correct.  */
! 	    REG_N_SETS (j) += 1;
! 	    REG_N_REFS (j) += 1;
! 	    REG_FREQ (j) += REG_FREQ_FROM_BB (pbi->bb);
! 
! 	    /* The insns where a reg is live are normally counted
! 	       elsewhere, but we want the count to include the insn
! 	       where the reg is set, and the normal counting mechanism
! 	       would not count it.  */
! 	    REG_LIVE_LENGTH (j) += 1;
! 	      
! 	    /* If this is a hard reg, record this function uses the reg.  */
! 	    if (regno_first < FIRST_PSEUDO_REGISTER)
! 	      regs_ever_live[j] = 1;
! 	  }
! 
! 	if (regno_first >= FIRST_PSEUDO_REGISTER)
! 	  {
!     	    /* Keep track of which basic blocks each reg appears in.  */
! 	    if (REG_BASIC_BLOCK (regno_first) == REG_BLOCK_UNKNOWN)
! 	      REG_BASIC_BLOCK (regno_first) = pbi->bb->index;
! 	    else if (REG_BASIC_BLOCK (regno_first) != pbi->bb->index)
! 	      REG_BASIC_BLOCK (regno_first) = REG_BLOCK_GLOBAL;
! 	  }
! 
! 	if (all_dead)
! 	  REG_N_DEATHS (regno_first) += 1;
!       }
! }
! 
! /* Counts register info for uses in insn.  */
! static void
! count_register_info_for_uses (pbi, insn_info)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
! {
!   rtx freg;
!   int set, alive, all_live, all_dead, all_set, flags;
!   regset already_done;
!   int j, regno_first, regno_last;
!   unsigned r;
! 
!   already_done = BITMAP_XMALLOC ();
!   CLEAR_REG_SET (already_done);
!   
!   /* Count the info.  */
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->registers_used); r++)
!     {
!       flags = VARRAY_IE_ELEM (insn_info->registers_used, r).flags;
!       freg = VARRAY_IE_ELEM (insn_info->registers_used, r).elem;
!       regno_first = VARRAY_IE_ELEM (insn_info->registers_used, r).regno_first;
!       regno_last = VARRAY_IE_ELEM (insn_info->registers_used, r).regno_last;
! 
!       /* Do not count stats for this one.  */
!       if (flags & IIF_CALL_STACK_USAGE)
! 	continue;
! 
!       /* Count register deaths.  */
!       if (!REGNO_REG_SET_P (already_done, regno_first))
! 	{
! 	  SET_REGNO_REG_SET (already_done, regno_first);
! 	  all_live = all_dead = 1;
! 	  all_set = 1;
! 
! 	  for (j = regno_first; j <= regno_last; j++)
! 	    {
! 	      /* Find out if any of this register is live after this
! 		 instruction.  */
! 	      alive = REGNO_REG_SET_P (pbi->reg_live, j);
! 	      all_live &= alive;
! 	      all_dead &= ! alive;
! 	  
! 	      set = REGNO_REG_SET_P (pbi->new_set, j);
! 	      /* Find out if all of the register was set by this insn.  */
! 	      all_set &= set;
!       
! 	      /* Check for the case where the register dying partially
! 		 overlaps the register set by this insn.  */
! 	      all_dead &= !set;
! 	    }
! 
! 	  if (!all_live && !all_set && all_dead)
! 	    REG_N_DEATHS (regno_first)++;
! 	}
! 
!       if (regno_first < FIRST_PSEUDO_REGISTER)
! 	{
! 	  /* If this is a register we are going to try to eliminate,
! 	     don't mark it live here.  If we are successful in
! 	     eliminating it, it need not be live unless it is used for
! 	     pseudos, in which case it will have been set live when it
! 	     was allocated to the pseudos.  If the register will not
! 	     be eliminated, reload will set it live at that point.
! 
! 	     Otherwise, record that this function uses this register.  */
! 	  /* ??? The PPC backend tries to "eliminate" on the pic
! 	     register to itself.  This should be fixed.  In the mean
! 	     time, hack around it.  */
! 
! 	  if (TEST_HARD_REG_BIT (elim_reg_set, regno_first)
! 	      && (regno_first == FRAME_POINTER_REGNUM
!        		  || regno_first == ARG_POINTER_REGNUM))
! 	    continue;
! 
! 	  for (j = regno_first; j <= regno_last; j++)
! 	    regs_ever_live[j] = 1;
! 	  continue;
! 	}
! 
!       /* Keep track of which basic block each reg appears in.  */
! 
!       if (REG_BASIC_BLOCK (regno_first) == REG_BLOCK_UNKNOWN)
! 	REG_BASIC_BLOCK (regno_first) = pbi->bb->index;
!       else if (REG_BASIC_BLOCK (regno_first) != pbi->bb->index)
! 	REG_BASIC_BLOCK (regno_first) = REG_BLOCK_GLOBAL;
! 
!       /* Count (weighted) number of uses of each reg.  */
!       REG_FREQ (regno_first) += REG_FREQ_FROM_BB (pbi->bb);
!       REG_N_REFS (regno_first)++;
!     }
! 
!   BITMAP_XFREE (already_done);
! }
! 
! #ifdef AUTO_INC_DEC
! /* Attempt to convert MEMs into autoincs.  */
! static int
! autoinc_transform (pbi, insn_info, insn)
!      struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
!      rtx insn;
! {
!   rtx mem;
!   varray_type lists[2];
!   int i;
!   int changed = 0;
!   unsigned r;
! 
!   lists[0] = insn_info->mems_set;
!   lists[1] = insn_info->mems_used;
! 
!   /* Count the info.  */
!   for (i = 0; i < 2; i++)
!     for (r = 0; r < VARRAY_ACTIVE_SIZE (lists[i]); r++)
!       {
! 	mem = VARRAY_IE_ELEM (lists[i], r).elem;
! 
! 	changed |= find_auto_inc (pbi, mem, insn);
!       }
! 
!   return changed;
! }
! #endif /* AUTO_INC_DEC */
! 
! /* Update the life-status of regs for one insn.  Return the previous insn.  */
! rtx
! propagate_one_insn (pbi, insn)
!      struct propagate_block_info *pbi;
!      rtx insn;
! {
!   rtx prev = PREV_INSN (insn);
!   int flags = pbi->flags;
!   int insn_is_dead = 0;
!   int libcall_is_dead = 0;
!   rtx note;
!   struct insn_extract *insn_info;
! 
!   if (! INSN_P (insn))
!     return prev;
! 
!   if (!optimize)
!     flags &= ~PROP_SCAN_DEAD_STORES;
! 
!   /* Extract the information about definitions, uses etc from insn.  */
!   insn_info = extract_insn_info (insn);
! 
!   note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
!   if (flags & PROP_SCAN_DEAD_CODE)
!     {
!       insn_is_dead = insn_dead_p (pbi, insn_info, 0, REG_NOTES (insn));
!       libcall_is_dead = (insn_is_dead && note != 0
! 			 && libcall_dead_p (pbi, note, insn));
!     }
! 
!   CLEAR_REG_SET (pbi->new_set);
! 
!   /* Update liveness info.  */
!   update_live_by_sets (pbi, insn_info);
! 
!   /* If this set is a MEM, then it kills any aliased writes.
!      If this set is a REG, then it kills any MEMs which use the reg.  */
!   if (flags & PROP_SCAN_DEAD_STORES)
!     update_mems_by_sets (pbi, insn_info);
! 
!   /* If an instruction consists of just dead store(s) on final pass,
!      delete it.  */
!   if ((flags & PROP_KILL_DEAD_CODE) && insn_is_dead)
!     return kill_dead_insn (pbi, insn, libcall_is_dead, note);
! 
!   /* If this is not the final pass, and this insn is copying the value of
!      a library call and it's dead, don't scan the insns that perform the
!      library call, so that the call's arguments are not marked live.  */
!   if (libcall_is_dead)
!     {
!       insn = XEXP (note, 0);
!       return PREV_INSN (insn);
!     }
!   
!   if (! insn_is_dead)
!     {
!       /* Update liveness info.  */
!       update_live_by_uses (pbi, insn_info);
! 
!       /* Update list of tracked MEMs.  */
!       if (flags & PROP_SCAN_DEAD_STORES)
! 	update_mems_by_uses (pbi, insn_info);
!     }
! 
!   return prev;
! }
! 
! /* Initialize a propagate_block_info struct for public consumption.
!    Note that the structure itself is opaque to this file, but that
!    the user can use the regsets provided here.  */
! 
! struct propagate_block_info *
! init_propagate_block_info (bb, live, local_set, cond_local_set, flags)
!      basic_block bb;
!      regset live, local_set, cond_local_set;
!      int flags;
! {
!   struct propagate_block_info *pbi = xmalloc (sizeof (*pbi));
! 
!   pbi->bb = bb;
!   pbi->reg_live = live;
!   pbi->mem_set_list = NULL_RTX;
!   pbi->mem_set_list_len = 0;
!   pbi->local_set = local_set;
!   pbi->cond_local_set = cond_local_set;
!   pbi->cc0_live = 0;
!   pbi->flags = flags;
! 
!   pbi->new_set = BITMAP_XMALLOC ();
! 
! #ifdef HAVE_conditional_execution
!   pbi->reg_cond_dead = splay_tree_new (splay_tree_compare_ints, NULL,
! 				       free_reg_cond_life_info);
!   pbi->reg_cond_reg = BITMAP_XMALLOC ();
! 
!   /* If this block ends in a conditional branch, for each register live
!      from one side of the branch and not the other, record the register
!      as conditionally dead.  */
!   if (GET_CODE (bb->end) == JUMP_INSN
!       && any_condjump_p (bb->end))
!     {
!       regset_head diff_head;
!       regset diff = INITIALIZE_REG_SET (diff_head);
!       basic_block bb_true, bb_false;
!       rtx cond_true, cond_false, set_src;
!       int i;
! 
!       /* Identify the successor blocks.  */
!       bb_true = bb->succ->dest;
!       if (bb->succ->succ_next != NULL)
! 	{
! 	  bb_false = bb->succ->succ_next->dest;
! 
! 	  if (bb->succ->flags & EDGE_FALLTHRU)
! 	    {
! 	      basic_block t = bb_false;
! 	      bb_false = bb_true;
! 	      bb_true = t;
! 	    }
! 	  else if (! (bb->succ->succ_next->flags & EDGE_FALLTHRU))
! 	    abort ();
! 	}
!       else
! 	{
! 	  /* This can happen with a conditional jump to the next insn.  */
! 	  if (JUMP_LABEL (bb->end) != bb_true->head)
! 	    abort ();
! 
! 	  /* Simplest way to do nothing.  */
! 	  bb_false = bb_true;
! 	}
! 
!       /* Extract the condition from the branch.  */
!       set_src = SET_SRC (pc_set (bb->end));
!       cond_true = XEXP (set_src, 0);
!       cond_false = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)),
! 				   GET_MODE (cond_true), XEXP (cond_true, 0),
  				   XEXP (cond_true, 1));
        if (GET_CODE (XEXP (set_src, 1)) == PC)
  	{
*************** init_propagate_block_info (bb, live, loc
*** 1974,2017 ****
      }
  #endif
  
-   /* If this block has no successors, any stores to the frame that aren't
-      used later in the block are dead.  So make a pass over the block
-      recording any such that are made and show them dead at the end.  We do
-      a very conservative and simple job here.  */
-   if (optimize
-       && ! (TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
- 	    && (TYPE_RETURNS_STACK_DEPRESSED
- 		(TREE_TYPE (current_function_decl))))
-       && (flags & PROP_SCAN_DEAD_STORES)
-       && (bb->succ == NULL
- 	  || (bb->succ->succ_next == NULL
- 	      && bb->succ->dest == EXIT_BLOCK_PTR
- 	      && ! current_function_calls_eh_return)))
-     {
-       rtx insn, set;
-       for (insn = bb->end; insn != bb->head; insn = PREV_INSN (insn))
- 	if (GET_CODE (insn) == INSN
- 	    && (set = single_set (insn))
- 	    && GET_CODE (SET_DEST (set)) == MEM)
- 	  {
- 	    rtx mem = SET_DEST (set);
- 	    rtx canon_mem = canon_rtx (mem);
- 
- 	    /* This optimization is performed by faking a store to the
- 	       memory at the end of the block.  This doesn't work for
- 	       unchanging memories because multiple stores to unchanging
- 	       memory is illegal and alias analysis doesn't consider it.  */
- 	    if (RTX_UNCHANGING_P (canon_mem))
- 	      continue;
- 
- 	    if (XEXP (canon_mem, 0) == frame_pointer_rtx
- 		|| (GET_CODE (XEXP (canon_mem, 0)) == PLUS
- 		    && XEXP (XEXP (canon_mem, 0), 0) == frame_pointer_rtx
- 		    && GET_CODE (XEXP (XEXP (canon_mem, 0), 1)) == CONST_INT))
- 	      add_to_mem_set_list (pbi, canon_mem);
- 	  }
-     }
- 
    return pbi;
  }
  
--- 2483,2488 ----
*************** free_propagate_block_info (pbi)
*** 2030,2038 ****
    BITMAP_XFREE (pbi->reg_cond_reg);
  #endif
  
-   if (pbi->reg_next_use)
-     free (pbi->reg_next_use);
- 
    free (pbi);
  }
  
--- 2501,2506 ----
*************** propagate_block (bb, live, local_set, co
*** 2068,2081 ****
  
    pbi = init_propagate_block_info (bb, live, local_set, cond_local_set, flags);
  
!   if (flags & PROP_REG_INFO)
!     {
!       int i;
  
!       /* Process the regs live at the end of the block.
! 	 Mark them as not local to any one basic block.  */
!       EXECUTE_IF_SET_IN_REG_SET (live, 0, i,
! 				 { REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; });
      }
  
    /* Scan the block an insn at a time from end to beginning.  */
--- 2536,2577 ----
  
    pbi = init_propagate_block_info (bb, live, local_set, cond_local_set, flags);
  
!   /* If this block has no successors, any stores to the frame that aren't
!      used later in the block are dead.  So make a pass over the block
!      recording any such that are made and show them dead at the end.  We do
!      a very conservative and simple job here.  */
!   if (optimize
!       && ! (TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
! 	    && (TYPE_RETURNS_STACK_DEPRESSED
! 		(TREE_TYPE (current_function_decl))))
!       && (flags & PROP_SCAN_DEAD_STORES)
!       && (bb->succ == NULL
! 	  || (bb->succ->succ_next == NULL
! 	      && bb->succ->dest == EXIT_BLOCK_PTR
! 	      && ! current_function_calls_eh_return)))
!     {
!       rtx insn, set;
!       for (insn = bb->end; insn != bb->head; insn = PREV_INSN (insn))
! 	if (GET_CODE (insn) == INSN
! 	    && (set = single_set (insn))
! 	    && GET_CODE (SET_DEST (set)) == MEM)
! 	  {
! 	    rtx mem = SET_DEST (set);
! 	    rtx canon_mem = canon_rtx (mem);
! 
! 	    /* This optimization is performed by faking a store to the
! 	       memory at the end of the block.  This doesn't work for
! 	       unchanging memories because multiple stores to unchanging
! 	       memory is illegal and alias analysis doesn't consider it.  */
! 	    if (RTX_UNCHANGING_P (canon_mem))
! 	      continue;
  
! 	    if (XEXP (canon_mem, 0) == frame_pointer_rtx
! 		|| (GET_CODE (XEXP (canon_mem, 0)) == PLUS
! 		    && XEXP (XEXP (canon_mem, 0), 0) == frame_pointer_rtx
! 		    && GET_CODE (XEXP (XEXP (canon_mem, 0), 1)) == CONST_INT))
! 	      add_to_mem_set_list (pbi, canon_mem);
! 	  }
      }
  
    /* Scan the block an insn at a time from end to beginning.  */
*************** propagate_block (bb, live, local_set, co
*** 2083,2095 ****
    changed = 0;
    for (insn = bb->end;; insn = prev)
      {
-       /* If this is a call to `setjmp' et al, warn if any
- 	 non-volatile datum is live.  */
-       if ((flags & PROP_REG_INFO)
- 	  && GET_CODE (insn) == CALL_INSN
- 	  && find_reg_note (insn, REG_SETJMP, NULL))
- 	IOR_REG_SET (regs_live_at_setjmp, pbi->reg_live);
- 
        prev = propagate_one_insn (pbi, insn);
        changed |= NEXT_INSN (prev) != insn;
  
--- 2579,2584 ----
*************** propagate_block (bb, live, local_set, co
*** 2112,2129 ****
     pertaining to the insn.  */
  
  static int
! insn_dead_p (pbi, x, call_ok, notes)
       struct propagate_block_info *pbi;
!      rtx x;
       int call_ok;
       rtx notes ATTRIBUTE_UNUSED;
  {
!   enum rtx_code code = GET_CODE (x);
  
    /* Don't eliminate insns that may trap.  */
!   if (flag_non_call_exceptions && may_trap_p (x))
      return 0;
  
  #ifdef AUTO_INC_DEC
    /* As flow is invoked after combine, we must take existing AUTO_INC
       expressions into account.  */
--- 2601,2652 ----
     pertaining to the insn.  */
  
  static int
! insn_dead_p (pbi, insn_info, call_ok, notes)
       struct propagate_block_info *pbi;
!      struct insn_extract *insn_info;
       int call_ok;
       rtx notes ATTRIBUTE_UNUSED;
  {
!   rtx reg, expr, canon_r, temp;
!   int regno, flags, regno_first, regno_last;
!   unsigned r;
  
    /* Don't eliminate insns that may trap.  */
!   if (flag_non_call_exceptions && insn_info->may_trap)
!     return 0;
! 
!   /* Do not elliminate calls.  */
!   if (!call_ok && insn_info->contains_call)
!     return 0;
! 
!   /* Don't eliminate loads from volatile memory or volatile asms.  */
!   if (insn_info->contains_volatile_ref)
      return 0;
  
+   /* We generally should not elliminate something else than sets.  */
+   if (insn_info->not_set)
+     {
+       if (VARRAY_ACTIVE_SIZE (insn_info->registers_altered) == 0)
+ 	return 0;
+ 
+       /* A CLOBBER of a pseudo-register that is dead serves no purpose.  That
+ 	 is not necessarily true for hard registers.  */
+       for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->registers_altered); r++)
+ 	{
+ 	  flags = VARRAY_IE_ELEM (insn_info->registers_altered, r).flags;
+ 	  reg = VARRAY_IE_ELEM (insn_info->registers_altered, r).elem;
+ 
+ 	  if (!flags & IIF_TOPLEV_CLOBBER)
+ 	    return 0;
+ 	  if (GET_CODE (reg) != REG)
+ 	    return 0;
+ 	  if (REGNO (reg) < FIRST_PSEUDO_REGISTER
+ 	      || REGNO_REG_SET_P (pbi->reg_live, REGNO (reg)))
+ 	    return 0;
+ 	}
+       return 1;
+     }
+ 
  #ifdef AUTO_INC_DEC
    /* As flow is invoked after combine, we must take existing AUTO_INC
       expressions into account.  */
*************** insn_dead_p (pbi, x, call_ok, notes)
*** 2141,2296 ****
      }
  #endif
  
-   /* If setting something that's a reg or part of one,
-      see if that register's altered value will be live.  */
- 
-   if (code == SET)
-     {
-       rtx r = SET_DEST (x);
- 
  #ifdef HAVE_cc0
!       if (GET_CODE (r) == CC0)
! 	return ! pbi->cc0_live;
  #endif
  
!       /* A SET that is a subroutine call cannot be dead.  */
!       if (GET_CODE (SET_SRC (x)) == CALL)
! 	{
! 	  if (! call_ok)
! 	    return 0;
! 	}
  
!       /* Don't eliminate loads from volatile memory or volatile asms.  */
!       else if (volatile_refs_p (SET_SRC (x)))
  	return 0;
  
!       if (GET_CODE (r) == MEM)
! 	{
! 	  rtx temp, canon_r;
! 
! 	  if (MEM_VOLATILE_P (r) || GET_MODE (r) == BLKmode)
! 	    return 0;
! 
! 	  canon_r = canon_rtx (r);
! 
! 	  /* Walk the set of memory locations we are currently tracking
! 	     and see if one is an identical match to this memory location.
! 	     If so, this memory write is dead (remember, we're walking
! 	     backwards from the end of the block to the start).  Since
! 	     rtx_equal_p does not check the alias set or flags, we also
! 	     must have the potential for them to conflict (anti_dependence).  */
! 	  for (temp = pbi->mem_set_list; temp != 0; temp = XEXP (temp, 1))
! 	    if (anti_dependence (r, XEXP (temp, 0)))
! 	      {
! 		rtx mem = XEXP (temp, 0);
  
! 		if (rtx_equal_p (XEXP (canon_r, 0), XEXP (mem, 0))
! 		    && (GET_MODE_SIZE (GET_MODE (canon_r))
! 			<= GET_MODE_SIZE (GET_MODE (mem))))
! 		  return 1;
  
  #ifdef AUTO_INC_DEC
! 		/* Check if memory reference matches an auto increment. Only
! 		   post increment/decrement or modify are valid.  */
! 		if (GET_MODE (mem) == GET_MODE (r)
! 		    && (GET_CODE (XEXP (mem, 0)) == POST_DEC
! 			|| GET_CODE (XEXP (mem, 0)) == POST_INC
! 			|| GET_CODE (XEXP (mem, 0)) == POST_MODIFY)
! 		    && GET_MODE (XEXP (mem, 0)) == GET_MODE (r)
! 		    && rtx_equal_p (XEXP (XEXP (mem, 0), 0), XEXP (r, 0)))
! 		  return 1;
  #endif
! 	      }
! 	}
!       else
! 	{
! 	  while (GET_CODE (r) == SUBREG
! 		 || GET_CODE (r) == STRICT_LOW_PART
! 		 || GET_CODE (r) == ZERO_EXTRACT)
! 	    r = XEXP (r, 0);
  
! 	  if (GET_CODE (r) == REG)
! 	    {
! 	      int regno = REGNO (r);
  
! 	      /* Obvious.  */
! 	      if (REGNO_REG_SET_P (pbi->reg_live, regno))
! 		return 0;
! 
! 	      /* If this is a hard register, verify that subsequent
! 		 words are not needed.  */
! 	      if (regno < FIRST_PSEUDO_REGISTER)
! 		{
! 		  int n = HARD_REGNO_NREGS (regno, GET_MODE (r));
  
! 		  while (--n > 0)
! 		    if (REGNO_REG_SET_P (pbi->reg_live, regno+n))
! 		      return 0;
! 		}
  
! 	      /* Don't delete insns to set global regs.  */
! 	      if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
! 		return 0;
! 
! 	      /* Make sure insns to set the stack pointer aren't deleted.  */
! 	      if (regno == STACK_POINTER_REGNUM)
! 		return 0;
! 
! 	      /* ??? These bits might be redundant with the force live bits
! 		 in calculate_global_regs_live.  We would delete from
! 		 sequential sets; whether this actually affects real code
! 		 for anything but the stack pointer I don't know.  */
! 	      /* Make sure insns to set the frame pointer aren't deleted.  */
! 	      if (regno == FRAME_POINTER_REGNUM
! 		  && (! reload_completed || frame_pointer_needed))
! 		return 0;
  #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
! 	      if (regno == HARD_FRAME_POINTER_REGNUM
! 		  && (! reload_completed || frame_pointer_needed))
! 		return 0;
  #endif
  
  #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
! 	      /* Make sure insns to set arg pointer are never deleted
! 		 (if the arg pointer isn't fixed, there will be a USE
! 		 for it, so we can treat it normally).  */
! 	      if (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
! 		return 0;
  #endif
  
! 	      /* Otherwise, the set is dead.  */
! 	      return 1;
! 	    }
  	}
      }
  
!   /* If performing several activities, insn is dead if each activity
!      is individually dead.  Also, CLOBBERs and USEs can be ignored; a
!      CLOBBER or USE that's inside a PARALLEL doesn't make the insn
!      worth keeping.  */
!   else if (code == PARALLEL)
!     {
!       int i = XVECLEN (x, 0);
! 
!       for (i--; i >= 0; i--)
! 	if (GET_CODE (XVECEXP (x, 0, i)) != CLOBBER
! 	    && GET_CODE (XVECEXP (x, 0, i)) != USE
! 	    && ! insn_dead_p (pbi, XVECEXP (x, 0, i), call_ok, NULL_RTX))
! 	  return 0;
! 
!       return 1;
!     }
! 
!   /* A CLOBBER of a pseudo-register that is dead serves no purpose.  That
!      is not necessarily true for hard registers.  */
!   else if (code == CLOBBER && GET_CODE (XEXP (x, 0)) == REG
! 	   && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER
! 	   && ! REGNO_REG_SET_P (pbi->reg_live, REGNO (XEXP (x, 0))))
!     return 1;
! 
!   /* We do not check other CLOBBER or USE here.  An insn consisting of just
!      a CLOBBER or just a USE should not be deleted.  */
!   return 0;
  }
  
  /* If INSN is the last insn in a libcall, and assuming INSN is dead,
--- 2664,2769 ----
      }
  #endif
  
  #ifdef HAVE_cc0
!   /* If it sets live cc0, it is not dead.  */
!   if (insn_info->sets_cc0 && pbi->cc0_live)
!     return 0;
  #endif
  
!   /* Check memory sets.  */
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->mems_set); r++)
!     {
!       expr = VARRAY_IE_ELEM (insn_info->mems_set, r).elem;
  
!       if (MEM_VOLATILE_P (expr) || GET_MODE (expr) == BLKmode)
  	return 0;
+       canon_r = canon_rtx (expr);
  
!       /* Walk the set of memory locations we are currently tracking
! 	 and see if one is an identical match to this memory location.
! 	 If so, this memory write is dead (remember, we're walking
! 	 backwards from the end of the block to the start).  Since
! 	 rtx_equal_p does not check the alias set or flags, we also
! 	 must have the potential for them to conflict (anti_dependence).  */
!       for (temp = pbi->mem_set_list; temp != 0; temp = XEXP (temp, 1))
! 	if (anti_dependence (expr, XEXP (temp, 0)))
! 	  {
! 	    rtx mem = XEXP (temp, 0);
  
! 	    if (rtx_equal_p (XEXP (canon_r, 0), XEXP (mem, 0))
! 		&& (GET_MODE_SIZE (GET_MODE (canon_r))
! 		    <= GET_MODE_SIZE (GET_MODE (mem))))
! 	      goto next;
  
  #ifdef AUTO_INC_DEC
! 	    /* Check if memory reference matches an auto increment. Only
! 	       post increment/decrement or modify are valid.  */
! 	    if (GET_MODE (mem) == GET_MODE (expr)
! 		&& (GET_CODE (XEXP (mem, 0)) == POST_DEC
! 		    || GET_CODE (XEXP (mem, 0)) == POST_INC
! 		    || GET_CODE (XEXP (mem, 0)) == POST_MODIFY)
! 		&& GET_MODE (XEXP (mem, 0)) == GET_MODE (expr)
! 		&& rtx_equal_p (XEXP (XEXP (mem, 0), 0), XEXP (expr, 0)))
! 	      goto next;
  #endif
! 	  }
  
!       /* The set is not dead.  */
!       return 0;
! next:;
!     }
  
!   /* If setting something that's a reg or part of one,
!      see if that register's altered value will be live.  */
!   for (r = 0; r < VARRAY_ACTIVE_SIZE (insn_info->registers_set); r++)
!     {
!       reg = VARRAY_IE_ELEM (insn_info->registers_set, r).elem;
!       regno_first = VARRAY_IE_ELEM (insn_info->registers_set, r).regno_first;
!       regno_last = VARRAY_IE_ELEM (insn_info->registers_set, r).regno_last;
!       regno = REGNO (reg);
!       
!       /* Don't delete insns to set global regs.  */
!       if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
! 	return 0;
  
!       /* Make sure insns to set the stack pointer aren't deleted.  */
!       if (regno == STACK_POINTER_REGNUM)
! 	return 0;
  
!       /* ??? These bits might be redundant with the force live bits
! 	 in calculate_global_regs_live.  We would delete from
! 	 sequential sets; whether this actually affects real code
! 	 for anything but the stack pointer I don't know.  */
!       /* Make sure insns to set the frame pointer aren't deleted.  */
!       if (regno == FRAME_POINTER_REGNUM
! 	  && (! reload_completed || frame_pointer_needed))
! 	return 0;
  #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
!       if (regno == HARD_FRAME_POINTER_REGNUM
! 	  && (! reload_completed || frame_pointer_needed))
! 	return 0;
  #endif
  
  #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
!       /* Make sure insns to set arg pointer are never deleted
! 	 (if the arg pointer isn't fixed, there will be a USE
! 	 for it, so we can treat it normally).  */
!       if (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
! 	return 0;
  #endif
  
!       /* Check whether register (or subsequent regs in case of
! 	 hard regs) is not live.  */
!       for (regno = regno_first; regno <= regno_last; regno++)
! 	{
! 	  /* Obvious.  */
! 	  if (REGNO_REG_SET_P (pbi->reg_live, regno))
! 	    return 0;
  	}
      }
  
!   /* If we got here, the instruction is dead.  */
!   return 1;
  }
  
  /* If INSN is the last insn in a libcall, and assuming INSN is dead,
*************** libcall_dead_p (pbi, note, insn)
*** 2314,2320 ****
--- 2787,2795 ----
       rtx note;
       rtx insn;
  {
+   struct insn_extract *call_info;
    rtx x = single_set (insn);
+   int ret;
  
    if (x)
      {
*************** libcall_dead_p (pbi, note, insn)
*** 2323,2330 ****
        if (GET_CODE (r) == REG)
  	{
  	  rtx call = XEXP (note, 0);
- 	  rtx call_pat;
- 	  int i;
  
  	  /* Find the call insn.  */
  	  while (call != insn && GET_CODE (call) != CALL_INSN)
--- 2798,2803 ----
*************** libcall_dead_p (pbi, note, insn)
*** 2335,2360 ****
  	  if (call == insn)
  	    return 0;
  
! 	  /* See if the hard reg holding the value is dead.
! 	     If this is a PARALLEL, find the call within it.  */
! 	  call_pat = PATTERN (call);
! 	  if (GET_CODE (call_pat) == PARALLEL)
! 	    {
! 	      for (i = XVECLEN (call_pat, 0) - 1; i >= 0; i--)
! 		if (GET_CODE (XVECEXP (call_pat, 0, i)) == SET
! 		    && GET_CODE (SET_SRC (XVECEXP (call_pat, 0, i))) == CALL)
! 		  break;
! 
! 	      /* This may be a library call that is returning a value
! 		 via invisible pointer.  Do nothing special, since
! 		 ordinary death handling can understand these insns.  */
! 	      if (i < 0)
! 		return 0;
! 
! 	      call_pat = XVECEXP (call_pat, 0, i);
! 	    }
! 
! 	  return insn_dead_p (pbi, call_pat, 1, REG_NOTES (call));
  	}
      }
    return 1;
--- 2808,2817 ----
  	  if (call == insn)
  	    return 0;
  
! 	  /* Check that the call is dead.  */
! 	  call_info = extract_insn_info (insn);
! 	  ret = insn_dead_p (pbi, call_info, 1, REG_NOTES (call));
! 	  return ret;
  	}
      }
    return 1;
*************** add_to_mem_set_list (pbi, mem)
*** 2415,2442 ****
        if (rtx_equal_p (XEXP (mem, 0), XEXP (e, 0)))
  	{
  	  if (GET_MODE_SIZE (GET_MODE (mem)) > GET_MODE_SIZE (GET_MODE (e)))
! 	    {
! #ifdef AUTO_INC_DEC
! 	      /* If we must store a copy of the mem, we can just modify
! 		 the mode of the stored copy.  */
! 	      if (pbi->flags & PROP_AUTOINC)
! 	        PUT_MODE (e, GET_MODE (mem));
! 	      else
! #endif
! 	        XEXP (i, 0) = mem;
! 	    }
  	  return;
  	}
      }
  
    if (pbi->mem_set_list_len < MAX_MEM_SET_LIST_LEN)
      {
- #ifdef AUTO_INC_DEC
-       /* Store a copy of mem, otherwise the address may be
- 	 scrogged by find_auto_inc.  */
-       if (pbi->flags & PROP_AUTOINC)
- 	mem = shallow_copy_rtx (mem);
- #endif
        pbi->mem_set_list = alloc_EXPR_LIST (0, mem, pbi->mem_set_list);
        pbi->mem_set_list_len++;
      }
--- 2872,2884 ----
        if (rtx_equal_p (XEXP (mem, 0), XEXP (e, 0)))
  	{
  	  if (GET_MODE_SIZE (GET_MODE (mem)) > GET_MODE_SIZE (GET_MODE (e)))
! 	    XEXP (i, 0) = mem;
  	  return;
  	}
      }
  
    if (pbi->mem_set_list_len < MAX_MEM_SET_LIST_LEN)
      {
        pbi->mem_set_list = alloc_EXPR_LIST (0, mem, pbi->mem_set_list);
        pbi->mem_set_list_len++;
      }
*************** invalidate_mems_from_set (pbi, exp)
*** 2476,2881 ****
  
    while (temp)
      {
!       next = XEXP (temp, 1);
!       if (reg_overlap_mentioned_p (exp, XEXP (temp, 0)))
! 	{
! 	  /* Splice this entry out of the list.  */
! 	  if (prev)
! 	    XEXP (prev, 1) = next;
! 	  else
! 	    pbi->mem_set_list = next;
! 	  free_EXPR_LIST_node (temp);
! 	  pbi->mem_set_list_len--;
! 	}
!       else
! 	prev = temp;
!       temp = next;
!     }
! }
! 
! /* Process the registers that are set within X.  Their bits are set to
!    1 in the regset DEAD, because they are dead prior to this insn.
! 
!    If INSN is nonzero, it is the insn being processed.
! 
!    FLAGS is the set of operations to perform.  */
! 
! static void
! mark_set_regs (pbi, x, insn)
!      struct propagate_block_info *pbi;
!      rtx x, insn;
! {
!   rtx cond = NULL_RTX;
!   rtx link;
!   enum rtx_code code;
! 
!   if (insn)
!     for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
!       {
! 	if (REG_NOTE_KIND (link) == REG_INC)
! 	  mark_set_1 (pbi, SET, XEXP (link, 0),
! 		      (GET_CODE (x) == COND_EXEC
! 		       ? COND_EXEC_TEST (x) : NULL_RTX),
! 		      insn, pbi->flags);
!       }
!  retry:
!   switch (code = GET_CODE (x))
!     {
!     case SET:
!     case CLOBBER:
!       mark_set_1 (pbi, code, SET_DEST (x), cond, insn, pbi->flags);
!       return;
! 
!     case COND_EXEC:
!       cond = COND_EXEC_TEST (x);
!       x = COND_EXEC_CODE (x);
!       goto retry;
! 
!     case PARALLEL:
!       {
! 	int i;
! 
! 	for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
! 	  {
! 	    rtx sub = XVECEXP (x, 0, i);
! 	    switch (code = GET_CODE (sub))
! 	      {
! 	      case COND_EXEC:
! 		if (cond != NULL_RTX)
! 		  abort ();
! 
! 		cond = COND_EXEC_TEST (sub);
! 		sub = COND_EXEC_CODE (sub);
! 		if (GET_CODE (sub) != SET && GET_CODE (sub) != CLOBBER)
! 		  break;
! 		/* Fall through.  */
! 
! 	      case SET:
! 	      case CLOBBER:
! 		mark_set_1 (pbi, code, SET_DEST (sub), cond, insn, pbi->flags);
! 		break;
! 
! 	      default:
! 		break;
! 	      }
! 	  }
! 	break;
!       }
! 
!     default:
!       break;
!     }
! }
! 
! /* Process a single set, which appears in INSN.  REG (which may not
!    actually be a REG, it may also be a SUBREG, PARALLEL, etc.) is
!    being set using the CODE (which may be SET, CLOBBER, or COND_EXEC).
!    If the set is conditional (because it appear in a COND_EXEC), COND
!    will be the condition.  */
! 
! static void
! mark_set_1 (pbi, code, reg, cond, insn, flags)
!      struct propagate_block_info *pbi;
!      enum rtx_code code;
!      rtx reg, cond, insn;
!      int flags;
! {
!   int regno_first = -1, regno_last = -1;
!   unsigned long not_dead = 0;
!   int i;
! 
!   /* Modifying just one hardware register of a multi-reg value or just a
!      byte field of a register does not mean the value from before this insn
!      is now dead.  Of course, if it was dead after it's unused now.  */
! 
!   switch (GET_CODE (reg))
!     {
!     case PARALLEL:
!       /* Some targets place small structures in registers for return values of
! 	 functions.  We have to detect this case specially here to get correct
! 	 flow information.  */
!       for (i = XVECLEN (reg, 0) - 1; i >= 0; i--)
! 	if (XEXP (XVECEXP (reg, 0, i), 0) != 0)
! 	  mark_set_1 (pbi, code, XEXP (XVECEXP (reg, 0, i), 0), cond, insn,
! 		      flags);
!       return;
! 
!     case ZERO_EXTRACT:
!     case SIGN_EXTRACT:
!     case STRICT_LOW_PART:
!       /* ??? Assumes STRICT_LOW_PART not used on multi-word registers.  */
!       do
! 	reg = XEXP (reg, 0);
!       while (GET_CODE (reg) == SUBREG
! 	     || GET_CODE (reg) == ZERO_EXTRACT
! 	     || GET_CODE (reg) == SIGN_EXTRACT
! 	     || GET_CODE (reg) == STRICT_LOW_PART);
!       if (GET_CODE (reg) == MEM)
! 	break;
!       not_dead = (unsigned long) REGNO_REG_SET_P (pbi->reg_live, REGNO (reg));
!       /* Fall through.  */
! 
!     case REG:
!       regno_last = regno_first = REGNO (reg);
!       if (regno_first < FIRST_PSEUDO_REGISTER)
! 	regno_last += HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1;
!       break;
! 
!     case SUBREG:
!       if (GET_CODE (SUBREG_REG (reg)) == REG)
! 	{
! 	  enum machine_mode outer_mode = GET_MODE (reg);
! 	  enum machine_mode inner_mode = GET_MODE (SUBREG_REG (reg));
! 
! 	  /* Identify the range of registers affected.  This is moderately
! 	     tricky for hard registers.  See alter_subreg.  */
! 
! 	  regno_last = regno_first = REGNO (SUBREG_REG (reg));
! 	  if (regno_first < FIRST_PSEUDO_REGISTER)
! 	    {
! 	      regno_first += subreg_regno_offset (regno_first, inner_mode,
! 						  SUBREG_BYTE (reg),
! 						  outer_mode);
! 	      regno_last = (regno_first
! 			    + HARD_REGNO_NREGS (regno_first, outer_mode) - 1);
! 
! 	      /* Since we've just adjusted the register number ranges, make
! 		 sure REG matches.  Otherwise some_was_live will be clear
! 		 when it shouldn't have been, and we'll create incorrect
! 		 REG_UNUSED notes.  */
! 	      reg = gen_rtx_REG (outer_mode, regno_first);
! 	    }
! 	  else
! 	    {
! 	      /* If the number of words in the subreg is less than the number
! 		 of words in the full register, we have a well-defined partial
! 		 set.  Otherwise the high bits are undefined.
! 
! 		 This is only really applicable to pseudos, since we just took
! 		 care of multi-word hard registers.  */
! 	      if (((GET_MODE_SIZE (outer_mode)
! 		    + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
! 		  < ((GET_MODE_SIZE (inner_mode)
! 		      + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
! 		not_dead = (unsigned long) REGNO_REG_SET_P (pbi->reg_live,
! 							    regno_first);
! 
! 	      reg = SUBREG_REG (reg);
! 	    }
! 	}
!       else
! 	reg = SUBREG_REG (reg);
!       break;
! 
!     default:
!       break;
!     }
! 
!   /* If this set is a MEM, then it kills any aliased writes.
!      If this set is a REG, then it kills any MEMs which use the reg.  */
!   if (optimize && (flags & PROP_SCAN_DEAD_STORES))
!     {
!       if (GET_CODE (reg) == REG)
! 	invalidate_mems_from_set (pbi, reg);
! 
!       /* If the memory reference had embedded side effects (autoincrement
! 	 address modes.  Then we may need to kill some entries on the
! 	 memory set list.  */
!       if (insn && GET_CODE (reg) == MEM)
! 	for_each_rtx (&PATTERN (insn), invalidate_mems_from_autoinc, pbi);
! 
!       if (GET_CODE (reg) == MEM && ! side_effects_p (reg)
! 	  /* ??? With more effort we could track conditional memory life.  */
! 	  && ! cond)
! 	add_to_mem_set_list (pbi, canon_rtx (reg));
!     }
! 
!   if (GET_CODE (reg) == REG
!       && ! (regno_first == FRAME_POINTER_REGNUM
! 	    && (! reload_completed || frame_pointer_needed))
! #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
!       && ! (regno_first == HARD_FRAME_POINTER_REGNUM
! 	    && (! reload_completed || frame_pointer_needed))
! #endif
! #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
!       && ! (regno_first == ARG_POINTER_REGNUM && fixed_regs[regno_first])
! #endif
!       )
!     {
!       int some_was_live = 0, some_was_dead = 0;
! 
!       for (i = regno_first; i <= regno_last; ++i)
! 	{
! 	  int needed_regno = REGNO_REG_SET_P (pbi->reg_live, i);
! 	  if (pbi->local_set)
! 	    {
! 	      /* Order of the set operation matters here since both
! 		 sets may be the same.  */
! 	      CLEAR_REGNO_REG_SET (pbi->cond_local_set, i);
! 	      if (cond != NULL_RTX
! 		  && ! REGNO_REG_SET_P (pbi->local_set, i))
! 		SET_REGNO_REG_SET (pbi->cond_local_set, i);
! 	      else
! 		SET_REGNO_REG_SET (pbi->local_set, i);
! 	    }
! 	  if (code != CLOBBER)
! 	    SET_REGNO_REG_SET (pbi->new_set, i);
! 
! 	  some_was_live |= needed_regno;
! 	  some_was_dead |= ! needed_regno;
! 	}
! 
! #ifdef HAVE_conditional_execution
!       /* Consider conditional death in deciding that the register needs
! 	 a death note.  */
!       if (some_was_live && ! not_dead
! 	  /* The stack pointer is never dead.  Well, not strictly true,
! 	     but it's very difficult to tell from here.  Hopefully
! 	     combine_stack_adjustments will fix up the most egregious
! 	     errors.  */
! 	  && regno_first != STACK_POINTER_REGNUM)
! 	{
! 	  for (i = regno_first; i <= regno_last; ++i)
! 	    if (! mark_regno_cond_dead (pbi, i, cond))
! 	      not_dead |= ((unsigned long) 1) << (i - regno_first);
! 	}
! #endif
! 
!       /* Additional data to record if this is the final pass.  */
!       if (flags & (PROP_LOG_LINKS | PROP_REG_INFO
! 		   | PROP_DEATH_NOTES | PROP_AUTOINC))
! 	{
! 	  rtx y;
! 	  int blocknum = pbi->bb->index;
! 
! 	  y = NULL_RTX;
! 	  if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
! 	    {
! 	      y = pbi->reg_next_use[regno_first];
! 
! 	      /* The next use is no longer next, since a store intervenes.  */
! 	      for (i = regno_first; i <= regno_last; ++i)
! 		pbi->reg_next_use[i] = 0;
! 	    }
! 
! 	  if (flags & PROP_REG_INFO)
! 	    {
! 	      for (i = regno_first; i <= regno_last; ++i)
! 		{
! 		  /* Count (weighted) references, stores, etc.  This counts a
! 		     register twice if it is modified, but that is correct.  */
! 		  REG_N_SETS (i) += 1;
! 		  REG_N_REFS (i) += 1;
! 		  REG_FREQ (i) += REG_FREQ_FROM_BB (pbi->bb);
! 
! 	          /* The insns where a reg is live are normally counted
! 		     elsewhere, but we want the count to include the insn
! 		     where the reg is set, and the normal counting mechanism
! 		     would not count it.  */
! 		  REG_LIVE_LENGTH (i) += 1;
! 		}
! 
! 	      /* If this is a hard reg, record this function uses the reg.  */
! 	      if (regno_first < FIRST_PSEUDO_REGISTER)
! 		{
! 		  for (i = regno_first; i <= regno_last; i++)
! 		    regs_ever_live[i] = 1;
! 		}
! 	      else
! 		{
! 		  /* Keep track of which basic blocks each reg appears in.  */
! 		  if (REG_BASIC_BLOCK (regno_first) == REG_BLOCK_UNKNOWN)
! 		    REG_BASIC_BLOCK (regno_first) = blocknum;
! 		  else if (REG_BASIC_BLOCK (regno_first) != blocknum)
! 		    REG_BASIC_BLOCK (regno_first) = REG_BLOCK_GLOBAL;
! 		}
! 	    }
! 
! 	  if (! some_was_dead)
! 	    {
! 	      if (flags & PROP_LOG_LINKS)
! 		{
! 		  /* Make a logical link from the next following insn
! 		     that uses this register, back to this insn.
! 		     The following insns have already been processed.
! 
! 		     We don't build a LOG_LINK for hard registers containing
! 		     in ASM_OPERANDs.  If these registers get replaced,
! 		     we might wind up changing the semantics of the insn,
! 		     even if reload can make what appear to be valid
! 		     assignments later.  */
! 		  if (y && (BLOCK_NUM (y) == blocknum)
! 		      && (regno_first >= FIRST_PSEUDO_REGISTER
! 			  || asm_noperands (PATTERN (y)) < 0))
! 		    LOG_LINKS (y) = alloc_INSN_LIST (insn, LOG_LINKS (y));
! 		}
! 	    }
! 	  else if (not_dead)
! 	    ;
! 	  else if (! some_was_live)
! 	    {
! 	      if (flags & PROP_REG_INFO)
! 		REG_N_DEATHS (regno_first) += 1;
! 
! 	      if (flags & PROP_DEATH_NOTES)
! 		{
! 		  /* Note that dead stores have already been deleted
! 		     when possible.  If we get here, we have found a
! 		     dead store that cannot be eliminated (because the
! 		     same insn does something useful).  Indicate this
! 		     by marking the reg being set as dying here.  */
! 		  REG_NOTES (insn)
! 		    = alloc_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
! 		}
! 	    }
! 	  else
! 	    {
! 	      if (flags & PROP_DEATH_NOTES)
! 		{
! 		  /* This is a case where we have a multi-word hard register
! 		     and some, but not all, of the words of the register are
! 		     needed in subsequent insns.  Write REG_UNUSED notes
! 		     for those parts that were not needed.  This case should
! 		     be rare.  */
! 
! 		  for (i = regno_first; i <= regno_last; ++i)
! 		    if (! REGNO_REG_SET_P (pbi->reg_live, i))
! 		      REG_NOTES (insn)
! 			= alloc_EXPR_LIST (REG_UNUSED,
! 					   regno_reg_rtx[i],
! 					   REG_NOTES (insn));
! 		}
! 	    }
! 	}
! 
!       /* Mark the register as being dead.  */
!       if (some_was_live
! 	  /* The stack pointer is never dead.  Well, not strictly true,
! 	     but it's very difficult to tell from here.  Hopefully
! 	     combine_stack_adjustments will fix up the most egregious
! 	     errors.  */
! 	  && regno_first != STACK_POINTER_REGNUM)
! 	{
! 	  for (i = regno_first; i <= regno_last; ++i)
! 	    if (!(not_dead & (((unsigned long) 1) << (i - regno_first))))
! 	      CLEAR_REGNO_REG_SET (pbi->reg_live, i);
! 	}
!     }
!   else if (GET_CODE (reg) == REG)
!     {
!       if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
! 	pbi->reg_next_use[regno_first] = 0;
!     }
! 
!   /* If this is the last pass and this is a SCRATCH, show it will be dying
!      here and count it.  */
!   else if (GET_CODE (reg) == SCRATCH)
!     {
!       if (flags & PROP_DEATH_NOTES)
! 	REG_NOTES (insn)
! 	  = alloc_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
      }
  }
  
  #ifdef HAVE_conditional_execution
  /* Mark REGNO conditionally dead.
--- 2918,2940 ----
  
    while (temp)
      {
!       next = XEXP (temp, 1);
!       if (reg_overlap_mentioned_p (exp, XEXP (temp, 0)))
! 	{
! 	  /* Splice this entry out of the list.  */
! 	  if (prev)
! 	    XEXP (prev, 1) = next;
! 	  else
! 	    pbi->mem_set_list = next;
! 	  free_EXPR_LIST_node (temp);
! 	  pbi->mem_set_list_len--;
! 	}
!       else
! 	prev = temp;
!       temp = next;
      }
  }
+ 
  
  #ifdef HAVE_conditional_execution
  /* Mark REGNO conditionally dead.
*************** elim_reg_cond (x, regno)
*** 3312,3318 ****
     that has a single set whose source is a PLUS of INCR_REG and something
     else.  */
  
! static void
  attempt_auto_inc (pbi, inc, insn, mem, incr, incr_reg)
       struct propagate_block_info *pbi;
       rtx inc, insn, mem, incr, incr_reg;
--- 3371,3377 ----
     that has a single set whose source is a PLUS of INCR_REG and something
     else.  */
  
! static int
  attempt_auto_inc (pbi, inc, insn, mem, incr, incr_reg)
       struct propagate_block_info *pbi;
       rtx inc, insn, mem, incr, incr_reg;
*************** attempt_auto_inc (pbi, inc, insn, mem, i
*** 3325,3331 ****
  
    /* Make sure this reg appears only once in this insn.  */
    if (count_occurrences (PATTERN (insn), incr_reg, 1) != 1)
!     return;
  
    if (dead_or_set_p (incr, incr_reg)
        /* Mustn't autoinc an eliminable register.  */
--- 3384,3390 ----
  
    /* Make sure this reg appears only once in this insn.  */
    if (count_occurrences (PATTERN (insn), incr_reg, 1) != 1)
!     return 0;
  
    if (dead_or_set_p (incr, incr_reg)
        /* Mustn't autoinc an eliminable register.  */
*************** attempt_auto_inc (pbi, inc, insn, mem, i
*** 3336,3342 ****
  	 we can't, we are done.  Otherwise, we will do any
  	 needed updates below.  */
        if (! validate_change (insn, &XEXP (mem, 0), inc, 0))
! 	return;
      }
    else if (GET_CODE (q) == REG
  	   /* PREV_INSN used here to check the semi-open interval
--- 3395,3401 ----
  	 we can't, we are done.  Otherwise, we will do any
  	 needed updates below.  */
        if (! validate_change (insn, &XEXP (mem, 0), inc, 0))
! 	return 0;
      }
    else if (GET_CODE (q) == REG
  	   /* PREV_INSN used here to check the semi-open interval
*************** attempt_auto_inc (pbi, inc, insn, mem, i
*** 3368,3374 ****
        validate_change (insn, &XEXP (mem, 0), inc, 1);
        validate_change (incr, &XEXP (y, opnum), q, 1);
        if (! apply_change_group ())
! 	return;
  
        /* We now know we'll be doing this change, so emit the
  	 new insn(s) and do the updates.  */
--- 3427,3433 ----
        validate_change (insn, &XEXP (mem, 0), inc, 1);
        validate_change (incr, &XEXP (y, opnum), q, 1);
        if (! apply_change_group ())
! 	return 0;
  
        /* We now know we'll be doing this change, so emit the
  	 new insn(s) and do the updates.  */
*************** attempt_auto_inc (pbi, inc, insn, mem, i
*** 3391,4015 ****
        incr_reg = q;
        regno = REGNO (q);
  
-       /* REGNO is now used in INCR which is below INSN, but
- 	 it previously wasn't live here.  If we don't mark
- 	 it as live, we'll put a REG_DEAD note for it
- 	 on this insn, which is incorrect.  */
-       SET_REGNO_REG_SET (pbi->reg_live, regno);
- 
        /* If there are any calls between INSN and INCR, show
  	 that REGNO now crosses them.  */
!       for (temp = insn; temp != incr; temp = NEXT_INSN (temp))
! 	if (GET_CODE (temp) == CALL_INSN)
! 	  REG_N_CALLS_CROSSED (regno)++;
! 
!       /* Invalidate alias info for Q since we just changed its value.  */
!       clear_reg_alias_info (q);
!     }
!   else
!     return;
! 
!   /* If we haven't returned, it means we were able to make the
!      auto-inc, so update the status.  First, record that this insn
!      has an implicit side effect.  */
! 
!   REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, incr_reg, REG_NOTES (insn));
! 
!   /* Modify the old increment-insn to simply copy
!      the already-incremented value of our register.  */
!   if (! validate_change (incr, &SET_SRC (set), incr_reg, 0))
!     abort ();
! 
!   /* If that makes it a no-op (copying the register into itself) delete
!      it so it won't appear to be a "use" and a "set" of this
!      register.  */
!   if (REGNO (SET_DEST (set)) == REGNO (incr_reg))
!     {
!       /* If the original source was dead, it's dead now.  */
!       rtx note;
! 
!       while ((note = find_reg_note (incr, REG_DEAD, NULL_RTX)) != NULL_RTX)
! 	{
! 	  remove_note (incr, note);
! 	  if (XEXP (note, 0) != incr_reg)
! 	    CLEAR_REGNO_REG_SET (pbi->reg_live, REGNO (XEXP (note, 0)));
! 	}
! 
!       PUT_CODE (incr, NOTE);
!       NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
!       NOTE_SOURCE_FILE (incr) = 0;
!     }
! 
!   if (regno >= FIRST_PSEUDO_REGISTER)
!     {
!       /* Count an extra reference to the reg.  When a reg is
! 	 incremented, spilling it is worse, so we want to make
! 	 that less likely.  */
!       REG_FREQ (regno) += REG_FREQ_FROM_BB (pbi->bb);
! 
!       /* Count the increment as a setting of the register,
! 	 even though it isn't a SET in rtl.  */
!       REG_N_SETS (regno)++;
!     }
! }
! 
! /* X is a MEM found in INSN.  See if we can convert it into an auto-increment
!    reference.  */
! 
! static void
! find_auto_inc (pbi, x, insn)
!      struct propagate_block_info *pbi;
!      rtx x;
!      rtx insn;
! {
!   rtx addr = XEXP (x, 0);
!   HOST_WIDE_INT offset = 0;
!   rtx set, y, incr, inc_val;
!   int regno;
!   int size = GET_MODE_SIZE (GET_MODE (x));
! 
!   if (GET_CODE (insn) == JUMP_INSN)
!     return;
! 
!   /* Here we detect use of an index register which might be good for
!      postincrement, postdecrement, preincrement, or predecrement.  */
! 
!   if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT)
!     offset = INTVAL (XEXP (addr, 1)), addr = XEXP (addr, 0);
! 
!   if (GET_CODE (addr) != REG)
!     return;
! 
!   regno = REGNO (addr);
! 
!   /* Is the next use an increment that might make auto-increment? */
!   incr = pbi->reg_next_use[regno];
!   if (incr == 0 || BLOCK_NUM (incr) != BLOCK_NUM (insn))
!     return;
!   set = single_set (incr);
!   if (set == 0 || GET_CODE (set) != SET)
!     return;
!   y = SET_SRC (set);
! 
!   if (GET_CODE (y) != PLUS)
!     return;
! 
!   if (REG_P (XEXP (y, 0)) && REGNO (XEXP (y, 0)) == REGNO (addr))
!     inc_val = XEXP (y, 1);
!   else if (REG_P (XEXP (y, 1)) && REGNO (XEXP (y, 1)) == REGNO (addr))
!     inc_val = XEXP (y, 0);
!   else
!     return;
! 
!   if (GET_CODE (inc_val) == CONST_INT)
!     {
!       if (HAVE_POST_INCREMENT
! 	  && (INTVAL (inc_val) == size && offset == 0))
! 	attempt_auto_inc (pbi, gen_rtx_POST_INC (Pmode, addr), insn, x,
! 			  incr, addr);
!       else if (HAVE_POST_DECREMENT
! 	       && (INTVAL (inc_val) == -size && offset == 0))
! 	attempt_auto_inc (pbi, gen_rtx_POST_DEC (Pmode, addr), insn, x,
! 			  incr, addr);
!       else if (HAVE_PRE_INCREMENT
! 	       && (INTVAL (inc_val) == size && offset == size))
! 	attempt_auto_inc (pbi, gen_rtx_PRE_INC (Pmode, addr), insn, x,
! 			  incr, addr);
!       else if (HAVE_PRE_DECREMENT
! 	       && (INTVAL (inc_val) == -size && offset == -size))
! 	attempt_auto_inc (pbi, gen_rtx_PRE_DEC (Pmode, addr), insn, x,
! 			  incr, addr);
!       else if (HAVE_POST_MODIFY_DISP && offset == 0)
! 	attempt_auto_inc (pbi, gen_rtx_POST_MODIFY (Pmode, addr,
! 						    gen_rtx_PLUS (Pmode,
! 								  addr,
! 								  inc_val)),
! 			  insn, x, incr, addr);
!     }
!   else if (GET_CODE (inc_val) == REG
! 	   && ! reg_set_between_p (inc_val, PREV_INSN (insn),
! 				   NEXT_INSN (incr)))
! 
!     {
!       if (HAVE_POST_MODIFY_REG && offset == 0)
! 	attempt_auto_inc (pbi, gen_rtx_POST_MODIFY (Pmode, addr,
! 						    gen_rtx_PLUS (Pmode,
! 								  addr,
! 								  inc_val)),
! 			  insn, x, incr, addr);
!     }
! }
! 
! #endif /* AUTO_INC_DEC */
! 
! static void
! mark_used_reg (pbi, reg, cond, insn)
!      struct propagate_block_info *pbi;
!      rtx reg;
!      rtx cond ATTRIBUTE_UNUSED;
!      rtx insn;
! {
!   unsigned int regno_first, regno_last, i;
!   int some_was_live, some_was_dead, some_not_set;
! 
!   regno_last = regno_first = REGNO (reg);
!   if (regno_first < FIRST_PSEUDO_REGISTER)
!     regno_last += HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1;
! 
!   /* Find out if any of this register is live after this instruction.  */
!   some_was_live = some_was_dead = 0;
!   for (i = regno_first; i <= regno_last; ++i)
!     {
!       int needed_regno = REGNO_REG_SET_P (pbi->reg_live, i);
!       some_was_live |= needed_regno;
!       some_was_dead |= ! needed_regno;
!     }
! 
!   /* Find out if any of the register was set this insn.  */
!   some_not_set = 0;
!   for (i = regno_first; i <= regno_last; ++i)
!     some_not_set |= ! REGNO_REG_SET_P (pbi->new_set, i);
! 
!   if (pbi->flags & (PROP_LOG_LINKS | PROP_AUTOINC))
!     {
!       /* Record where each reg is used, so when the reg is set we know
! 	 the next insn that uses it.  */
!       pbi->reg_next_use[regno_first] = insn;
!     }
! 
!   if (pbi->flags & PROP_REG_INFO)
!     {
!       if (regno_first < FIRST_PSEUDO_REGISTER)
! 	{
! 	  /* If this is a register we are going to try to eliminate,
! 	     don't mark it live here.  If we are successful in
! 	     eliminating it, it need not be live unless it is used for
! 	     pseudos, in which case it will have been set live when it
! 	     was allocated to the pseudos.  If the register will not
! 	     be eliminated, reload will set it live at that point.
! 
! 	     Otherwise, record that this function uses this register.  */
! 	  /* ??? The PPC backend tries to "eliminate" on the pic
! 	     register to itself.  This should be fixed.  In the mean
! 	     time, hack around it.  */
! 
! 	  if (! (TEST_HARD_REG_BIT (elim_reg_set, regno_first)
! 	         && (regno_first == FRAME_POINTER_REGNUM
! 		     || regno_first == ARG_POINTER_REGNUM)))
! 	    for (i = regno_first; i <= regno_last; ++i)
! 	      regs_ever_live[i] = 1;
! 	}
!       else
! 	{
! 	  /* Keep track of which basic block each reg appears in.  */
! 
! 	  int blocknum = pbi->bb->index;
! 	  if (REG_BASIC_BLOCK (regno_first) == REG_BLOCK_UNKNOWN)
! 	    REG_BASIC_BLOCK (regno_first) = blocknum;
! 	  else if (REG_BASIC_BLOCK (regno_first) != blocknum)
! 	    REG_BASIC_BLOCK (regno_first) = REG_BLOCK_GLOBAL;
! 
! 	  /* Count (weighted) number of uses of each reg.  */
! 	  REG_FREQ (regno_first) += REG_FREQ_FROM_BB (pbi->bb);
! 	  REG_N_REFS (regno_first)++;
! 	}
!     }
! 
!   /* Record and count the insns in which a reg dies.  If it is used in
!      this insn and was dead below the insn then it dies in this insn.
!      If it was set in this insn, we do not make a REG_DEAD note;
!      likewise if we already made such a note.  */
!   if ((pbi->flags & (PROP_DEATH_NOTES | PROP_REG_INFO))
!       && some_was_dead
!       && some_not_set)
!     {
!       /* Check for the case where the register dying partially
! 	 overlaps the register set by this insn.  */
!       if (regno_first != regno_last)
! 	for (i = regno_first; i <= regno_last; ++i)
! 	  some_was_live |= REGNO_REG_SET_P (pbi->new_set, i);
! 
!       /* If none of the words in X is needed, make a REG_DEAD note.
! 	 Otherwise, we must make partial REG_DEAD notes.  */
!       if (! some_was_live)
! 	{
! 	  if ((pbi->flags & PROP_DEATH_NOTES)
! 	      && ! find_regno_note (insn, REG_DEAD, regno_first))
! 	    REG_NOTES (insn)
! 	      = alloc_EXPR_LIST (REG_DEAD, reg, REG_NOTES (insn));
! 
! 	  if (pbi->flags & PROP_REG_INFO)
! 	    REG_N_DEATHS (regno_first)++;
! 	}
!       else
! 	{
! 	  /* Don't make a REG_DEAD note for a part of a register
! 	     that is set in the insn.  */
! 	  for (i = regno_first; i <= regno_last; ++i)
! 	    if (! REGNO_REG_SET_P (pbi->reg_live, i)
! 		&& ! dead_or_set_regno_p (insn, i))
! 	      REG_NOTES (insn)
! 		= alloc_EXPR_LIST (REG_DEAD,
! 				   regno_reg_rtx[i],
! 				   REG_NOTES (insn));
! 	}
!     }
! 
!   /* Mark the register as being live.  */
!   for (i = regno_first; i <= regno_last; ++i)
!     {
! #ifdef HAVE_conditional_execution
!       int this_was_live = REGNO_REG_SET_P (pbi->reg_live, i);
! #endif
! 
!       SET_REGNO_REG_SET (pbi->reg_live, i);
! 
! #ifdef HAVE_conditional_execution
!       /* If this is a conditional use, record that fact.  If it is later
! 	 conditionally set, we'll know to kill the register.  */
!       if (cond != NULL_RTX)
! 	{
! 	  splay_tree_node node;
! 	  struct reg_cond_life_info *rcli;
! 	  rtx ncond;
! 
! 	  if (this_was_live)
! 	    {
! 	      node = splay_tree_lookup (pbi->reg_cond_dead, i);
! 	      if (node == NULL)
! 		{
! 		  /* The register was unconditionally live previously.
! 		     No need to do anything.  */
! 		}
! 	      else
! 		{
! 		  /* The register was conditionally live previously.
! 		     Subtract the new life cond from the old death cond.  */
! 		  rcli = (struct reg_cond_life_info *) node->value;
! 		  ncond = rcli->condition;
! 		  ncond = and_reg_cond (ncond, not_reg_cond (cond), 1);
! 
! 		  /* If the register is now unconditionally live,
! 		     remove the entry in the splay_tree.  */
! 		  if (ncond == const0_rtx)
! 		    splay_tree_remove (pbi->reg_cond_dead, i);
! 		  else
! 		    {
! 		      rcli->condition = ncond;
! 		      SET_REGNO_REG_SET (pbi->reg_cond_reg,
! 					 REGNO (XEXP (cond, 0)));
! 		    }
! 		}
! 	    }
! 	  else
! 	    {
! 	      /* The register was not previously live at all.  Record
! 		 the condition under which it is still dead.  */
! 	      rcli = (struct reg_cond_life_info *) xmalloc (sizeof (*rcli));
! 	      rcli->condition = not_reg_cond (cond);
! 	      rcli->stores = const0_rtx;
! 	      rcli->orig_condition = const0_rtx;
! 	      splay_tree_insert (pbi->reg_cond_dead, i,
! 				 (splay_tree_value) rcli);
! 
! 	      SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0)));
! 	    }
! 	}
!       else if (this_was_live)
! 	{
! 	  /* The register may have been conditionally live previously, but
! 	     is now unconditionally live.  Remove it from the conditionally
! 	     dead list, so that a conditional set won't cause us to think
! 	     it dead.  */
! 	  splay_tree_remove (pbi->reg_cond_dead, i);
! 	}
! #endif
!     }
! }
! 
! /* Scan expression X and store a 1-bit in NEW_LIVE for each reg it uses.
!    This is done assuming the registers needed from X are those that
!    have 1-bits in PBI->REG_LIVE.
! 
!    INSN is the containing instruction.  If INSN is dead, this function
!    is not called.  */
! 
! static void
! mark_used_regs (pbi, x, cond, insn)
!      struct propagate_block_info *pbi;
!      rtx x, cond, insn;
! {
!   RTX_CODE code;
!   int regno;
!   int flags = pbi->flags;
! 
!  retry:
!   if (!x)
!     return;
!   code = GET_CODE (x);
!   switch (code)
!     {
!     case LABEL_REF:
!     case SYMBOL_REF:
!     case CONST_INT:
!     case CONST:
!     case CONST_DOUBLE:
!     case CONST_VECTOR:
!     case PC:
!     case ADDR_VEC:
!     case ADDR_DIFF_VEC:
!       return;
! 
! #ifdef HAVE_cc0
!     case CC0:
!       pbi->cc0_live = 1;
!       return;
! #endif
! 
!     case CLOBBER:
!       /* If we are clobbering a MEM, mark any registers inside the address
! 	 as being used.  */
!       if (GET_CODE (XEXP (x, 0)) == MEM)
! 	mark_used_regs (pbi, XEXP (XEXP (x, 0), 0), cond, insn);
!       return;
  
!     case MEM:
!       /* Don't bother watching stores to mems if this is not the
! 	 final pass.  We'll not be deleting dead stores this round.  */
!       if (optimize && (flags & PROP_SCAN_DEAD_STORES))
! 	{
! 	  /* Invalidate the data for the last MEM stored, but only if MEM is
! 	     something that can be stored into.  */
! 	  if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
! 	      && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
! 	    /* Needn't clear the memory set list.  */
! 	    ;
! 	  else
! 	    {
! 	      rtx temp = pbi->mem_set_list;
! 	      rtx prev = NULL_RTX;
! 	      rtx next;
  
! 	      while (temp)
! 		{
! 		  next = XEXP (temp, 1);
! 		  if (anti_dependence (XEXP (temp, 0), x))
! 		    {
! 		      /* Splice temp out of the list.  */
! 		      if (prev)
! 			XEXP (prev, 1) = next;
! 		      else
! 			pbi->mem_set_list = next;
! 		      free_EXPR_LIST_node (temp);
! 		      pbi->mem_set_list_len--;
! 		    }
! 		  else
! 		    prev = temp;
! 		  temp = next;
! 		}
! 	    }
  
! 	  /* If the memory reference had embedded side effects (autoincrement
! 	     address modes.  Then we may need to kill some entries on the
! 	     memory set list.  */
! 	  if (insn)
! 	    for_each_rtx (&PATTERN (insn), invalidate_mems_from_autoinc, pbi);
! 	}
  
! #ifdef AUTO_INC_DEC
!       if (flags & PROP_AUTOINC)
! 	find_auto_inc (pbi, x, insn);
! #endif
!       break;
  
!     case SUBREG:
! #ifdef CANNOT_CHANGE_MODE_CLASS
!       if (GET_CODE (SUBREG_REG (x)) == REG
! 	  && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
! 	SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (x)],
! 			   REGNO (SUBREG_REG (x)));
! #endif
  
!       /* While we're here, optimize this case.  */
!       x = SUBREG_REG (x);
!       if (GET_CODE (x) != REG)
! 	goto retry;
!       /* Fall through.  */
! 
!     case REG:
!       /* See a register other than being set => mark it as needed.  */
!       mark_used_reg (pbi, x, cond, insn);
!       return;
  
!     case SET:
!       {
! 	rtx testreg = SET_DEST (x);
! 	int mark_dest = 0;
  
! 	/* If storing into MEM, don't show it as being used.  But do
! 	   show the address as being used.  */
! 	if (GET_CODE (testreg) == MEM)
! 	  {
! #ifdef AUTO_INC_DEC
! 	    if (flags & PROP_AUTOINC)
! 	      find_auto_inc (pbi, testreg, insn);
! #endif
! 	    mark_used_regs (pbi, XEXP (testreg, 0), cond, insn);
! 	    mark_used_regs (pbi, SET_SRC (x), cond, insn);
! 	    return;
! 	  }
  
! 	/* Storing in STRICT_LOW_PART is like storing in a reg
! 	   in that this SET might be dead, so ignore it in TESTREG.
! 	   but in some other ways it is like using the reg.
! 
! 	   Storing in a SUBREG or a bit field is like storing the entire
! 	   register in that if the register's value is not used
! 	   then this SET is not needed.  */
! 	while (GET_CODE (testreg) == STRICT_LOW_PART
! 	       || GET_CODE (testreg) == ZERO_EXTRACT
! 	       || GET_CODE (testreg) == SIGN_EXTRACT
! 	       || GET_CODE (testreg) == SUBREG)
! 	  {
! #ifdef CANNOT_CHANGE_MODE_CLASS
! 	    if (GET_CODE (testreg) == SUBREG
! 		&& GET_CODE (SUBREG_REG (testreg)) == REG
! 		&& REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER)
! 	      SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (testreg)],
! 				 REGNO (SUBREG_REG (testreg)));
! #endif
! 
! 	    /* Modifying a single register in an alternate mode
! 	       does not use any of the old value.  But these other
! 	       ways of storing in a register do use the old value.  */
! 	    if (GET_CODE (testreg) == SUBREG
! 		&& !((REG_BYTES (SUBREG_REG (testreg))
! 		      + UNITS_PER_WORD - 1) / UNITS_PER_WORD
! 		     > (REG_BYTES (testreg)
! 			+ UNITS_PER_WORD - 1) / UNITS_PER_WORD))
! 	      ;
! 	    else
! 	      mark_dest = 1;
  
! 	    testreg = XEXP (testreg, 0);
! 	  }
  
! 	/* If this is a store into a register or group of registers,
! 	   recursively scan the value being stored.  */
  
! 	if ((GET_CODE (testreg) == PARALLEL
! 	     && GET_MODE (testreg) == BLKmode)
! 	    || (GET_CODE (testreg) == REG
! 		&& (regno = REGNO (testreg),
! 		    ! (regno == FRAME_POINTER_REGNUM
! 		       && (! reload_completed || frame_pointer_needed)))
! #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
! 		&& ! (regno == HARD_FRAME_POINTER_REGNUM
! 		      && (! reload_completed || frame_pointer_needed))
! #endif
! #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
! 		&& ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
! #endif
! 		))
! 	  {
! 	    if (mark_dest)
! 	      mark_used_regs (pbi, SET_DEST (x), cond, insn);
! 	    mark_used_regs (pbi, SET_SRC (x), cond, insn);
! 	    return;
! 	  }
!       }
!       break;
  
!     case ASM_OPERANDS:
!     case UNSPEC_VOLATILE:
!     case TRAP_IF:
!     case ASM_INPUT:
!       {
! 	/* Traditional and volatile asm instructions must be considered to use
! 	   and clobber all hard registers, all pseudo-registers and all of
! 	   memory.  So must TRAP_IF and UNSPEC_VOLATILE operations.
! 
! 	   Consider for instance a volatile asm that changes the fpu rounding
! 	   mode.  An insn should not be moved across this even if it only uses
! 	   pseudo-regs because it might give an incorrectly rounded result.
! 
! 	   ?!? Unfortunately, marking all hard registers as live causes massive
! 	   problems for the register allocator and marking all pseudos as live
! 	   creates mountains of uninitialized variable warnings.
! 
! 	   So for now, just clear the memory set list and mark any regs
! 	   we can find in ASM_OPERANDS as used.  */
! 	if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
! 	  {
! 	    free_EXPR_LIST_list (&pbi->mem_set_list);
! 	    pbi->mem_set_list_len = 0;
! 	  }
  
! 	/* For all ASM_OPERANDS, we must traverse the vector of input operands.
! 	   We can not just fall through here since then we would be confused
! 	   by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate
! 	   traditional asms unlike their normal usage.  */
! 	if (code == ASM_OPERANDS)
! 	  {
! 	    int j;
  
! 	    for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
! 	      mark_used_regs (pbi, ASM_OPERANDS_INPUT (x, j), cond, insn);
! 	  }
! 	break;
!       }
  
!     case COND_EXEC:
!       if (cond != NULL_RTX)
! 	abort ();
  
!       mark_used_regs (pbi, COND_EXEC_TEST (x), NULL_RTX, insn);
  
!       cond = COND_EXEC_TEST (x);
!       x = COND_EXEC_CODE (x);
!       goto retry;
! 
!     case PHI:
!       /* We _do_not_ want to scan operands of phi nodes.  Operands of
! 	 a phi function are evaluated only when control reaches this
! 	 block along a particular edge.  Therefore, regs that appear
! 	 as arguments to phi should not be added to the global live at
! 	 start.  */
!       return;
  
!     default:
!       break;
      }
  
!   /* Recursively scan the operands of this expression.  */
! 
!   {
!     const char * const fmt = GET_RTX_FORMAT (code);
!     int i;
  
!     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
!       {
! 	if (fmt[i] == 'e')
! 	  {
! 	    /* Tail recursive case: save a function call level.  */
! 	    if (i == 0)
! 	      {
! 		x = XEXP (x, 0);
! 		goto retry;
! 	      }
! 	    mark_used_regs (pbi, XEXP (x, i), cond, insn);
! 	  }
! 	else if (fmt[i] == 'E')
! 	  {
! 	    int j;
! 	    for (j = 0; j < XVECLEN (x, i); j++)
! 	      mark_used_regs (pbi, XVECEXP (x, i, j), cond, insn);
! 	  }
!       }
!   }
  }
- 
- #ifdef AUTO_INC_DEC
  
  static int
  try_pre_increment_1 (pbi, insn)
--- 3450,3592 ----
        incr_reg = q;
        regno = REGNO (q);
  
        /* If there are any calls between INSN and INCR, show
  	 that REGNO now crosses them.  */
!       for (temp = insn; temp != incr; temp = NEXT_INSN (temp))
! 	if (GET_CODE (temp) == CALL_INSN)
! 	  REG_N_CALLS_CROSSED (regno)++;
  
!       /* Invalidate alias info for Q since we just changed its value.  */
!       clear_reg_alias_info (q);
!     }
!   else
!     return 0;
  
!   /* If we haven't returned, it means we were able to make the
!      auto-inc, so update the status.  First, record that this insn
!      has an implicit side effect.  */
  
!   REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, incr_reg, REG_NOTES (insn));
  
!   /* Modify the old increment-insn to simply copy
!      the already-incremented value of our register.  */
!   if (! validate_change (incr, &SET_SRC (set), incr_reg, 0))
!     abort ();
  
!   /* If that makes it a no-op (copying the register into itself) delete
!      it so it won't appear to be a "use" and a "set" of this
!      register.  */
!   if (REGNO (SET_DEST (set)) == REGNO (incr_reg))
!     {
!       /* If the original source was dead, it's dead now.  */
!       rtx note;
  
!       while ((note = find_reg_note (incr, REG_DEAD, NULL_RTX)) != NULL_RTX)
! 	{
! 	  remove_note (incr, note);
! 	  if (XEXP (note, 0) != incr_reg)
! 	    CLEAR_REGNO_REG_SET (pbi->reg_live, REGNO (XEXP (note, 0)));
! 	}
  
!       PUT_CODE (incr, NOTE);
!       NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
!       NOTE_SOURCE_FILE (incr) = 0;
!     }
  
!   return 1;
! }
  
! /* X is a MEM found in INSN.  See if we can convert it into an auto-increment
!    reference.  */
  
! static int
! find_auto_inc (pbi, x, insn)
!      struct propagate_block_info *pbi;
!      rtx x;
!      rtx insn;
! {
!   rtx addr = XEXP (x, 0);
!   HOST_WIDE_INT offset = 0;
!   rtx set, y, incr, inc_val;
!   int regno;
!   int size = GET_MODE_SIZE (GET_MODE (x));
!   int changed = 0;
  
!   if (GET_CODE (insn) == JUMP_INSN)
!     return 0;
  
!   /* Here we detect use of an index register which might be good for
!      postincrement, postdecrement, preincrement, or predecrement.  */
  
!   if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT)
!     offset = INTVAL (XEXP (addr, 1)), addr = XEXP (addr, 0);
  
!   if (GET_CODE (addr) != REG)
!     return 0;
  
!   regno = REGNO (addr);
  
!   /* Is the next use an increment that might make auto-increment? */
!   incr = pbi->reg_next_use[regno];
!   if (incr == 0 || BLOCK_NUM (incr) != BLOCK_NUM (insn))
!     return 0;
!   set = single_set (incr);
!   if (set == 0 || GET_CODE (set) != SET)
!     return 0;
!   y = SET_SRC (set);
  
!   if (GET_CODE (y) != PLUS)
!     return 0;
  
!   if (REG_P (XEXP (y, 0)) && REGNO (XEXP (y, 0)) == REGNO (addr))
!     inc_val = XEXP (y, 1);
!   else if (REG_P (XEXP (y, 1)) && REGNO (XEXP (y, 1)) == REGNO (addr))
!     inc_val = XEXP (y, 0);
!   else
!     return 0;
  
!   if (GET_CODE (inc_val) == CONST_INT)
!     {
!       if (HAVE_POST_INCREMENT
! 	  && (INTVAL (inc_val) == size && offset == 0))
! 	changed = attempt_auto_inc (pbi, gen_rtx_POST_INC (Pmode, addr),
! 				    insn, x, incr, addr);
!       else if (HAVE_POST_DECREMENT
! 	       && (INTVAL (inc_val) == -size && offset == 0))
! 	changed = attempt_auto_inc (pbi, gen_rtx_POST_DEC (Pmode, addr),
! 				    insn, x, incr, addr);
!       else if (HAVE_PRE_INCREMENT
! 	       && (INTVAL (inc_val) == size && offset == size))
! 	changed = attempt_auto_inc (pbi, gen_rtx_PRE_INC (Pmode, addr),
! 				    insn, x, incr, addr);
!       else if (HAVE_PRE_DECREMENT
! 	       && (INTVAL (inc_val) == -size && offset == -size))
! 	changed = attempt_auto_inc (pbi, gen_rtx_PRE_DEC (Pmode, addr),
! 				    insn, x, incr, addr);
!       else if (HAVE_POST_MODIFY_DISP && offset == 0)
! 	changed = attempt_auto_inc (pbi,
! 				    gen_rtx_POST_MODIFY (Pmode, addr,
! 					gen_rtx_PLUS (Pmode,
! 						      addr,
! 						      inc_val)),
! 				    insn, x, incr, addr);
      }
+   else if (GET_CODE (inc_val) == REG
+ 	   && ! reg_set_between_p (inc_val, PREV_INSN (insn),
+ 				   NEXT_INSN (incr)))
  
!     {
!       if (HAVE_POST_MODIFY_REG && offset == 0)
! 	changed = attempt_auto_inc (pbi,
! 				    gen_rtx_POST_MODIFY (Pmode, addr,
! 					    gen_rtx_PLUS (Pmode,
! 							  addr,
! 							  inc_val)),
! 				    insn, x, incr, addr);
!     }
  
!   return changed;
  }
  
  static int
  try_pre_increment_1 (pbi, insn)
*************** debug_regset (r)
*** 4235,4241 ****
  }
  
  /* Recompute register set/reference counts immediately prior to register
!    allocation.
  
     This avoids problems with set/reference counts changing to/from values
     which have special meanings to the register allocators.
--- 3812,3818 ----
  }
  
  /* Recompute register set/reference counts immediately prior to register
!    allocation. Requieres liveness info to be up-to-date.
  
     This avoids problems with set/reference counts changing to/from values
     which have special meanings to the register allocators.
*************** debug_regset (r)
*** 4243,4265 ****
     Additionally, the reference counts are the primary component used by the
     register allocators to prioritize pseudos for allocation to hard regs.
     More accurate reference counts generally lead to better register allocation.
  
!    F is the first insn to be scanned.
  
!    LOOP_STEP denotes how much loop_depth should be incremented per
!    loop nesting level in order to increase the ref count more for
!    references in a loop.
  
!    It might be worthwhile to update REG_LIVE_LENGTH, REG_BASIC_BLOCK and
!    possibly other information which is used by the register allocators.  */
  
! void
! recompute_reg_usage (f, loop_step)
!      rtx f ATTRIBUTE_UNUSED;
!      int loop_step ATTRIBUTE_UNUSED;
! {
    allocate_reg_life_data ();
!   update_life_info (NULL, UPDATE_LIFE_LOCAL, PROP_REG_INFO);
  }
  
  /* Optionally removes all the REG_DEAD and REG_UNUSED notes from a set of
--- 3820,3949 ----
     Additionally, the reference counts are the primary component used by the
     register allocators to prioritize pseudos for allocation to hard regs.
     More accurate reference counts generally lead to better register allocation.
+    */
  
! void
! compute_reg_usage (allocate_data)
!      int allocate_data;
! {
!   basic_block bb;
!   rtx insn;
! #ifdef CANNOT_CHANGE_MODE_CLASS
!   rtx subreg;
! #endif
!   regset live;
!   regset_head live_head;
!   struct insn_extract *insn_info;
!   int i;
!   struct propagate_block_info *pbi;
  
!   if (allocate_data)
!     {
!       memset (regs_ever_live, 0, sizeof (regs_ever_live));
  
! #ifdef CANNOT_CHANGE_MODE_CLASS
!       for (i=0; i < NUM_MACHINE_MODES; ++i)
! 	INIT_REG_SET (&subregs_of_mode[i]);
! #endif
!     }
  
!   live = INITIALIZE_REG_SET (live_head);
    allocate_reg_life_data ();
! 
!   FOR_EACH_BB (bb)
!     {
!       COPY_REG_SET (live, bb->global_live_at_end);
!       pbi = init_propagate_block_info (bb, live, NULL, NULL, 0);
! 
!       /* Process the regs live at the end of the block.
! 	 Mark them as not local to any one basic block.  */
!       EXECUTE_IF_SET_IN_REG_SET (live, 0, i,
! 				 { REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; });
!   
!       for (insn = bb->end;
! 	   insn != PREV_INSN (bb->head);
! 	   insn = PREV_INSN (insn))
! 	{
! 	  if (!INSN_P (insn))
! 	    continue;
! 
! 	  insn_info = extract_insn_info (insn);
! 
! 	  /* If this is a call to `setjmp' et al, warn if any
! 	     non-volatile datum is live.  */
! 	  if (GET_CODE (insn) == CALL_INSN
! 	      && find_reg_note (insn, REG_SETJMP, NULL))
! 	    IOR_REG_SET (regs_live_at_setjmp, pbi->reg_live);
! 
! 	  /* Any regs live at the time of a call instruction must not go
! 	     in a register clobbered by calls.  Find all regs now live and
! 	     record this for them.  */
! 
! 	  if (GET_CODE (insn) == CALL_INSN)
! 	    EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
! 				       { REG_N_CALLS_CROSSED (i)++; });
! 
! 	  CLEAR_REG_SET (pbi->new_set);
! 
! 	  /* Count register info for set registers.  */
! 	  count_register_info_for_sets (pbi, insn_info);
! 
! 	  /* Update liveness info.  */
! 	  update_live_by_sets (pbi, insn_info);
! 
! 	  /* Count register info for used registers.  */
! 	  count_register_info_for_uses (pbi, insn_info);
!       
! 	  /* Update liveness info.  */
! 	  update_live_by_uses (pbi, insn_info);
! 
! #ifdef CANNOT_CHANGE_MODE_CLASS
! 	  /* Record subregs_of_mode.  */
! 	  for (i = 0; i < (int) VARRAY_ACTIVE_SIZE (insn_info->subregs); i++)
! 	    {
! 	      subreg = VARRAY_IE_ELEM (insn_info->subregs, i).elem;
! 	      SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (subreg)],
! 				 REGNO (SUBREG_REG (subreg)));
! 	    }
! #endif
! 
! 	  /* On final pass, update counts of how many insns in which each reg
! 	     is live.  */
! 	  EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
! 	      			     { REG_LIVE_LENGTH (i)++; });
! 	}
! 
!       verify_local_live_at_start (live, bb);
!       free_propagate_block_info (pbi);
!     }
!   
!   /* The only pseudos that are live at the beginning of the function
!      are those that were not set anywhere in the function.  local-alloc
!      doesn't know how to handle these correctly, so mark them as not
!      local to any one basic block.  */
!   EXECUTE_IF_SET_IN_REG_SET (ENTRY_BLOCK_PTR->global_live_at_end,
! 			     FIRST_PSEUDO_REGISTER, i,
! 			     { REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; });
! 
!   /* We have a problem with any pseudoreg that lives across the setjmp.
!      ANSI says that if a user variable does not change in value between
!      the setjmp and the longjmp, then the longjmp preserves it.  This
!      includes longjmp from a place where the pseudo appears dead.
!      (In principle, the value still exists if it is in scope.)
!      If the pseudo goes in a hard reg, some other value may occupy
!      that hard reg where this pseudo is dead, thus clobbering the pseudo.
!      Conclusion: such a pseudo must not go in a hard reg.  */
!   EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
! 			     FIRST_PSEUDO_REGISTER, i,
! 			     {
! 		  	      if (regno_reg_rtx[i] != 0)
! 				{
! 				  REG_LIVE_LENGTH (i) = -1;
! 			     	  REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
! 		     		}
! 			     });
!   
!   FREE_REG_SET (live);
  }
  
  /* Optionally removes all the REG_DEAD and REG_UNUSED notes from a set of
*************** reg_set_to_hard_reg_set (to, from)
*** 4379,4381 ****
--- 4063,4236 ----
         SET_HARD_REG_BIT (*to, i);
       });
  }
+ 
+ /* Recompute log links for BLOCKS (for all if NULL).  */
+ void
+ create_log_links (blocks)
+      sbitmap blocks;
+ {
+   struct propagate_block_info pbi;
+   basic_block bb;
+   rtx insn;
+   struct insn_extract *insn_info;
+ 
+   /* Clear the old log links.  */
+   clear_log_links (blocks);
+ 
+   /* Allocate the structures used.  */
+   memset (&pbi, 0, sizeof (pbi));
+   pbi.reg_next_use = (rtx *) xcalloc (max_reg_num (), sizeof (rtx));
+ 
+   /* Pass through the insns and establish log links.  */
+   FOR_EACH_BB (bb)
+     {
+       if (blocks && ! TEST_BIT (blocks, bb->index))
+ 	continue;
+       
+       for (insn = bb->end; insn != PREV_INSN (bb->head); insn = PREV_INSN (insn))
+ 	{
+ 	  if (!INSN_P (insn))
+ 	    continue;
+ 
+ 	  /* Extract the information about definitions, uses etc from insn.  */
+ 	  insn_info = extract_insn_info (insn);
+ 	  
+ 	  /* Set up log links.  */
+ 	  set_up_log_links (insn, &pbi, insn_info);
+ 
+ 	  /* Update reg_next_use.  */
+ 	  update_next_use_sets (&pbi, insn_info);
+ 	  update_next_use_uses (insn, &pbi, insn_info);
+ 	}
+     }
+ 
+   free (pbi.reg_next_use);
+ }
+ 
+ #ifdef AUTO_INC_DEC
+ /* Convert MEMs in BLOCKS (all if NULL) into autoincs.  */
+ void
+ pre_post_modify_transformation (blocks)
+      sbitmap blocks;
+ {
+   struct propagate_block_info pbi;
+   basic_block bb;
+   rtx insn, prev, x;
+   struct insn_extract *insn_info;
+ 
+   /* Allocate the structures used.  */
+   memset (&pbi, 0, sizeof (pbi));
+   pbi.reg_next_use = (rtx *) xcalloc (max_reg_num (), sizeof (rtx));
+ 
+   /* Pass through the insns and attempt the transformations.  */
+   FOR_EACH_BB (bb)
+     {
+       if (blocks && ! TEST_BIT (blocks, bb->index))
+ 	continue;
+       
+       pbi.bb = bb;
+       for (insn = bb->end; insn != PREV_INSN (bb->head); insn = prev)
+ 	{
+ 	  prev = PREV_INSN (insn);
+ 	  if (!INSN_P (insn))
+ 	    continue;
+ 
+ 	  /* See if this is an increment or decrement that can be merged into
+ 	     a following memory address.  */
+ 	  x = single_set (insn);
+ 
+ 	  /* Does this instruction increment or decrement a register?  */
+ 	  if (x != 0
+ 	      && GET_CODE (SET_DEST (x)) == REG
+ 	      && (GET_CODE (SET_SRC (x)) == PLUS
+ 		  || GET_CODE (SET_SRC (x)) == MINUS)
+ 	      && XEXP (SET_SRC (x), 0) == SET_DEST (x)
+ 	      && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
+ 	      /* Ok, look for a following memory ref we can combine with.
+ 		 If one is found, change the memory ref to a PRE_INC
+ 		 or PRE_DEC, cancel this insn, and return 1.
+ 		 Return 0 if nothing has been done.  */
+ 	      && try_pre_increment_1 (&pbi, insn))
+ 	    continue;
+ 
+ 	  /* Extract the information about definitions, uses etc from insn.  */
+ 	  insn_info = extract_insn_info (insn);
+ 	  
+ 	  /* Update reg_next_use by sets.  */
+ 	  update_next_use_sets (&pbi, insn_info);
+ 
+ 	  if (autoinc_transform (&pbi, insn_info, insn))
+     	    {
+ 	      /* The insn has changed, rescan it.  */
+ 	      insn_info = extract_insn_info (insn);
+ 
+ 	      /* Sometimes we may have inserted something before INSN (such as a move)
+ 		 when we make an auto-inc.  So ensure we will scan those insns. */
+ 	      prev = PREV_INSN (insn);
+ 	    }
+ 
+ 	  /* Update reg_next_use by uses.  */
+ 	  update_next_use_uses (insn, &pbi, insn_info);
+ 	}
+     }
+ 
+   free (pbi.reg_next_use);
+ }
+ #endif
+ 
+ /* Compute death notes for BLOCKS (everything if NULL). Requieres liveness
+    info to be up-to-date.  */
+ void
+ compute_death_notes (blocks)
+      sbitmap blocks;
+ {
+   basic_block bb;
+   rtx insn;
+   regset live;
+   regset_head live_head;
+   struct insn_extract *insn_info;
+   struct propagate_block_info *pbi;
+ 
+   /* Remove the existing death notes.  */
+   count_or_remove_death_notes (blocks, 1);
+ 
+   live = INITIALIZE_REG_SET (live_head);
+ 
+   FOR_EACH_BB (bb)
+     {
+       if (blocks && ! TEST_BIT (blocks, bb->index))
+ 	continue;
+ 
+       COPY_REG_SET (live, bb->global_live_at_end);
+       pbi = init_propagate_block_info (bb, live, NULL, NULL, 0);
+ 
+       for (insn = bb->end;
+ 	   insn != PREV_INSN (bb->head);
+ 	   insn = PREV_INSN (insn))
+ 	{
+ 	  if (!INSN_P (insn))
+ 	    continue;
+ 
+ 	  insn_info = extract_insn_info (insn);
+ 
+ 	  CLEAR_REG_SET (pbi->new_set);
+ 
+ 	  /* Create REG_UNUSED notes.  */
+ 	  create_unused_notes (pbi, insn_info, insn);
+ 
+ 	  /* Update liveness info.  */
+ 	  update_live_by_sets (pbi, insn_info);
+ 
+ 	  /* Create REG_DEAD notes.  */
+ 	  create_dead_notes (pbi, insn_info, insn);
+ 
+ 	  /* Update liveness info.  */
+ 	  update_live_by_uses (pbi, insn_info);
+ 	}
+ 
+       verify_local_live_at_start (live, bb);
+       free_propagate_block_info (pbi);
+     }
+   FREE_REG_SET (live);
+ }
+ 
Index: ifcvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.106
diff -c -3 -p -r1.106 ifcvt.c
*** ifcvt.c	16 Dec 2002 18:19:38 -0000	1.106
--- ifcvt.c	29 Dec 2002 20:27:05 -0000
*************** if_convert (x_life_data_ok)
*** 3070,3075 ****
--- 3070,3076 ----
  {
    basic_block bb;
    int pass;
+   sbitmap dirty_blocks;
  
    num_possible_if_blocks = 0;
    num_updated_if_blocks = 0;
*************** if_convert (x_life_data_ok)
*** 3139,3147 ****
  	  max_regno = max_reg_num ();
  	  allocate_reg_info (max_regno, FALSE, FALSE);
  	}
!       update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
! 					PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
! 					| PROP_KILL_DEAD_CODE);
      }
  
    /* Write the final stats.  */
--- 3140,3150 ----
  	  max_regno = max_reg_num ();
  	  allocate_reg_info (max_regno, FALSE, FALSE);
  	}
!       update_life_info_in_dirty_blocks (PROP_SCAN_DEAD_CODE
! 					| PROP_KILL_DEAD_CODE,
! 					&dirty_blocks);
!       compute_death_notes (dirty_blocks);
!       sbitmap_free (dirty_blocks);
      }
  
    /* Write the final stats.  */
Index: lcm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/lcm.c,v
retrieving revision 1.51
diff -c -3 -p -r1.51 lcm.c
*** lcm.c	16 Dec 2002 18:19:41 -0000	1.51
--- lcm.c	29 Dec 2002 20:27:08 -0000
*************** optimize_mode_switching (file)
*** 1027,1032 ****
--- 1027,1033 ----
    int max_num_modes = 0;
    bool emited = false;
    basic_block post_entry ATTRIBUTE_UNUSED, pre_exit ATTRIBUTE_UNUSED;
+   sbitmap dirty_blocks;
  
    clear_bb_flags ();
  
*************** optimize_mode_switching (file)
*** 1343,1351 ****
  
    max_regno = max_reg_num ();
    allocate_reg_info (max_regno, FALSE, FALSE);
!   update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
! 				    (PROP_DEATH_NOTES | PROP_KILL_DEAD_CODE
! 				     | PROP_SCAN_DEAD_CODE));
  
    return 1;
  }
--- 1344,1353 ----
  
    max_regno = max_reg_num ();
    allocate_reg_info (max_regno, FALSE, FALSE);
!   update_life_info_in_dirty_blocks (PROP_KILL_DEAD_CODE | PROP_SCAN_DEAD_CODE,
! 				    &dirty_blocks);
!   compute_death_notes (dirty_blocks);
!   sbitmap_free (dirty_blocks);
  
    return 1;
  }
Index: ra.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ra.c,v
retrieving revision 1.6
diff -c -3 -p -r1.6 ra.c
*** ra.c	25 Dec 2002 15:15:09 -0000	1.6
--- ra.c	29 Dec 2002 20:27:14 -0000
*************** reg_alloc ()
*** 858,867 ****
    /* Cleanup the flow graph.  */
    if ((debug_new_regalloc & DUMP_LAST_FLOW) == 0)
      rtl_dump_file = NULL;
!   life_analysis (get_insns (), rtl_dump_file,
! 		 PROP_DEATH_NOTES | PROP_LOG_LINKS  | PROP_REG_INFO);
    cleanup_cfg (CLEANUP_EXPENSIVE);
!   recompute_reg_usage (get_insns (), TRUE);
    if (rtl_dump_file)
      dump_flow_info (rtl_dump_file);
    rtl_dump_file = ra_dump_file;
--- 858,867 ----
    /* Cleanup the flow graph.  */
    if ((debug_new_regalloc & DUMP_LAST_FLOW) == 0)
      rtl_dump_file = NULL;
!   life_analysis (get_insns (), rtl_dump_file, 0);
!   compute_death_notes (NULL);
    cleanup_cfg (CLEANUP_EXPENSIVE);
!   compute_reg_usage (1);
    if (rtl_dump_file)
      dump_flow_info (rtl_dump_file);
    rtl_dump_file = ra_dump_file;
Index: recog.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/recog.c,v
retrieving revision 1.170
diff -c -3 -p -r1.170 recog.c
*** recog.c	25 Dec 2002 15:15:10 -0000	1.170
--- recog.c	29 Dec 2002 20:27:19 -0000
*************** apply_change_group ()
*** 405,413 ****
  
        for (i = 0; i < num_changes; i++)
  	if (changes[i].object
! 	    && INSN_P (changes[i].object)
! 	    && (bb = BLOCK_FOR_INSN (changes[i].object)))
! 	  bb->flags |= BB_DIRTY;
  
        num_changes = 0;
        return 1;
--- 405,417 ----
  
        for (i = 0; i < num_changes; i++)
  	if (changes[i].object
! 	    && INSN_P (changes[i].object))
! 	  {
! 	    bb = BLOCK_FOR_INSN (changes[i].object);
! 	    if (bb)
! 	      bb->flags |= BB_DIRTY;
! 	    invalidate_insn_extract (changes[i].object);
! 	  }
  
        num_changes = 0;
        return 1;
*************** split_all_insns (upd_life)
*** 2849,2858 ****
      }
  
    if (changed && upd_life)
!     {
!       count_or_remove_death_notes (blocks, 1);
!       update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
!     }
  #ifdef ENABLE_CHECKING
    verify_flow_info ();
  #endif
--- 2853,2859 ----
      }
  
    if (changed && upd_life)
!     compute_death_notes (blocks);
  #ifdef ENABLE_CHECKING
    verify_flow_info ();
  #endif
*************** peephole2_optimize (dump_file)
*** 3081,3090 ****
    regset live;
    int i;
    basic_block bb;
- #ifdef HAVE_conditional_execution
    sbitmap blocks;
-   bool changed;
- #endif
    bool do_cleanup_cfg = false;
    bool do_rebuild_jump_labels = false;
  
--- 3082,3088 ----
*************** peephole2_optimize (dump_file)
*** 3093,3105 ****
      peep2_insn_data[i].live_before = INITIALIZE_REG_SET (rs_heads[i]);
    live = INITIALIZE_REG_SET (rs_heads[i]);
  
- #ifdef HAVE_conditional_execution
    blocks = sbitmap_alloc (last_basic_block);
    sbitmap_zero (blocks);
-   changed = false;
- #else
-   count_or_remove_death_notes (NULL, 1);
- #endif
  
    FOR_EACH_BB_REVERSE (bb)
      {
--- 3091,3098 ----
*************** peephole2_optimize (dump_file)
*** 3117,3127 ****
        COPY_REG_SET (live, bb->global_live_at_end);
        COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
  
- #ifdef HAVE_conditional_execution
        pbi = init_propagate_block_info (bb, live, NULL, NULL, 0);
- #else
-       pbi = init_propagate_block_info (bb, live, NULL, NULL, PROP_DEATH_NOTES);
- #endif
  
        for (insn = bb->end; ; insn = prev)
  	{
--- 3110,3116 ----
*************** peephole2_optimize (dump_file)
*** 3257,3266 ****
  				  = REG_BR_PROB_BASE - nehe->probability;
  
  			        do_cleanup_cfg |= purge_dead_edges (nfte->dest);
- #ifdef HAVE_conditional_execution
  				SET_BIT (blocks, nfte->dest->index);
! 				changed = true;
! #endif
  				bb = nfte->src;
  				eh_edge = nehe;
  			      }
--- 3246,3253 ----
  				  = REG_BR_PROB_BASE - nehe->probability;
  
  			        do_cleanup_cfg |= purge_dead_edges (nfte->dest);
  				SET_BIT (blocks, nfte->dest->index);
! 
  				bb = nfte->src;
  				eh_edge = nehe;
  			      }
*************** peephole2_optimize (dump_file)
*** 3271,3284 ****
  		      do_cleanup_cfg |= purge_dead_edges (bb);
  		    }
  
  #ifdef HAVE_conditional_execution
  		  /* With conditional execution, we cannot back up the
  		     live information so easily, since the conditional
  		     death data structures are not so self-contained.
  		     So record that we've made a modification to this
  		     block and update life information at the end.  */
- 		  SET_BIT (blocks, bb->index);
- 		  changed = true;
  
  		  for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
  		    peep2_insn_data[i].insn = NULL_RTX;
--- 3258,3270 ----
  		      do_cleanup_cfg |= purge_dead_edges (bb);
  		    }
  
+ 		  SET_BIT (blocks, bb->index);
  #ifdef HAVE_conditional_execution
  		  /* With conditional execution, we cannot back up the
  		     live information so easily, since the conditional
  		     death data structures are not so self-contained.
  		     So record that we've made a modification to this
  		     block and update life information at the end.  */
  
  		  for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
  		    peep2_insn_data[i].insn = NULL_RTX;
*************** peephole2_optimize (dump_file)
*** 3343,3358 ****
    if (do_cleanup_cfg)
      {
        cleanup_cfg (0);
!       update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES);
      }
- #ifdef HAVE_conditional_execution
    else
!     {
!       count_or_remove_death_notes (blocks, 1);
!       update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
!     }
    sbitmap_free (blocks);
- #endif
  }
  #endif /* HAVE_peephole2 */
  
--- 3329,3341 ----
    if (do_cleanup_cfg)
      {
        cleanup_cfg (0);
!       update_life_info (NULL, 0);
!       compute_death_notes (NULL);
      }
    else
!     compute_death_notes (blocks);
!     
    sbitmap_free (blocks);
  }
  #endif /* HAVE_peephole2 */
  
Index: reg-stack.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reg-stack.c,v
retrieving revision 1.119
diff -c -3 -p -r1.119 reg-stack.c
*** reg-stack.c	25 Dec 2002 15:15:10 -0000	1.119
--- reg-stack.c	29 Dec 2002 20:27:29 -0000
*************** static rtx *get_true_reg		PARAMS ((rtx *
*** 244,250 ****
  static int check_asm_stack_operands	PARAMS ((rtx));
  static int get_asm_operand_n_inputs	PARAMS ((rtx));
  static rtx stack_result			PARAMS ((tree));
! static void replace_reg			PARAMS ((rtx *, int));
  static void remove_regno_note		PARAMS ((rtx, enum reg_note,
  						 unsigned int));
  static int get_hard_regnum		PARAMS ((stack, rtx));
--- 244,250 ----
  static int check_asm_stack_operands	PARAMS ((rtx));
  static int get_asm_operand_n_inputs	PARAMS ((rtx));
  static rtx stack_result			PARAMS ((tree));
! static void replace_reg			PARAMS ((rtx *, int, rtx));
  static void remove_regno_note		PARAMS ((rtx, enum reg_note,
  						 unsigned int));
  static int get_hard_regnum		PARAMS ((stack, rtx));
*************** reg_to_stack (first, file)
*** 443,450 ****
       build the CFG and run life analysis.  */
    if (!optimize)
      {
!       count_or_remove_death_notes (NULL, 1);
!       life_analysis (first, file, PROP_DEATH_NOTES);
      }
    mark_dfs_back_edges ();
  
--- 443,450 ----
       build the CFG and run life analysis.  */
    if (!optimize)
      {
!       life_analysis (first, file, 0);
!       compute_death_notes (NULL);
      }
    mark_dfs_back_edges ();
  
*************** stack_result (decl)
*** 837,848 ****
   */
  
  /* Replace REG, which is a pointer to a stack reg RTX, with an RTX for
!    the desired hard REGNO.  */
  
  static void
! replace_reg (reg, regno)
       rtx *reg;
       int regno;
  {
    if (regno < FIRST_STACK_REG || regno > LAST_STACK_REG
        || ! STACK_REG_P (*reg))
--- 837,849 ----
   */
  
  /* Replace REG, which is a pointer to a stack reg RTX, with an RTX for
!    the desired hard REGNO; the REG is part of INSN.  */
  
  static void
! replace_reg (reg, regno, insn)
       rtx *reg;
       int regno;
+      rtx insn;
  {
    if (regno < FIRST_STACK_REG || regno > LAST_STACK_REG
        || ! STACK_REG_P (*reg))
*************** replace_reg (reg, regno)
*** 856,861 ****
--- 857,863 ----
      }
  
    *reg = FP_MODE_REG (regno, GET_MODE (*reg));
+   invalidate_insn_extract (insn);
  }
  
  /* Remove a note of type NOTE, which must be found, for register
*************** move_for_stack_reg (insn, regstack, pat)
*** 1131,1141 ****
        if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
  	abort ();
  
!       replace_reg (psrc, get_hard_regnum (regstack, src));
  
        regstack->reg[++regstack->top] = REGNO (dest);
        SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
!       replace_reg (pdest, FIRST_STACK_REG);
      }
    else if (STACK_REG_P (src))
      {
--- 1133,1143 ----
        if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
  	abort ();
  
!       replace_reg (psrc, get_hard_regnum (regstack, src), insn);
  
        regstack->reg[++regstack->top] = REGNO (dest);
        SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
!       replace_reg (pdest, FIRST_STACK_REG, insn);
      }
    else if (STACK_REG_P (src))
      {
*************** move_for_stack_reg (insn, regstack, pat)
*** 1148,1154 ****
        note = find_regno_note (insn, REG_DEAD, REGNO (src));
        if (note)
  	{
! 	  replace_reg (&XEXP (note, 0), FIRST_STACK_REG);
  	  regstack->top--;
  	  CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
  	}
--- 1150,1156 ----
        note = find_regno_note (insn, REG_DEAD, REGNO (src));
        if (note)
  	{
! 	  replace_reg (&XEXP (note, 0), FIRST_STACK_REG, insn);
  	  regstack->top--;
  	  CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
  	}
*************** move_for_stack_reg (insn, regstack, pat)
*** 1174,1180 ****
  						REG_NOTES (insn));
  	}
  
!       replace_reg (psrc, FIRST_STACK_REG);
      }
    else if (STACK_REG_P (dest))
      {
--- 1176,1182 ----
  						REG_NOTES (insn));
  	}
  
!       replace_reg (psrc, FIRST_STACK_REG, insn);
      }
    else if (STACK_REG_P (dest))
      {
*************** move_for_stack_reg (insn, regstack, pat)
*** 1192,1198 ****
  
        regstack->reg[++regstack->top] = REGNO (dest);
        SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
!       replace_reg (pdest, FIRST_STACK_REG);
      }
    else
      abort ();
--- 1194,1200 ----
  
        regstack->reg[++regstack->top] = REGNO (dest);
        SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
!       replace_reg (pdest, FIRST_STACK_REG, insn);
      }
    else
      abort ();
*************** compare_for_stack_reg (insn, regstack, p
*** 1365,1379 ****
  
    emit_swap_insn (insn, regstack, *src1);
  
!   replace_reg (src1, FIRST_STACK_REG);
  
    if (STACK_REG_P (*src2))
!     replace_reg (src2, get_hard_regnum (regstack, *src2));
  
    if (src1_note)
      {
        pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
!       replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
      }
  
    /* If the second operand dies, handle that.  But if the operands are
--- 1367,1381 ----
  
    emit_swap_insn (insn, regstack, *src1);
  
!   replace_reg (src1, FIRST_STACK_REG, insn);
  
    if (STACK_REG_P (*src2))
!     replace_reg (src2, get_hard_regnum (regstack, *src2), insn);
  
    if (src1_note)
      {
        pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
!       replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG, insn);
      }
  
    /* If the second operand dies, handle that.  But if the operands are
*************** compare_for_stack_reg (insn, regstack, p
*** 1393,1399 ****
  	  && src1_note)
  	{
  	  pop_stack (regstack, REGNO (XEXP (src2_note, 0)));
! 	  replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
  	}
        else
  	{
--- 1395,1401 ----
  	  && src1_note)
  	{
  	  pop_stack (regstack, REGNO (XEXP (src2_note, 0)));
! 	  replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1, insn);
  	}
        else
  	{
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1466,1472 ****
  		      abort ();
  		  }
  		remove_note (insn, note);
! 		replace_reg (dest, LAST_STACK_REG);
  	      }
  	    else
  	      {
--- 1468,1474 ----
  		      abort ();
  		  }
  		remove_note (insn, note);
! 		replace_reg (dest, LAST_STACK_REG, insn);
  	      }
  	    else
  	      {
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1534,1540 ****
  		  SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count);
  		}
  	    }
! 	    replace_reg (dest, FIRST_STACK_REG);
  	    break;
  
  	  case REG:
--- 1536,1542 ----
  		  SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count);
  		}
  	    }
! 	    replace_reg (dest, FIRST_STACK_REG, insn);
  	    break;
  
  	  case REG:
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1562,1577 ****
  	    src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
  
  	    if (STACK_REG_P (*dest))
! 	      replace_reg (dest, FIRST_STACK_REG);
  
  	    if (src1_note)
  	      {
! 		replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
  		regstack->top--;
  		CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
  	      }
  
! 	    replace_reg (src1, FIRST_STACK_REG);
  	    break;
  
  	  case MINUS:
--- 1564,1579 ----
  	    src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
  
  	    if (STACK_REG_P (*dest))
! 	      replace_reg (dest, FIRST_STACK_REG, insn);
  
  	    if (src1_note)
  	      {
! 		replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG, insn);
  		regstack->top--;
  		CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
  	      }
  
! 	    replace_reg (src1, FIRST_STACK_REG, insn);
  	    break;
  
  	  case MINUS:
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1624,1632 ****
  	      }
  
  	    if (STACK_REG_P (*src1))
! 	      replace_reg (src1, get_hard_regnum (regstack, *src1));
  	    if (STACK_REG_P (*src2))
! 	      replace_reg (src2, get_hard_regnum (regstack, *src2));
  
  	    if (src1_note)
  	      {
--- 1626,1634 ----
  	      }
  
  	    if (STACK_REG_P (*src1))
! 	      replace_reg (src1, get_hard_regnum (regstack, *src1), insn);
  	    if (STACK_REG_P (*src2))
! 	      replace_reg (src2, get_hard_regnum (regstack, *src2), insn);
  
  	    if (src1_note)
  	      {
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1641,1654 ****
  		if (REGNO (src1_reg) == regstack->reg[regstack->top])
  		  {
  		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		    replace_reg (dest, get_hard_regnum (regstack, *dest));
  		  }
  		else
  		  {
  		    int regno = get_hard_regnum (regstack, src1_reg);
  
  		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		    replace_reg (dest, regno);
  
  		    regstack->reg[regstack->top - (regno - FIRST_STACK_REG)]
  		      = regstack->reg[regstack->top];
--- 1643,1656 ----
  		if (REGNO (src1_reg) == regstack->reg[regstack->top])
  		  {
  		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		    replace_reg (dest, get_hard_regnum (regstack, *dest), insn);
  		  }
  		else
  		  {
  		    int regno = get_hard_regnum (regstack, src1_reg);
  
  		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		    replace_reg (dest, regno, insn);
  
  		    regstack->reg[regstack->top - (regno - FIRST_STACK_REG)]
  		      = regstack->reg[regstack->top];
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1656,1662 ****
  
  		CLEAR_HARD_REG_BIT (regstack->reg_set,
  				    REGNO (XEXP (src1_note, 0)));
! 		replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
  		regstack->top--;
  	      }
  	    else if (src2_note)
--- 1658,1664 ----
  
  		CLEAR_HARD_REG_BIT (regstack->reg_set,
  				    REGNO (XEXP (src1_note, 0)));
! 		replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG, insn);
  		regstack->top--;
  	      }
  	    else if (src2_note)
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1665,1678 ****
  		if (REGNO (src2_reg) == regstack->reg[regstack->top])
  		  {
  		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		    replace_reg (dest, get_hard_regnum (regstack, *dest));
  		  }
  		else
  		  {
  		    int regno = get_hard_regnum (regstack, src2_reg);
  
  		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		    replace_reg (dest, regno);
  
  		    regstack->reg[regstack->top - (regno - FIRST_STACK_REG)]
  		      = regstack->reg[regstack->top];
--- 1667,1680 ----
  		if (REGNO (src2_reg) == regstack->reg[regstack->top])
  		  {
  		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		    replace_reg (dest, get_hard_regnum (regstack, *dest), insn);
  		  }
  		else
  		  {
  		    int regno = get_hard_regnum (regstack, src2_reg);
  
  		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		    replace_reg (dest, regno, insn);
  
  		    regstack->reg[regstack->top - (regno - FIRST_STACK_REG)]
  		      = regstack->reg[regstack->top];
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1680,1692 ****
  
  		CLEAR_HARD_REG_BIT (regstack->reg_set,
  				    REGNO (XEXP (src2_note, 0)));
! 		replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG);
  		regstack->top--;
  	      }
  	    else
  	      {
  		SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		replace_reg (dest, get_hard_regnum (regstack, *dest));
  	      }
  
  	    /* Keep operand 1 matching with destination.  */
--- 1682,1694 ----
  
  		CLEAR_HARD_REG_BIT (regstack->reg_set,
  				    REGNO (XEXP (src2_note, 0)));
! 		replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG, insn);
  		regstack->top--;
  	      }
  	    else
  	      {
  		SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 		replace_reg (dest, get_hard_regnum (regstack, *dest), insn);
  	      }
  
  	    /* Keep operand 1 matching with destination.  */
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1695,1702 ****
  		&& REGNO (*src1) != REGNO (*dest))
  	     {
  		int tmp = REGNO (*src1);
! 		replace_reg (src1, REGNO (*src2));
! 		replace_reg (src2, tmp);
  	     }
  	    break;
  
--- 1697,1704 ----
  		&& REGNO (*src1) != REGNO (*dest))
  	     {
  		int tmp = REGNO (*src1);
! 		replace_reg (src1, REGNO (*src2), insn);
! 		replace_reg (src2, tmp, insn);
  	     }
  	    break;
  
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1714,1729 ****
  		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
  
  		if (STACK_REG_P (*dest))
! 		  replace_reg (dest, FIRST_STACK_REG);
  
  		if (src1_note)
  		  {
! 		    replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
  		    regstack->top--;
  		    CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
  		  }
  
! 		replace_reg (src1, FIRST_STACK_REG);
  		break;
  
  	      case UNSPEC_SAHF:
--- 1716,1731 ----
  		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
  
  		if (STACK_REG_P (*dest))
! 		  replace_reg (dest, FIRST_STACK_REG, insn);
  
  		if (src1_note)
  		  {
! 		    replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG, insn);
  		    regstack->top--;
  		    CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
  		  }
  
! 		replace_reg (src1, FIRST_STACK_REG, insn);
  		break;
  
  	      case UNSPEC_SAHF:
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1806,1814 ****
  	      src_note[2] = src2_note;
  
  	      if (STACK_REG_P (*src1))
! 		replace_reg (src1, get_hard_regnum (regstack, *src1));
  	      if (STACK_REG_P (*src2))
! 		replace_reg (src2, get_hard_regnum (regstack, *src2));
  
  	      for (i = 1; i <= 2; i++)
  		if (src_note [i])
--- 1808,1816 ----
  	      src_note[2] = src2_note;
  
  	      if (STACK_REG_P (*src1))
! 		replace_reg (src1, get_hard_regnum (regstack, *src1), insn);
  	      if (STACK_REG_P (*src2))
! 		replace_reg (src2, get_hard_regnum (regstack, *src2), insn);
  
  	      for (i = 1; i <= 2; i++)
  		if (src_note [i])
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1835,1841 ****
  	    if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
  	      regstack->reg[++regstack->top] = REGNO (*dest);
  	    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 	    replace_reg (dest, FIRST_STACK_REG);
  	    break;
  
  	  default:
--- 1837,1843 ----
  	    if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
  	      regstack->reg[++regstack->top] = REGNO (*dest);
  	    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
! 	    replace_reg (dest, FIRST_STACK_REG, insn);
  	    break;
  
  	  default:
*************** subst_asm_stack_regs (insn, regstack)
*** 2027,2033 ****
  	if (regnum < 0)
  	  abort ();
  
! 	replace_reg (recog_data.operand_loc[i], regnum);
        }
  
    for (i = 0; i < n_notes; i++)
--- 2029,2035 ----
  	if (regnum < 0)
  	  abort ();
  
! 	replace_reg (recog_data.operand_loc[i], regnum, insn);
        }
  
    for (i = 0; i < n_notes; i++)
*************** subst_asm_stack_regs (insn, regstack)
*** 2038,2044 ****
  	if (regnum < 0)
  	  abort ();
  
! 	replace_reg (note_loc[i], regnum);
        }
  
    for (i = 0; i < n_clobbers; i++)
--- 2040,2046 ----
  	if (regnum < 0)
  	  abort ();
  
! 	replace_reg (note_loc[i], regnum, insn);
        }
  
    for (i = 0; i < n_clobbers; i++)
Index: regmove.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regmove.c,v
retrieving revision 1.136
diff -c -3 -p -r1.136 regmove.c
*** regmove.c	24 Dec 2002 08:30:28 -0000	1.136
--- regmove.c	29 Dec 2002 20:27:33 -0000
*************** optimize_reg_copy_2 (insn, dest, src)
*** 622,628 ****
  	    if (INSN_P (q))
  	      {
  		if (reg_mentioned_p (dest, PATTERN (q)))
! 		  PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
  
  
  	      if (GET_CODE (q) == CALL_INSN)
--- 622,631 ----
  	    if (INSN_P (q))
  	      {
  		if (reg_mentioned_p (dest, PATTERN (q)))
! 		  {
! 		    PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
! 		    invalidate_insn_extract (q);
! 		  }
  
  
  	      if (GET_CODE (q) == CALL_INSN)
*************** copy_src_to_dest (insn, src, dest, old_m
*** 785,791 ****
  	  || ! validate_replace_rtx (src, dest, insn))
  	{
  	  /* We have to restore reg_rtx_no to its old value, lest
! 	     recompute_reg_usage will try to compute the usage of the
  	     new regs, yet reg_n_info is not valid for them.  */
  	  reg_rtx_no = old_num_regs;
  	  return;
--- 788,794 ----
  	  || ! validate_replace_rtx (src, dest, insn))
  	{
  	  /* We have to restore reg_rtx_no to its old value, lest
! 	     compute_reg_usage will try to compute the usage of the
  	     new regs, yet reg_n_info is not valid for them.  */
  	  reg_rtx_no = old_num_regs;
  	  return;
Index: regrename.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regrename.c,v
retrieving revision 1.64
diff -c -3 -p -r1.64 regrename.c
*** regrename.c	16 Dec 2002 18:19:50 -0000	1.64
--- regrename.c	29 Dec 2002 20:27:38 -0000
*************** regrename_optimize ()
*** 364,372 ****
    if (rtl_dump_file)
      fputc ('\n', rtl_dump_file);
  
!   count_or_remove_death_notes (NULL, 1);
!   update_life_info (NULL, UPDATE_LIFE_LOCAL,
! 		    PROP_REG_INFO | PROP_DEATH_NOTES);
  }
  
  static void
--- 364,371 ----
    if (rtl_dump_file)
      fputc ('\n', rtl_dump_file);
  
!   compute_death_notes (NULL);
!   compute_reg_usage (0);
  }
  
  static void
*************** do_replace (chain, reg)
*** 380,385 ****
--- 379,385 ----
        *chain->loc = gen_raw_REG (GET_MODE (*chain->loc), reg);
        if (regno >= FIRST_PSEUDO_REGISTER)
  	ORIGINAL_REGNO (*chain->loc) = regno;
+       invalidate_insn_extract (chain->insn);
        chain = chain->next_use;
      }
  }
*************** copyprop_hardreg_forward_1 (bb, vd)
*** 1753,1758 ****
--- 1753,1761 ----
  	}
  
      did_replacement:
+       /* Invalidate cached insn extract.  */
+       invalidate_insn_extract (insn);
+ 
        /* Clobber call-clobbered registers.  */
        if (GET_CODE (insn) == CALL_INSN)
  	for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
*************** copyprop_hardreg_forward ()
*** 1816,1825 ****
  	 to scan, so we have to do a life update with no initial set of
  	 blocks Just In Case.  */
        delete_noop_moves (get_insns ());
!       update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES,
! 			PROP_DEATH_NOTES
! 			| PROP_SCAN_DEAD_CODE
! 			| PROP_KILL_DEAD_CODE);
      }
  
    free (all_vd);
--- 1819,1826 ----
  	 to scan, so we have to do a life update with no initial set of
  	 blocks Just In Case.  */
        delete_noop_moves (get_insns ());
!       update_life_info (NULL, PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE);
!       compute_death_notes (NULL);
      }
  
    free (all_vd);
Index: reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.369
diff -c -3 -p -r1.369 reload1.c
*** reload1.c	24 Dec 2002 08:30:29 -0000	1.369
--- reload1.c	29 Dec 2002 20:28:06 -0000
*************** reload_as_needed (live_known)
*** 3844,3849 ****
--- 3844,3851 ----
        rtx insn = chain->insn;
        rtx old_next = NEXT_INSN (insn);
  
+       invalidate_insn_extract (insn);
+ 
        /* If we pass a label, copy the offsets from the label information
  	 into the current offsets of each elimination.  */
        if (GET_CODE (insn) == CODE_LABEL)
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.378
diff -c -3 -p -r1.378 rtl.h
*** rtl.h	26 Dec 2002 18:15:56 -0000	1.378
--- rtl.h	29 Dec 2002 20:28:14 -0000
*************** extern rtx set_unique_reg_note		PARAMS (
*** 1571,1576 ****
--- 1571,1621 ----
  
  /* Functions in rtlanal.c */
  
+ /* Information about insn.  */
+ struct varray_head_tag;
+ 
+ struct insn_extract GTY (())
+ {
+   int up_to_date;			/* Should we recount the info here?  */
+   int regs_altered;			/* Should we recount the info just
+ 					   because some pseudos were assigned
+ 					   to hard registers?  */
+ 
+   /* Definitions:  */
+   struct varray_head_tag *registers_set; /* List of set registers.  */
+   struct varray_head_tag *mems_set;	/* List of set memory references.  */
+   int all_mems_altered;			/* By a function call.  */
+   struct varray_head_tag *registers_altered; /* List of registers altered
+ 						(by call or embedded clobber).  */
+   struct varray_head_tag *scratches;	/* Scratches.  */
+   int sets_cc0;				/* Sets cc0?  */
+ 
+   /* Uses:  */
+   struct varray_head_tag *registers_used; /* List of register uses.  */
+   struct varray_head_tag *mems_used;	/* List of used memory references.  */
+   int uses_cc0;				/* Uses cc0?  */
+ 
+   /* Other:  */
+   struct varray_head_tag *subregs;	/* List of subregs for subregs_of_mode.  */
+   int may_trap;				/* May trap?  */
+   int contains_call;			/* Contains any call?  */
+   int contains_impure_call;		/* Contains impure call?  */
+   int contains_volatile_ref;		/* Contains load from volatile memory
+ 					   or volatile asms?  */
+   int not_set;				/* Something else than set.  */
+ };
+ 
+ /* Cached extracts.  */
+ extern struct varray_head_tag *cached_insn_extracts;
+ 
+ /* Placed to register lists to specify details about their origin.  */
+ enum insn_extract_flags
+ {
+   IIF_TOPLEV_CLOBBER = 1,		/* Comes from a toplevel CLOBBER.  */
+   IIF_CALL_CLOBBERED_GLOBAL = 2,	/* A global register clobbered by call.  */
+   IIF_CALL_STACK_USAGE = 4		/* A stack pointer used by CALL.  */
+ };
+ 
  /* Single set is implemented as macro for performance reasons.  */
  #define single_set(I) (INSN_P (I) \
  		       ? (GET_CODE (PATTERN (I)) == SET \
*************** extern int insns_safe_to_move_p         
*** 1648,1653 ****
--- 1693,1706 ----
  extern int loc_mentioned_in_p		PARAMS ((rtx *, rtx));
  extern rtx find_first_parameter_load	PARAMS ((rtx, rtx));
  extern bool keep_with_call_p		PARAMS ((rtx));
+ void initialize_cached_insn_extracts	PARAMS ((void));
+ void initialize_insn_info		PARAMS ((struct insn_extract *));
+ struct insn_extract *extract_insn_info	PARAMS ((rtx));
+ void release_insn_info			PARAMS ((struct insn_extract *));
+ void invalidate_insn_extracts		PARAMS ((void));
+ void invalidate_insn_extracts_regs_altered PARAMS ((void));
+ void invalidate_insn_extract		PARAMS ((rtx));
+ void debug_insn_extract			PARAMS ((struct insn_extract *));
  
  /* flow.c */
  
*************** extern void move_by_pieces		PARAMS ((rtx
*** 2067,2073 ****
  						 unsigned int));
  
  /* In flow.c */
! extern void recompute_reg_usage			PARAMS ((rtx, int));
  extern int initialize_uninitialized_subregs	PARAMS ((void));
  extern void delete_dead_jumptables		PARAMS ((void));
  #ifdef BUFSIZ
--- 2120,2126 ----
  						 unsigned int));
  
  /* In flow.c */
! extern void compute_reg_usage			PARAMS ((int));
  extern int initialize_uninitialized_subregs	PARAMS ((void));
  extern void delete_dead_jumptables		PARAMS ((void));
  #ifdef BUFSIZ
Index: rtlanal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtlanal.c,v
retrieving revision 1.142
diff -c -3 -p -r1.142 rtlanal.c
*** rtlanal.c	24 Dec 2002 08:30:30 -0000	1.142
--- rtlanal.c	29 Dec 2002 20:28:22 -0000
*************** Software Foundation, 59 Temple Place - S
*** 33,38 ****
--- 33,43 ----
  #include "flags.h"
  #include "basic-block.h"
  #include "real.h"
+ #include "function.h"
+ #include "regs.h"
+ 
+ /* Array of cached insn extracts.  */
+ struct varray_head_tag *cached_insn_extracts;
  
  /* Forward declarations */
  static int global_reg_mentioned_p_1 PARAMS ((rtx *, void *));
*************** static int computed_jump_p_1	PARAMS ((rt
*** 42,47 ****
--- 47,66 ----
  static void parms_set 		PARAMS ((rtx, rtx, void *));
  static bool hoist_test_store		PARAMS ((rtx, rtx, regset));
  static void hoist_update_store		PARAMS ((rtx, rtx *, rtx, rtx));
+ static void record_set_regs		PARAMS ((struct insn_extract *,
+ 						 rtx, rtx, int));
+ static void record_set_1		PARAMS ((struct insn_extract *,
+ 						 enum rtx_code,
+ 						 rtx, rtx, rtx, int));
+ static void record_used_regs		PARAMS ((struct insn_extract *,
+ 						 rtx, rtx, rtx, int));
+ static void record_used_reg		PARAMS ((struct insn_extract *,
+ 						 rtx, rtx, int));
+ #ifdef ENABLE_INSNINFO_CHECKING
+ static int insn_extract_elems_hash	PARAMS ((varray_type));
+ static int insn_info_hash		PARAMS ((struct insn_extract *));
+ #endif
+ static void debug_insn_extract_elems	PARAMS ((const char *, varray_type));
  
  /* Bit flags that specify the machine subtype we are compiling for.
     Bits are tested using macros TARGET_... defined in the tm.h file
*************** hoist_insn_to_edge (insn, e, val, new)
*** 3632,3634 ****
--- 3651,4576 ----
    end_sequence ();
    return new_insn;
  }
+ 
+ /* Initialize structure for insn info.  */
+ void
+ initialize_insn_info (insn_info)
+      struct insn_extract *insn_info;
+ {
+   VARRAY_IE_ELEM_INIT (insn_info->registers_set, 1, "registers_set");
+   VARRAY_IE_ELEM_INIT (insn_info->mems_set, 1, "mems_set");
+   VARRAY_IE_ELEM_INIT (insn_info->registers_altered, 3, "registers_altered");
+   VARRAY_IE_ELEM_INIT (insn_info->scratches, 1, "scratches");
+   VARRAY_IE_ELEM_INIT (insn_info->registers_used, 3, "registers_used");
+   VARRAY_IE_ELEM_INIT (insn_info->mems_used, 3, "mems_used");
+ #ifdef CANNOT_CHANGE_MODE_CLASS
+   VARRAY_IE_ELEM_INIT (insn_info->subregs, 1, "subregs");
+ #endif
+ }
+ 
+ /* Release structure for insn info.  */
+ void
+ release_insn_info (insn_info)
+      struct insn_extract *insn_info;
+ {
+   VARRAY_FREE (insn_info->registers_set);
+   VARRAY_FREE (insn_info->mems_set);
+   VARRAY_FREE (insn_info->registers_altered);
+   VARRAY_FREE (insn_info->scratches);
+   VARRAY_FREE (insn_info->registers_used);
+   VARRAY_FREE (insn_info->mems_used);
+ #ifdef CANNOT_CHANGE_MODE_CLASS
+   VARRAY_FREE (insn_info->subregs);
+ #endif
+ }
+ 
+ /* Initialize array of cached insn extracts.  */
+ void
+ initialize_cached_insn_extracts ()
+ {
+   unsigned i;
+   struct insn_extract *insn_info;
+ 
+   if (cached_insn_extracts)
+     {
+       for (i = 0; i < VARRAY_SIZE (cached_insn_extracts); i++)
+ 	{
+ 	  insn_info = VARRAY_IE (cached_insn_extracts, i);
+ 	  if (!insn_info)
+ 	    continue;
+ 	  release_insn_info (insn_info);
+ 	}
+       VARRAY_FREE (cached_insn_extracts);
+     }
+ 
+   VARRAY_IE_INIT (cached_insn_extracts,
+ 		  get_max_uid () + 1,
+ 		  "cached_insn_extracts");
+ }
+ 
+ #ifdef ENABLE_INSNINFO_CHECKING
+ /* Returns hash of insn_extract_elems LIST.  */
+ static int
+ insn_extract_elems_hash (list)
+      varray_type list;
+ {
+   unsigned i;
+   int ret = VARRAY_ACTIVE_SIZE (list);
+   struct insn_extract_elem elem;
+ 
+   for (i = 0; i < VARRAY_ACTIVE_SIZE (list); i++)
+     {
+       elem = VARRAY_IE_ELEM (list, i);
+ 
+       ret ^= elem.flags;
+       ret ^= elem.regno_first << 4;
+       ret ^= elem.regno_last << 8;
+       if (elem.cond)
+ 	ret ^= 1234;
+       if (elem.elem)
+ 	{
+ 	  switch (GET_CODE (elem.elem))
+ 	    {
+ 	    case REG:
+ 	      ret ^= REGNO (elem.elem) << 16;
+ 	      break;
+ 
+ 	    case MEM:
+ 	      ret ^= 8754;
+ 	      break;
+ 
+ 	    case SUBREG:
+ 	      ret ^= REGNO (SUBREG_REG (elem.elem)) << 16;
+ 	      break;
+ 
+ 	    default:
+ 	      ret ^= 4321;
+ 	    }
+ 	}
+       ret *= 13;
+     }
+   return ret;
+ }
+ 
+ /* Returns hash of INSN_INFO for checking purposes.  */
+ static int
+ insn_info_hash (insn_info)
+      struct insn_extract *insn_info;
+ {
+   int ret = 0;
+ 
+   ret ^= insn_extract_elems_hash (insn_info->registers_set);
+   ret *= 13;
+   ret ^= insn_extract_elems_hash (insn_info->mems_set);
+   ret *= 13;
+   ret ^= insn_extract_elems_hash (insn_info->registers_altered);
+   ret *= 13;
+   ret ^= insn_extract_elems_hash (insn_info->scratches);
+   ret *= 13;
+   ret ^= insn_extract_elems_hash (insn_info->registers_used);
+   ret *= 13;
+   ret ^= insn_extract_elems_hash (insn_info->mems_used);
+   ret *= 13;
+ #ifdef CANNOT_CHANGE_MODE_CLASS
+   ret ^= insn_extract_elems_hash (insn_info->subregs);
+   ret *= 13;
+ #endif
+   ret ^= insn_info->all_mems_altered;
+   ret ^= insn_info->sets_cc0 << 1;
+   ret ^= insn_info->uses_cc0 << 2;
+   ret ^= insn_info->may_trap << 3;
+   ret ^= insn_info->contains_impure_call << 4;
+   ret ^= insn_info->contains_volatile_ref << 5;
+   ret ^= insn_info->contains_call << 6;
+   ret ^= insn_info->not_set << 30;
+ 
+   return ret;
+ }
+ #endif
+ 
+ /* Debug dump of LIST of insn_extract_elems.  */
+ static void
+ debug_insn_extract_elems (name, list)
+      const char *name;
+      varray_type list;
+ {
+   unsigned i;
+   struct insn_extract_elem elem;
+ 
+   if (VARRAY_ACTIVE_SIZE (list))
+     {
+       fprintf(stderr, "\n%s:\n", name);
+       for (i = 0; i < VARRAY_ACTIVE_SIZE (list); i++)
+ 	{
+ 	  elem = VARRAY_IE_ELEM (list, i);
+ 	  fprintf (stderr, " %d: (%d -- %d)", i, elem.regno_first, elem.regno_last);
+ 	  if (elem.flags & IIF_TOPLEV_CLOBBER)
+ 	    fprintf(stderr, " toplev clobber;");
+ 	  if (elem.flags & IIF_CALL_CLOBBERED_GLOBAL)
+ 	    fprintf(stderr, " call clobbered global;");
+ 	  if (elem.flags & IIF_CALL_STACK_USAGE)
+ 	    fprintf(stderr, " stack used by call;");
+ 	  fprintf (stderr, "\n");
+ 	  if (elem.cond)
+ 	    {
+ 	      fprintf (stderr, " condition:");
+ 	      debug_rtx (elem.cond);
+ 	    }
+ 	  if (elem.elem)
+ 	    {
+ 	      fprintf (stderr, " elem:");
+ 	      debug_rtx (elem.elem);
+ 	    }
+ 	}
+     }
+ }
+ 
+ /* Debug dump of INSN_INFO.  */
+ void
+ debug_insn_extract (insn_info)
+      struct insn_extract *insn_info;
+ {
+   if (insn_info->up_to_date)
+     fprintf(stderr, "up to date, ");
+   if (insn_info->all_mems_altered)
+     fprintf(stderr, "alters all mems, ");
+   if (insn_info->sets_cc0)
+     fprintf(stderr, "sets cc0, ");
+   if (insn_info->uses_cc0)
+     fprintf(stderr, "uses cc0, ");
+   if (insn_info->may_trap)
+     fprintf(stderr, "may trap, ");
+   if (insn_info->contains_impure_call)
+     fprintf(stderr, "contains impure call, ");
+   if (insn_info->contains_call)
+     fprintf(stderr, "contains call, ");
+   if (insn_info->contains_volatile_ref)
+     fprintf(stderr, "contains volatile reg, ");
+   if (insn_info->not_set)
+     fprintf(stderr, "is not set, ");
+   debug_insn_extract_elems ("registers set", insn_info->registers_set);
+   debug_insn_extract_elems ("mems set", insn_info->mems_set);
+   debug_insn_extract_elems ("registers altered", insn_info->registers_altered);
+   debug_insn_extract_elems ("scratches", insn_info->scratches);
+   debug_insn_extract_elems ("registers used", insn_info->registers_used);
+   debug_insn_extract_elems ("mems used", insn_info->mems_used);
+ #ifdef CANNOT_CHANGE_MODE_CLASS
+   debug_insn_extract_elems ("subregs", insn_info->subregs);
+ #endif
+ }
+ 
+ /* Invalidate all insn extracts.  */
+ void
+ invalidate_insn_extracts ()
+ {
+   unsigned i;
+   struct insn_extract *insn_info;
+ 
+   if (!cached_insn_extracts)
+     return;
+ 
+   for (i = 0; i < VARRAY_SIZE (cached_insn_extracts); i++)
+     {
+       insn_info = VARRAY_IE (cached_insn_extracts, i);
+       if (insn_info)
+ 	insn_info->up_to_date = 0;
+     }
+ }
+ 
+ /* Invalidate all insn extracts due to pseudos assigned to hard regs.  */
+ void
+ invalidate_insn_extracts_regs_altered ()
+ {
+   unsigned i;
+   struct insn_extract *insn_info;
+ 
+   if (!cached_insn_extracts)
+     return;
+ 
+   for (i = 0; i < VARRAY_SIZE (cached_insn_extracts); i++)
+     {
+       insn_info = VARRAY_IE (cached_insn_extracts, i);
+       if (insn_info)
+ 	insn_info->regs_altered = 1;
+     }
+ }
+ 
+ /* Invalidate INSN extract.  */
+ void
+ invalidate_insn_extract (insn)
+      rtx insn;
+ {
+   unsigned uid = INSN_UID (insn);
+   struct insn_extract *insn_info;
+ 
+   if (!cached_insn_extracts)
+     return;
+ 
+   if (uid >= VARRAY_SIZE (cached_insn_extracts))
+     return;
+ 
+   insn_info = VARRAY_IE (cached_insn_extracts, uid);
+   if (insn_info)
+     insn_info->up_to_date = 0;
+ }
+ 
+ /* Extract various information about INSN.  */
+ struct insn_extract *
+ extract_insn_info (insn)
+      rtx insn;
+ {
+   rtx note, cond;
+   int i;
+   int iif = 0;
+   struct insn_extract *insn_info;
+   int do_not_recount_all = 0;
+ #ifdef ENABLE_INSNINFO_CHECKING
+   int was_cached = 0;
+   int hash = 0;
+ #endif
+ 
+   /* Have we already computed the info?  */
+   if ((unsigned) INSN_UID (insn) >= VARRAY_SIZE (cached_insn_extracts))
+     VARRAY_GROW (cached_insn_extracts, INSN_UID (insn) + 1);
+   if (!VARRAY_IE (cached_insn_extracts, INSN_UID (insn)))
+     {
+       insn_info = xmalloc (sizeof(struct insn_extract));
+       initialize_insn_info (insn_info);
+       insn_info->up_to_date = 0;
+       VARRAY_IE (cached_insn_extracts, INSN_UID (insn)) = insn_info;
+     }
+   else
+     insn_info = VARRAY_IE (cached_insn_extracts, INSN_UID (insn));
+ 
+   if (insn_info->up_to_date)
+     {
+       if (insn_info->regs_altered)
+ 	do_not_recount_all = 1;
+       else
+ 	{
+ #ifdef ENABLE_INSNINFO_CHECKING
+ 	  was_cached = 1;
+ 	  hash = insn_info_hash (insn_info);
+ #else
+ 	  return insn_info;
+ #endif
+ 	}
+     }
+ 
+   insn_info->up_to_date = 1;
+   insn_info->regs_altered = 0;
+ 
+   /* Sets.  */
+   VARRAY_POP_ALL (insn_info->registers_set);
+   VARRAY_POP_ALL (insn_info->mems_set);
+   insn_info->all_mems_altered = 0;
+   VARRAY_POP_ALL (insn_info->registers_altered);
+   VARRAY_POP_ALL (insn_info->scratches);
+   insn_info->sets_cc0 = 0;
+ 
+   /* Uses:  */
+   VARRAY_POP_ALL (insn_info->registers_used);
+   VARRAY_POP_ALL (insn_info->mems_used);
+   insn_info->uses_cc0 = 0;
+ 
+   /* Special effects:  */
+ #ifdef CANNOT_CHANGE_MODE_CLASS
+   VARRAY_POP_ALL (insn_info->subregs);
+ #endif
+   if (!do_not_recount_all)
+     {
+       insn_info->may_trap = 0;
+       insn_info->contains_volatile_ref = 0;
+     }
+   insn_info->contains_call = 0;
+   insn_info->contains_impure_call = 0;
+   insn_info->not_set = 0;
+ 
+   if (! INSN_P (insn))
+     {
+       insn_info->not_set = 1;
+ #ifdef ENABLE_INSNINFO_CHECKING
+       if (was_cached && hash != insn_info_hash (insn_info))
+ 	abort ();
+ #endif
+       return insn_info;
+     }
+  
+   if (!do_not_recount_all)
+     {
+       insn_info->may_trap = may_trap_p (PATTERN (insn));
+       insn_info->contains_volatile_ref = volatile_refs_p (PATTERN (insn));
+     }
+ #ifdef ENABLE_INSNINFO_CHECKING
+   else
+     {
+       if (insn_info->may_trap != may_trap_p (PATTERN (insn)))
+ 	abort ();
+ 
+       if (insn_info->contains_volatile_ref != volatile_refs_p (PATTERN (insn)))
+ 	abort ();
+     }
+ #endif
+ 
+   switch (GET_CODE (insn))
+     {
+     case INSN:
+     case CALL_INSN:
+       break;
+     case CLOBBER:
+       iif |= IIF_TOPLEV_CLOBBER;
+       /* Fallthru.  */
+     default:
+       insn_info->not_set = 1;
+     }
+   switch (GET_CODE (PATTERN (insn)))
+     {
+     case SET:
+     case CALL:
+     case PARALLEL:
+       break;
+     default:
+       insn_info->not_set = 1;
+     }
+ 
+   /* Any regs live at the time of a call instruction must not go
+      in a register clobbered by calls.  Find all regs now live and
+      record this for them.  */
+ 
+   /* Record sets.  */
+   record_set_regs (insn_info, PATTERN (insn), insn, iif);
+ 
+   if (GET_CODE (insn) == CALL_INSN)
+     {
+       insn_info->contains_call = 1;
+ 
+       cond = NULL_RTX;
+       if (GET_CODE (PATTERN (insn)) == COND_EXEC)
+ 	cond = COND_EXEC_TEST (PATTERN (insn));
+ 
+       /* Non-constant calls clobber memory, constant calls do not
+ 	 clobber memory, though they may clobber outgoing arguments
+ 	 on the stack.  */
+       if (! CONST_OR_PURE_CALL_P (insn))
+ 	{
+ 	  insn_info->all_mems_altered = 1;
+ 	  insn_info->contains_impure_call = 1;
+ 	}
+ 
+       /* There may be extra registers to be clobbered.  */
+       for (note = CALL_INSN_FUNCTION_USAGE (insn);
+ 	   note;
+ 	   note = XEXP (note, 1))
+ 	if (GET_CODE (XEXP (note, 0)) == CLOBBER)
+ 	  record_set_1 (insn_info, CLOBBER, XEXP (XEXP (note, 0), 0),
+ 			cond, insn, iif);
+ 
+       /* Calls change all call-used and global registers.  */
+       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ 	if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+ 	  record_set_1 (insn_info, CLOBBER, regno_reg_rtx[i], cond, insn,
+ 			iif | IIF_CALL_CLOBBERED_GLOBAL);
+     }
+ 
+   /* Record uses.  */
+   record_used_regs (insn_info, PATTERN (insn), NULL_RTX, insn, iif);
+ 
+   if (GET_CODE (insn) == CALL_INSN)
+     {
+       cond = NULL_RTX;
+       if (GET_CODE (PATTERN (insn)) == COND_EXEC)
+ 	cond = COND_EXEC_TEST (PATTERN (insn));
+ 
+       /* Calls use their arguments.  */
+       for (note = CALL_INSN_FUNCTION_USAGE (insn);
+ 	   note;
+ 	   note = XEXP (note, 1))
+ 	if (GET_CODE (XEXP (note, 0)) == USE)
+ 	  record_used_regs (insn_info, XEXP (XEXP (note, 0), 0),
+ 			    cond, insn, iif);
+ 
+       /* The stack ptr is used (honorarily) by a CALL insn.  */
+       record_used_regs (insn_info, stack_pointer_rtx, cond, insn,
+ 			iif | IIF_CALL_STACK_USAGE);
+ 
+       /* Calls may also reference any of the global registers,
+ 	 so they are made live.  */
+       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ 	if (global_regs[i])
+ 	  record_used_reg (insn_info, regno_reg_rtx[i], cond, iif);
+     }
+ 
+ #ifdef ENABLE_INSNINFO_CHECKING
+   if (was_cached && hash != insn_info_hash (insn_info))
+     abort ();
+ #endif
+   return insn_info;
+ }
+ 
+ /* Record the registers that are set within X
+ 
+    If INSN is nonzero, it is the insn being processed.  */
+ 
+ static void
+ record_set_regs (insn_info, x, insn, iif)
+      struct insn_extract *insn_info;
+      rtx x, insn;
+      int iif;
+ {
+   rtx cond = NULL_RTX;
+   rtx link;
+   enum rtx_code code;
+ 
+   if (insn)
+     for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+       {
+ 	if (REG_NOTE_KIND (link) == REG_INC)
+ 	  record_set_1 (insn_info, SET, XEXP (link, 0),
+ 			(GET_CODE (x) == COND_EXEC
+ 			 ? COND_EXEC_TEST (x) : NULL_RTX),
+ 			insn, iif);
+       }
+ retry:
+   switch (code = GET_CODE (x))
+     {
+     case SET:
+     case CLOBBER:
+       record_set_1 (insn_info, code, SET_DEST (x), cond, insn, iif);
+       return;
+ 
+     case COND_EXEC:
+       cond = COND_EXEC_TEST (x);
+       x = COND_EXEC_CODE (x);
+       goto retry;
+ 
+     case PARALLEL:
+       {
+ 	int i;
+ 
+ 	for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ 	  {
+ 	    rtx sub = XVECEXP (x, 0, i);
+ 	    switch (code = GET_CODE (sub))
+ 	      {
+ 	      case COND_EXEC:
+ 		if (cond != NULL_RTX)
+ 		  abort ();
+ 
+ 		cond = COND_EXEC_TEST (sub);
+ 		sub = COND_EXEC_CODE (sub);
+ 		if (GET_CODE (sub) != SET && GET_CODE (sub) != CLOBBER)
+ 		  break;
+ 		/* Fall through.  */
+ 
+ 	      case SET:
+ 	      case CLOBBER:
+ 		record_set_1 (insn_info, code, SET_DEST (sub), cond, insn, iif);
+ 		break;
+ 
+ 	      default:
+ 		break;
+ 	      }
+ 	  }
+ 	break;
+       }
+ 
+     default:
+       break;
+     }
+ }
+ 
+ /* Process a single set, which appears in INSN.  REG (which may not
+    actually be a REG, it may also be a SUBREG, PARALLEL, etc.) is
+    being set using the CODE (which may be SET, CLOBBER, or COND_EXEC).
+    If the set is conditional (because it appear in a COND_EXEC), COND
+    will be the condition.  IIF are the flags containing some special
+    info about usage of the REG in the INSN.  */
+ 
+ static void
+ record_set_1 (insn_info, code, reg, cond, insn, iif)
+      struct insn_extract *insn_info;
+      enum rtx_code code;
+      rtx reg, cond, insn;
+      int iif;
+ {
+   int regno_first = -1, regno_last = -2;
+   int i;
+   struct insn_extract_elem elem;
+ 
+   /* Modifying just one hardware register of a multi-reg value or just a
+      byte field of a register does not mean the value from before this insn
+      is now dead.  Of course, if it was dead after it's unused now.  */
+ 
+   switch (GET_CODE (reg))
+     {
+     case PARALLEL:
+       /* Some targets place small structures in registers for return values of
+ 	 functions.  We have to detect this case specially here to get correct
+ 	 flow information.  */
+       for (i = XVECLEN (reg, 0) - 1; i >= 0; i--)
+ 	if (XEXP (XVECEXP (reg, 0, i), 0) != 0)
+ 	  record_set_1 (insn_info, code, XEXP (XVECEXP (reg, 0, i), 0),
+ 			cond, insn, iif);
+       return;
+ 
+     case ZERO_EXTRACT:
+     case SIGN_EXTRACT:
+     case STRICT_LOW_PART:
+       /* ??? Assumes STRICT_LOW_PART not used on multi-word registers.  */
+       do
+ 	reg = XEXP (reg, 0);
+       while (GET_CODE (reg) == SUBREG
+ 	     || GET_CODE (reg) == ZERO_EXTRACT
+ 	     || GET_CODE (reg) == SIGN_EXTRACT
+ 	     || GET_CODE (reg) == STRICT_LOW_PART);
+       if (GET_CODE (reg) == MEM)
+ 	break;
+       /* Fall through.  */
+ 
+     case REG:
+       regno_last = regno_first = REGNO (reg);
+       if (regno_first < FIRST_PSEUDO_REGISTER)
+ 	regno_last += HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1;
+       break;
+ 
+     case SUBREG:
+       if (GET_CODE (SUBREG_REG (reg)) == REG)
+ 	{
+ 	  enum machine_mode outer_mode = GET_MODE (reg);
+ 	  enum machine_mode inner_mode = GET_MODE (SUBREG_REG (reg));
+ 
+ 	  /* Identify the range of registers affected.  This is moderately
+ 	     tricky for hard registers.  See alter_subreg.  */
+ 
+ 	  regno_last = regno_first = REGNO (SUBREG_REG (reg));
+ 	  if (regno_first < FIRST_PSEUDO_REGISTER)
+ 	    {
+ 	      regno_first += subreg_regno_offset (regno_first, inner_mode,
+ 						  SUBREG_BYTE (reg),
+ 						  outer_mode);
+ 	      regno_last = (regno_first
+ 			    + HARD_REGNO_NREGS (regno_first, outer_mode) - 1);
+ 
+ 	      /* Since we've just adjusted the register number ranges, make
+ 		 sure REG matches.  Otherwise some_was_live will be clear
+ 		 when it shouldn't have been, and we'll create incorrect
+ 		 REG_UNUSED notes.  */
+ 	      reg = gen_rtx_REG (outer_mode, regno_first);
+ 	    }
+ 	  else
+ 	    reg = SUBREG_REG (reg);
+ 	}
+       else
+ 	reg = SUBREG_REG (reg);
+       break;
+ 
+     case CC0:
+       insn_info->sets_cc0 = 1;
+       break;
+ 
+     default:
+       break;
+     }
+ 
+   switch (GET_CODE (reg))
+     {
+     case REG:
+       elem.flags = iif;
+       elem.cond = cond;
+       elem.elem = reg;
+       elem.regno_first = regno_first;
+       elem.regno_last = regno_last;
+ 
+       if (code == SET)
+ 	VARRAY_PUSH_IE_ELEM (insn_info->registers_set, elem);
+       else
+ 	VARRAY_PUSH_IE_ELEM (insn_info->registers_altered, elem);
+       break;
+ 
+     case MEM:
+       elem.flags = iif;
+       elem.cond = cond;
+       elem.elem = reg;
+       elem.regno_first = -1;
+       elem.regno_last = -2;
+       VARRAY_PUSH_IE_ELEM (insn_info->mems_set, elem);
+       break;
+  
+     case SCRATCH:
+       elem.flags = iif;
+       elem.cond = cond;
+       elem.elem = reg;
+       elem.regno_first = -1;
+       elem.regno_last = -2;
+       VARRAY_PUSH_IE_ELEM (insn_info->scratches, elem);
+       break;
+ 
+     default:;
+     }
+ }
+ 
+ /* Record usage of REG inside INSN_INFO.  */
+ 
+ static void
+ record_used_reg (insn_info, reg, cond, iif)
+      struct insn_extract *insn_info;
+      rtx reg;
+      rtx cond;
+      int iif;
+ {
+   int regno_first, regno_last;
+   struct insn_extract_elem elem;
+ 
+   regno_last = regno_first = REGNO (reg);
+   if (regno_first < FIRST_PSEUDO_REGISTER)
+     regno_last += HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1;
+ 
+   elem.flags = iif;
+   elem.cond = cond;
+   elem.elem = reg;
+   elem.regno_first = regno_first;
+   elem.regno_last = regno_last;
+   VARRAY_PUSH_IE_ELEM (insn_info->registers_used, elem);
+ }
+ 
+ /* Record registers used in INSN inside INSN_INFO.  */
+ 
+ static void
+ record_used_regs (insn_info, x, cond, insn, iif)
+      struct insn_extract *insn_info;
+      rtx x, cond, insn;
+      int iif;
+ {
+   RTX_CODE code;
+   int regno;
+   const char *fmt;
+   int i;
+   struct insn_extract_elem elem;
+ 
+  retry:
+   if (!x)
+     return;
+   code = GET_CODE (x);
+   switch (code)
+     {
+     case LABEL_REF:
+     case SYMBOL_REF:
+     case CONST_INT:
+     case CONST:
+     case CONST_DOUBLE:
+     case CONST_VECTOR:
+     case PC:
+     case ADDR_VEC:
+     case ADDR_DIFF_VEC:
+       return;
+ 
+ #ifdef HAVE_cc0
+     case CC0:
+       insn_info->uses_cc0 = 1;
+       return;
+ #endif
+ 
+     case CLOBBER:
+       /* If we are clobbering a MEM, mark any registers inside the address
+ 	 as being used.  */
+       if (GET_CODE (XEXP (x, 0)) == MEM)
+ 	record_used_regs (insn_info, XEXP (XEXP (x, 0), 0), cond, insn, iif);
+       return;
+ 
+     case MEM:
+       elem.flags = iif;
+       elem.cond = cond;
+       elem.elem = x;
+       elem.regno_first = -1;
+       elem.regno_last = -2;
+       VARRAY_PUSH_IE_ELEM (insn_info->mems_used, elem);
+       break;
+ 
+     case SUBREG:
+ #ifdef CANNOT_CHANGE_MODE_CLASS
+       if (GET_CODE (SUBREG_REG (x)) == REG
+ 	  && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
+ 	{
+ 	  elem.flags = iif;
+ 	  elem.cond = cond;
+ 	  elem.elem = x;
+ 	  elem.regno_first = -1;
+ 	  elem.regno_last = -2;
+ 	  VARRAY_PUSH_IE_ELEM (insn_info->subregs, elem);
+ 	}
+ #endif
+ 
+       /* While we're here, optimize this case.  */
+       x = SUBREG_REG (x);
+       if (GET_CODE (x) != REG)
+ 	goto retry;
+       /* Fall through.  */
+ 
+     case REG:
+       /* See a register other than being set => mark it as needed.  */
+       record_used_reg (insn_info, x, cond, iif);
+       return;
+ 
+     case SET:
+       {
+ 	rtx testreg = SET_DEST (x);
+ 	int mark_dest = 0;
+ 
+ 	/* If storing into MEM, don't show it as being used.  But do
+ 	   show the address as being used.  */
+ 	if (GET_CODE (testreg) == MEM)
+ 	  {
+ 	    record_used_regs (insn_info, XEXP (testreg, 0), cond, insn, iif);
+ 	    record_used_regs (insn_info, SET_SRC (x), cond, insn, iif);
+ 	    return;
+ 	  }
+ 
+ 	/* Storing in STRICT_LOW_PART is like storing in a reg
+ 	   in that this SET might be dead, so ignore it in TESTREG.
+ 	   but in some other ways it is like using the reg.
+ 
+ 	   Storing in a SUBREG or a bit field is like storing the entire
+ 	   register in that if the register's value is not used
+ 	   then this SET is not needed.  */
+ 	while (GET_CODE (testreg) == STRICT_LOW_PART
+ 	       || GET_CODE (testreg) == ZERO_EXTRACT
+ 	       || GET_CODE (testreg) == SIGN_EXTRACT
+ 	       || GET_CODE (testreg) == SUBREG)
+ 	  {
+ #ifdef CANNOT_CHANGE_MODE_CLASS
+ 	    if (GET_CODE (testreg) == SUBREG
+ 		&& GET_CODE (SUBREG_REG (testreg)) == REG
+ 		&& REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER)
+ 	      {
+ 		elem.flags = iif;
+ 		elem.cond = cond;
+ 		elem.elem = testreg;
+ 		elem.regno_first = -1;
+ 		elem.regno_last = -2;
+ 		VARRAY_PUSH_IE_ELEM (insn_info->subregs, elem);
+ 	      }
+ #endif
+ 
+ 	    /* Modifying a single register in an alternate mode
+ 	       does not use any of the old value.  But these other
+ 	       ways of storing in a register do use the old value.  */
+ 	    if (GET_CODE (testreg) == SUBREG
+ 		&& !((REG_BYTES (SUBREG_REG (testreg))
+ 		      + UNITS_PER_WORD - 1) / UNITS_PER_WORD
+ 		     > (REG_BYTES (testreg)
+ 			+ UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+ 	      ;
+ 	    else
+ 	      mark_dest = 1;
+ 
+ 	    testreg = XEXP (testreg, 0);
+ 	  }
+ 
+ 	/* If this is a store into a register or group of registers,
+ 	   recursively scan the value being stored.  */
+ 
+ 	if ((GET_CODE (testreg) == PARALLEL
+ 	     && GET_MODE (testreg) == BLKmode)
+ 	    || (GET_CODE (testreg) == REG
+ 		&& (regno = REGNO (testreg),
+ 		    ! (regno == FRAME_POINTER_REGNUM
+ 		       && (! reload_completed || frame_pointer_needed)))
+ #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ 		&& ! (regno == HARD_FRAME_POINTER_REGNUM
+ 		      && (! reload_completed || frame_pointer_needed))
+ #endif
+ #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ 		&& ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+ #endif
+ 		))
+ 	  {
+ 	    if (mark_dest)
+ 	      record_used_regs (insn_info, SET_DEST (x), cond, insn, iif);
+ 	    record_used_regs (insn_info, SET_SRC (x), cond, insn, iif);
+ 	    return;
+ 	  }
+       }
+       break;
+ 
+     case ASM_OPERANDS:
+     case UNSPEC_VOLATILE:
+     case TRAP_IF:
+     case ASM_INPUT:
+       {
+ 	/* Traditional and volatile asm instructions must be considered to use
+ 	   and clobber all hard registers, all pseudo-registers and all of
+ 	   memory.  So must TRAP_IF and UNSPEC_VOLATILE operations.
+ 
+ 	   Consider for instance a volatile asm that changes the fpu rounding
+ 	   mode.  An insn should not be moved across this even if it only uses
+ 	   pseudo-regs because it might give an incorrectly rounded result.
+ 
+ 	   ?!? Unfortunately, marking all hard registers as live causes massive
+ 	   problems for the register allocator and marking all pseudos as live
+ 	   creates mountains of uninitialized variable warnings.
+ 
+ 	   So for now, just clear the memory set list and mark any regs
+ 	   we can find in ASM_OPERANDS as used.  */
+ 	if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
+ 	  insn_info->all_mems_altered = 1;
+ 
+ 	/* For all ASM_OPERANDS, we must traverse the vector of input operands.
+ 	   We can not just fall through here since then we would be confused
+ 	   by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate
+ 	   traditional asms unlike their normal usage.  */
+ 	if (code == ASM_OPERANDS)
+ 	  {
+ 	    int j;
+ 
+ 	    for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
+ 	      record_used_regs (insn_info, ASM_OPERANDS_INPUT (x, j),
+ 				cond, insn, iif);
+ 	  }
+ 	break;
+       }
+ 
+     case COND_EXEC:
+       if (cond != NULL_RTX)
+ 	abort ();
+ 
+       record_used_regs (insn_info, COND_EXEC_TEST (x), NULL_RTX, insn, iif);
+ 
+       cond = COND_EXEC_TEST (x);
+       x = COND_EXEC_CODE (x);
+       goto retry;
+ 
+     case PHI:
+       /* We _do_not_ want to scan operands of phi nodes.  Operands of
+ 	 a phi function are evaluated only when control reaches this
+ 	 block along a particular edge.  Therefore, regs that appear
+ 	 as arguments to phi should not be added to the global live at
+ 	 start.  */
+       return;
+ 
+     default:
+       break;
+     }
+ 
+   /* Recursively scan the operands of this expression.  */
+   fmt = GET_RTX_FORMAT (code);
+   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+     {
+       if (fmt[i] == 'e')
+ 	{
+ 	  /* Tail recursive case: save a function call level.  */
+ 	  if (i == 0)
+ 	    {
+ 	      x = XEXP (x, 0);
+ 	      goto retry;
+ 	    }
+ 	  record_used_regs (insn_info, XEXP (x, i), cond, insn, iif);
+ 	}
+       else if (fmt[i] == 'E')
+ 	{
+ 	  int j;
+ 	  for (j = 0; j < XVECLEN (x, i); j++)
+ 	    record_used_regs (insn_info, XVECEXP (x, i, j), cond, insn, iif);
+ 	}
+     }
+ }
+ 
Index: sched-rgn.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-rgn.c,v
retrieving revision 1.54
diff -c -3 -p -r1.54 sched-rgn.c
*** sched-rgn.c	24 Dec 2002 08:30:30 -0000	1.54
--- sched-rgn.c	29 Dec 2002 20:28:31 -0000
*************** schedule_insns (dump_file)
*** 3028,3043 ****
  	RESET_BIT (large_region_blocks, rgn_bb_table[RGN_BLOCKS (rgn)]);
        }
  
!   /* Don't update reg info after reload, since that affects
!      regs_ever_live, which should not change after reload.  */
!   update_life_info (blocks, UPDATE_LIFE_LOCAL,
! 		    (reload_completed ? PROP_DEATH_NOTES
! 		     : PROP_DEATH_NOTES | PROP_REG_INFO));
    if (any_large_regions)
      {
!       update_life_info (large_region_blocks, UPDATE_LIFE_GLOBAL,
! 			PROP_DEATH_NOTES | PROP_REG_INFO);
      }
  
    if (CHECK_DEAD_NOTES)
      {
--- 3028,3045 ----
  	RESET_BIT (large_region_blocks, rgn_bb_table[RGN_BLOCKS (rgn)]);
        }
  
!   compute_death_notes (blocks);
! 
    if (any_large_regions)
      {
!       update_life_info (large_region_blocks, 0);
!       compute_death_notes (large_region_blocks);
      }
+ 
+   /* Don't update reg info after reload, since that affects
+      regs_ever_live, which should not change after reload.  */
+   if (!reload_completed)
+     compute_reg_usage (0);
  
    if (CHECK_DEAD_NOTES)
      {
Index: ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ssa.c,v
retrieving revision 1.58
diff -c -3 -p -r1.58 ssa.c
*** ssa.c	24 Dec 2002 08:30:31 -0000	1.58
--- ssa.c	29 Dec 2002 20:28:36 -0000
*************** convert_from_ssa ()
*** 2181,2187 ****
       stores.  So do not take the time to perform dead code elimination.
  
       Register coalescing needs death notes, so generate them.  */
!   life_analysis (insns, NULL, PROP_DEATH_NOTES);
  
    /* Figure out which regs in copies and phi nodes don't conflict and
       therefore can be coalesced.  */
--- 2181,2188 ----
       stores.  So do not take the time to perform dead code elimination.
  
       Register coalescing needs death notes, so generate them.  */
!   life_analysis (insns, NULL, 0);
!   compute_death_notes (NULL);
  
    /* Figure out which regs in copies and phi nodes don't conflict and
       therefore can be coalesced.  */
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.693
diff -c -3 -p -r1.693 toplev.c
*** toplev.c	24 Dec 2002 08:30:32 -0000	1.693
--- toplev.c	29 Dec 2002 20:28:52 -0000
*************** rest_of_compilation (decl)
*** 2592,2597 ****
--- 2592,2598 ----
    rebuild_jump_labels (insns);
    find_exception_handler_labels ();
    find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
+   initialize_cached_insn_extracts ();
  
    delete_unreachable_blocks ();
  
*************** rest_of_compilation (decl)
*** 2716,2721 ****
--- 2717,2723 ----
  
        cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
        convert_to_ssa ();
+       invalidate_insn_extracts_regs_altered ();
  
        close_dump_file (DFI_ssa, print_rtl_with_bb, insns);
        timevar_pop (TV_TO_SSA);
*************** rest_of_compilation (decl)
*** 2761,2766 ****
--- 2763,2769 ----
        open_dump_file (DFI_ussa, decl);
  
        convert_from_ssa ();
+       invalidate_insn_extracts_regs_altered ();
        /* New registers have been created.  Rescan their usage.  */
        reg_scan (insns, max_reg_num (), 1);
  
*************** rest_of_compilation (decl)
*** 3075,3081 ****
  #ifdef ENABLE_CHECKING
    verify_flow_info ();
  #endif
!   life_analysis (insns, rtl_dump_file, PROP_FINAL);
    if (optimize)
      cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE
  		 | (flag_thread_jumps ? CLEANUP_THREADING : 0));
--- 3078,3094 ----
  #ifdef ENABLE_CHECKING
    verify_flow_info ();
  #endif
! 
!   life_analysis (insns, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
! #ifdef AUTO_INC_DEC
!   if (optimize)
!     pre_post_modify_transformation (NULL);
! #endif
!   compute_reg_usage (1);
!   if (rtl_dump_file)
!     dump_flow_info (rtl_dump_file);
! 
    if (optimize)
      cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE
  		 | (flag_thread_jumps ? CLEANUP_THREADING : 0));
*************** rest_of_compilation (decl)
*** 3096,3105 ****
        if (!flag_new_regalloc && initialize_uninitialized_subregs ())
  	{
  	  /* Insns were inserted, so things might look a bit different.  */
  	  insns = get_insns ();
! 	  update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
! 					    PROP_LOG_LINKS | PROP_REG_INFO
! 					    | PROP_DEATH_NOTES);
  	}
      }
  
--- 3109,3121 ----
        if (!flag_new_regalloc && initialize_uninitialized_subregs ())
  	{
  	  /* Insns were inserted, so things might look a bit different.  */
+ 	  sbitmap dirty_blocks;
+ 
  	  insns = get_insns ();
! 	  update_life_info_in_dirty_blocks (0, &dirty_blocks);
! 	  compute_death_notes (dirty_blocks);
! 	  sbitmap_free (dirty_blocks);
! 	  compute_reg_usage (0);
  	}
      }
  
*************** rest_of_compilation (decl)
*** 3116,3121 ****
--- 3132,3138 ----
        timevar_push (TV_COMBINE);
        open_dump_file (DFI_combine, decl);
  
+       create_log_links (NULL);
        rebuild_jump_labels_after_combine
  	= combine_instructions (insns, max_reg_num ());
  
*************** rest_of_compilation (decl)
*** 3159,3164 ****
--- 3176,3182 ----
        timevar_push (TV_REGMOVE);
        open_dump_file (DFI_regmove, decl);
  
+       create_log_links (NULL);
        regmove_optimize (insns, max_reg_num (), rtl_dump_file);
  
        cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
*************** rest_of_compilation (decl)
*** 3226,3232 ****
       jump optimizer after register allocation and reloading are finished.  */
  
    if (! register_life_up_to_date)
!     recompute_reg_usage (insns, ! optimize_size);
  
    if (flag_new_regalloc)
      {
--- 3244,3250 ----
       jump optimizer after register allocation and reloading are finished.  */
  
    if (! register_life_up_to_date)
!     compute_reg_usage (0);
  
    if (flag_new_regalloc)
      {
*************** rest_of_compilation (decl)
*** 3351,3356 ****
--- 3369,3377 ----
  
    close_dump_file (DFI_postreload, print_rtl_with_bb, insns);
  
+   /* Invalidate all insn extracts, as register allocation altered the regs.  */
+   invalidate_insn_extracts_regs_altered ();
+ 
    /* Re-create the death notes which were deleted during reload.  */
    timevar_push (TV_FLOW2);
    open_dump_file (DFI_flow2, decl);
*************** rest_of_compilation (decl)
*** 3374,3379 ****
--- 3395,3401 ----
    if (optimize)
      {
        life_analysis (insns, rtl_dump_file, PROP_FINAL);
+       compute_death_notes (NULL);
        cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE
  		   | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
  
Index: varray.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varray.c,v
retrieving revision 1.16
diff -c -3 -p -r1.16 varray.c
*** varray.c	16 Dec 2002 18:20:02 -0000	1.16
--- varray.c	29 Dec 2002 20:28:52 -0000
*************** static const size_t element_size[NUM_VAR
*** 49,62 ****
    sizeof (struct reg_info_def *),
    sizeof (struct const_equiv_data),
    sizeof (struct basic_block_def *),
!   sizeof (struct elt_list *)
  };
  
  static const int uses_ggc[NUM_VARRAY_DATA] = {
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* unsigned HOST_WIDE_INT */
    1, /* PTR */
    1, 1, 1, 1, 1, /* bitmap_head_def */
!   0, 0, 0, 1
  };
  
  /* Allocate a virtual array with NUM_ELEMENT elements, each of which is
--- 49,64 ----
    sizeof (struct reg_info_def *),
    sizeof (struct const_equiv_data),
    sizeof (struct basic_block_def *),
!   sizeof (struct elt_list *),
!   sizeof (struct insn_extract_elem),
!   sizeof (struct insn_extract *)
  };
  
  static const int uses_ggc[NUM_VARRAY_DATA] = {
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* unsigned HOST_WIDE_INT */
    1, /* PTR */
    1, 1, 1, 1, 1, /* bitmap_head_def */
!   0, 0, 0, 1, 0, 0
  };
  
  /* Allocate a virtual array with NUM_ELEMENT elements, each of which is
Index: varray.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varray.h,v
retrieving revision 1.29
diff -c -3 -p -r1.29 varray.h
*** varray.h	16 Dec 2002 18:20:02 -0000	1.29
--- varray.h	29 Dec 2002 20:28:53 -0000
*************** struct const_equiv_data GTY(()) {
*** 56,61 ****
--- 56,72 ----
    unsigned age;
  };
  
+ /* Auxiliary structure used inside the varray structure, used for
+    liveness analysis.  */
+ struct insn_extract_elem GTY(())
+ {
+   int flags;			/* Flags.  */
+   rtx cond;			/* Condition.  */
+   rtx elem;			/* The element.  */
+   int regno_first;
+   int regno_last;		/* Parts of multiword registers.  */
+ };
+ 
  /* Enum indicating what the varray contains.  
     If this is changed, `element_size' in varray.c needs to be updated.  */
  
*************** enum varray_data_enum {
*** 80,85 ****
--- 91,98 ----
    VARRAY_DATA_CONST_EQUIV,
    VARRAY_DATA_BB,
    VARRAY_DATA_TE,
+   VARRAY_DATA_IE_ELEM,
+   VARRAY_DATA_IE,
    NUM_VARRAY_DATA
  };
  
*************** typedef union varray_data_tag GTY (()) {
*** 125,130 ****
--- 138,147 ----
  				tag ("VARRAY_DATA_BB")))	bb[1];
    struct elt_list	 *GTY ((length ("%0.num_elements"),
  				tag ("VARRAY_DATA_TE")))	te[1];
+   struct insn_extract_elem GTY ((length ("%0.num_elements"),
+ 			tag ("VARRAY_DATA_IE_ELEM"))) 	ie_elem[1];
+   struct insn_extract	 *GTY ((length ("%0.num_elements"),
+ 				tag ("VARRAY_DATA_IE"))) 	ie[1];
  } varray_data;
  
  /* Virtual array of pointers header.  */
*************** extern varray_type varray_init	PARAMS ((
*** 204,209 ****
--- 221,232 ----
  #define VARRAY_ELT_LIST_INIT(va, num, name) \
    va = varray_init (num, VARRAY_DATA_TE, name)
  
+ #define VARRAY_IE_ELEM_INIT(va, num, name) \
+   va = varray_init (num, VARRAY_DATA_IE_ELEM, name)
+ 
+ #define VARRAY_IE_INIT(va, num, name) \
+   va = varray_init (num, VARRAY_DATA_IE, name)
+ 
  /* Free up memory allocated by the virtual array, but do not free any of the
     elements involved.  */
  #define VARRAY_FREE(vp) \
*************** extern void varray_check_failed PARAMS (
*** 277,282 ****
--- 300,307 ----
  #define VARRAY_CONST_EQUIV(VA, N)	VARRAY_CHECK (VA, N, const_equiv)
  #define VARRAY_BB(VA, N)		VARRAY_CHECK (VA, N, bb)
  #define VARRAY_ELT_LIST(VA, N)		VARRAY_CHECK (VA, N, te)
+ #define VARRAY_IE_ELEM(VA, N)		VARRAY_CHECK (VA, N, ie_elem)
+ #define VARRAY_IE(VA, N)		VARRAY_CHECK (VA, N, ie)
  
  /* Push a new element on the end of VA, extending it if necessary.  */
  #define VARRAY_PUSH_CHAR(VA, X)		VARRAY_PUSH (VA, c, X)
*************** extern void varray_check_failed PARAMS (
*** 298,303 ****
--- 323,330 ----
  #define VARRAY_PUSH_REG(VA, X)		VARRAY_PUSH (VA, reg, X)
  #define VARRAY_PUSH_CONST_EQUIV(VA, X)	VARRAY_PUSH (VA, const_equiv, X)
  #define VARRAY_PUSH_BB(VA, X)		VARRAY_PUSH (VA, bb, X)
+ #define VARRAY_PUSH_IE_ELEM(VA, X)	VARRAY_PUSH (VA, ie_elem, X)
+ #define VARRAY_PUSH_IE(VA, X)		VARRAY_PUSH (VA, ie, X)
  
  /* Return the last element of VA.  */
  #define VARRAY_TOP_CHAR(VA)		VARRAY_TOP (VA, c)
*************** extern void varray_check_failed PARAMS (
*** 319,323 ****
--- 346,352 ----
  #define VARRAY_TOP_REG(VA)		VARRAY_TOP (VA, reg)
  #define VARRAY_TOP_CONST_EQUIV(VA)	VARRAY_TOP (VA, const_equiv)
  #define VARRAY_TOP_BB(VA)		VARRAY_TOP (VA, bb)
+ #define VARRAY_TOP_IE_ELEM(VA)		VARRAY_TOP (VA, ie_elem)
+ #define VARRAY_TOP_IE(VA)		VARRAY_TOP (VA, ie)
  
  #endif /* ! GCC_VARRAY_H */
Index: config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.c,v
retrieving revision 1.201
diff -c -3 -p -r1.201 ia64.c
*** config/ia64/ia64.c	20 Dec 2002 04:30:47 -0000	1.201
--- config/ia64/ia64.c	29 Dec 2002 20:29:17 -0000
*************** void
*** 6998,7003 ****
--- 6998,7005 ----
  ia64_reorg (insns)
       rtx insns;
  {
+   sbitmap dirty_blocks;
+ 
    /* We are freeing block_for_insn in the toplev to keep compatibility
       with old MDEP_REORGS that are not CFG based.  Recompute it now.  */
    compute_bb_for_insn ();
*************** ia64_reorg (insns)
*** 7006,7014 ****
    if (optimize == 0)
      split_all_insns (0);
  
!   /* ??? update_life_info_in_dirty_blocks fails to terminate during
!      non-optimizing bootstrap.  */
!   update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES);
  
    if (ia64_flag_schedule_insns2)
      {
--- 7008,7016 ----
    if (optimize == 0)
      split_all_insns (0);
  
!   update_life_info_in_dirty_blocks (0, &dirty_blocks);
!   compute_death_notes (dirty_blocks);
!   sbitmap_free (dirty_blocks);
  
    if (ia64_flag_schedule_insns2)
      {
Index: config/ip2k/ip2k.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ip2k/ip2k.c,v
retrieving revision 1.14
diff -c -3 -p -r1.14 ip2k.c
*** config/ip2k/ip2k.c	16 Dec 2002 18:21:27 -0000	1.14
--- config/ip2k/ip2k.c	29 Dec 2002 20:29:28 -0000
*************** machine_dependent_reorg (first_insn)
*** 5358,5364 ****
       things in such a way that another go will win.  Do so now!  */
    reload_cse_regs (first_insn);
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
    
    /* Look for where absurd things are happening with DP.  */
    mdr_try_dp_reload_elim (first_insn);
--- 5358,5366 ----
       things in such a way that another go will win.  Do so now!  */
    reload_cse_regs (first_insn);
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, 0);
!   compute_death_notes (NULL);
!   compute_reg_usage (1);
    
    /* Look for where absurd things are happening with DP.  */
    mdr_try_dp_reload_elim (first_insn);
*************** machine_dependent_reorg (first_insn)
*** 5370,5376 ****
  
    reload_cse_regs (first_insn);
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
    if (flag_peephole2)
      peephole2_optimize (NULL);
  
--- 5372,5381 ----
  
    reload_cse_regs (first_insn);
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, 0);
!   compute_death_notes (NULL);
!   compute_reg_usage (1);
!   
    if (flag_peephole2)
      peephole2_optimize (NULL);
  
*************** machine_dependent_reorg (first_insn)
*** 5397,5403 ****
    mdr_try_move_pushes (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
  
    mdr_try_propagate_move (first_insn);
    mdr_resequence_xy_yx (first_insn);
--- 5402,5409 ----
    mdr_try_move_pushes (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
  
    mdr_try_propagate_move (first_insn);
    mdr_resequence_xy_yx (first_insn);
*************** machine_dependent_reorg (first_insn)
*** 5411,5424 ****
  
    reload_cse_regs (first_insn);
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
    if (flag_peephole2)
      peephole2_optimize (NULL);
  
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
  
    ip2k_reorg_split_simode = 1;
    split_all_insns (0);
--- 5417,5432 ----
  
    reload_cse_regs (first_insn);
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
    if (flag_peephole2)
      peephole2_optimize (NULL);
  
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
  
    ip2k_reorg_split_simode = 1;
    split_all_insns (0);
*************** machine_dependent_reorg (first_insn)
*** 5429,5442 ****
  
    reload_cse_regs (first_insn);
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
    if (flag_peephole2)
      peephole2_optimize (NULL);
  
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
  
    ip2k_reorg_split_himode = 1;
    ip2k_reorg_merge_qimode = 1;
--- 5437,5452 ----
  
    reload_cse_regs (first_insn);
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
    if (flag_peephole2)
      peephole2_optimize (NULL);
  
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
  
    ip2k_reorg_split_himode = 1;
    ip2k_reorg_merge_qimode = 1;
*************** machine_dependent_reorg (first_insn)
*** 5454,5474 ****
    /* Call to  jump_optimize (...) was here, but now I removed it.  */
    
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
    if (flag_peephole2)
      peephole2_optimize (NULL);
  
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
    mdr_try_remove_redundant_insns (first_insn);
  
    mdr_try_propagate_clr (first_insn);
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
  
    ip2k_reorg_split_qimode = 1;
    split_all_insns (0);
--- 5464,5488 ----
    /* Call to  jump_optimize (...) was here, but now I removed it.  */
    
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
! 
    if (flag_peephole2)
      peephole2_optimize (NULL);
  
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
    mdr_try_remove_redundant_insns (first_insn);
  
    mdr_try_propagate_clr (first_insn);
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
  
    ip2k_reorg_split_qimode = 1;
    split_all_insns (0);
*************** machine_dependent_reorg (first_insn)
*** 5477,5483 ****
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, 0, PROP_FINAL);
  #endif
  }
  
--- 5491,5498 ----
    mdr_try_propagate_move (first_insn);
  
    find_basic_blocks (first_insn, max_reg_num (), 0);
!   life_analysis (first_insn, NULL, PROP_FINAL);
!   compute_death_notes (NULL);
  #endif
  }
  
Index: config/m68hc11/m68hc11.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/m68hc11/m68hc11.c,v
retrieving revision 1.57
diff -c -3 -p -r1.57 m68hc11.c
*** config/m68hc11/m68hc11.c	16 Dec 2002 18:21:29 -0000	1.57
--- config/m68hc11/m68hc11.c	29 Dec 2002 20:29:38 -0000
*************** m68hc11_reorg (first)
*** 5112,5118 ****
              }
          }
  
!       life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
      }
  
    z_replacement_completed = 2;
--- 5112,5120 ----
              }
          }
  
!       life_analysis (first, 0, 0);
!       compute_death_notes (NULL);
!       compute_reg_usage (1);
      }
  
    z_replacement_completed = 2;


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