Reg stack rewrite ....

Jan Hubicka hubicka@atrey.karlin.mff.cuni.cz
Sat Jul 3 16:01:00 GMT 1999


Hi
Here is updated version of my patch for new backend. Hope I didn't lost
any changes while merging the patches.  Because patch is quite
large and reg-stack changes common new, I would like to ask you to give some
priority to this to avoid new rejects, please :)

I didn't run the testsuite, because I don't have it here, but I've succesfully
compiled some fp intensive applications. Interesting enought I've got
noticeable speed improbements (that was much smaller in old backend). 30%
in mset calculation loop.
This seems to be caused by fact, that gcc fails to unroll loop correctly
with the new backend, so basic blocks are smaller and jumps in flow graph
more common.

There is still hack with return value life analysis. I am able to do this
only after reload. Before reload it causes compiler faults.
This is most probably caused in case return value is undefined or only half
defined.  Life analysis then increases lifetime of eax over whole function.
Maybe this can be fixed by making lifeanalysis to shorten lifetimes to
smallest possible in such case. I would love to hear your suggestions
about this problem.

This change is necesary, because
the reg-stack code removes all non-live registers from stack, so the
register must be live on the end. I believe that I can't easily update the flow
information for this in reg-stack.


Tue Apr  6 22:13:17 CEST 1999 Jan Hubicka <hubicka@freesoft.cz>

	* function.c (assign_params): Do not emit USE insns.

	* expr.c (expand_builtin_apply_args): Do not emit USE insns.

	* global.c (global_conflicts): Do not spill pseudos for non-critical
	abnormal edges, because reg-stack can now handle them.

	* flow.c (mark_regs_live_at_end):

	* reg-stack.c: include basic-block.h and output.h
	(max_uid): Remove global variable.
	(blocks): Remove global variable.
	(block_begin): Remove global variable.
	(block_end): Remove global variable.
	(block_drops_in): Remove global variable.
	(block_number): Remove global variable.
	(block_out_reg_set): Remove global variable.
	(block_stack_in): Remove global variable.
	(BLOCK_NUM): Remove function.
	(mark_regs_pat): Remove function.
	(record_label_references): Remove function.
	(record_reg_life_pat): Remove function.
	(record_reg_life): Remove function.
	(find_blocks): Remove function.
	(goto_block_pat): Remove function.
	(print_blocks): Remove function.
	(dump_stack_info): Remove function.
	(forced_labels): Remove global variable.
	(block_info): New structure.
	(block): New global variable.
	(current_block): New global variable.
	(convert_regs): New parameter file.
	(print_stack): New function.
	(emit_insns_after_bb): New function.
	(straighten_stack): Update change_stack call.
	(next_flags_user): Use block_end info.
	(reg_to_stack): Update comment, remove (use fpreg) insns,
	don't do life analysis by hand and call find_basic_block
	and life_analysis instead, 
	do not call stack_reg_life_analysis.
	(record_asm_reg_life): Rename to check_asm_stack_operands
	and remove most of code used to update life information.
	(stack_reg_life_analysis): Remove unused parameters first and
	stackentry, don't do the life analysis, only convert CFG generated
	by flow.c, generate initialization code converted and to the edge
	of flow graph.
	(emit_swap_insn): Use NOTE_INSN_BASIC_BLOCK do determine basic
	block boundary, work correctly for beggining of insn chain too,
	use emit_insn_after_bb.
	(move_for_stack_reg): Use emit_insn_after_bb.
	(subst_stack_regs_pat): Handle USE insns, use emit_insn_after_bb,
	ensure that reg with UNUSED note is really live before killing it.
	(subst_asm_stack_regs): Call check_asm_stack_operands, use
	emit_insn_after_bb, update change_stack call.
	(change_stack): Take care for basic block boundaries, when converted
	to enum parameter emit_where.
	(convert_regs): Use new basic block representation, process only
	reached blocks, dump debuging information, follow edges and
	emit correcting insns to them. Call commit_edge_insertions
	when necesary, call stack_reg_life_analysis.

*** flow.c.old	Fri Jul  2 05:08:17 1999
--- flow.c	Sat Jul  3 07:05:23 1999
*************** Boston, MA 02111-1307, USA.  */
*** 132,137 ****
--- 132,138 ----
  #include "recog.h"
  #include "insn-flags.h"
  #include "resource.h"
+ #include "tree.h"
  
  #include "obstack.h"
  #define obstack_chunk_alloc xmalloc
*************** mark_regs_live_at_end (set)
*** 2300,2306 ****
  	)
        SET_REGNO_REG_SET (set, i);
  
!   /* ??? Mark function return value here rather than as uses.  */
  }
  
  /* Determine which registers are live at the start of each
--- 2301,2328 ----
  	)
        SET_REGNO_REG_SET (set, i);
  
!   /* Mark function return value here.  
!      ??? remove uses?  */
!   if (reload_completed)
!   {
!     tree decl = current_function_decl;
!     rtx result = DECL_RTL ( DECL_RESULT (decl));
!     /* ??? this is copied from reg-stack. I am not sure what this actually
!        mean.  */
!     if (result != 0 && GET_CODE (result) != REG)
!       {
! #ifdef FUNCTION_OUTGOING_VALUE
!         result = FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);
! #else
!         result = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);
! #endif
!       }
!     /* ??? can function return multiple registers?  */
!     if (result && GET_CODE (result) == REG)
!       {
!   	 SET_REGNO_REG_SET (set, REGNO (result));
!       }
!   }
  }
  
  /* Determine which registers are live at the start of each
*** reg-stack.c.orig	Fri Jul  2 09:53:18 1999
--- reg-stack.c	Sat Jul  3 08:29:25 1999
*************** Boston, MA 02111-1307, USA.  */
*** 162,167 ****
--- 162,169 ----
  #include "toplev.h"
  #include "recog.h"
  #include "varray.h"
+ #include "basic-block.h"
+ #include "output.h"
  
  #ifdef STACK_REGS
  
*************** typedef struct stack_def
*** 183,217 ****
    char reg[REG_STACK_SIZE];	/* register - stack mapping */
  } *stack;
  
! /* highest instruction uid */
! static int max_uid = 0;
! 
! /* Number of basic blocks in the current function.  */
! static int blocks;
  
! /* Element N is first insn in basic block N.
!    This info lasts until we finish compiling the function.  */
! static rtx *block_begin;
! 
! /* Element N is last insn in basic block N.
!    This info lasts until we finish compiling the function.  */
! static rtx *block_end;
! 
! /* Element N is nonzero if control can drop into basic block N */
! static char *block_drops_in;
! 
! /* Element N says all about the stack at entry block N */
! static stack block_stack_in;
! 
! /* Element N says all about the stack life at the end of block N */
! static HARD_REG_SET *block_out_reg_set;
! 
! /* This is where the BLOCK_NUM values are really stored.  This is set
!    up by find_blocks and used there and in life_analysis.  It can be used
!    later, but only to look up an insn that is the head or tail of some
!    block.  life_analysis and the stack register conversion process can
!    add insns within a block.  */
! static int *block_number;
  
  /* We use this array to cache info about insns, because otherwise we
     spend too much time in stack_regs_mentioned_p. 
--- 185,207 ----
    char reg[REG_STACK_SIZE];	/* register - stack mapping */
  } *stack;
  
! /* This record is used to carry information about basic blocks.  */
! struct block_info
! {
!   int done;			/* 1 in case block is already converted */
!   struct stack_def stack_in;	/* input stack configuration */
!   HARD_REG_SET out_reg_set;	/* stack registers live on the output */
! };
! 
!  /* This enum is passed to change_stack to indicate where to emit insns.  */
! enum emit_when
! {
!   EMIT_AFTER,
!   EMIT_BEFORE
! };
  
! /* Basic block information structure.  */
! static struct block_info *block;
  
  /* We use this array to cache info about insns, because otherwise we
     spend too much time in stack_regs_mentioned_p. 
*************** static int *block_number;
*** 221,226 ****
--- 211,219 ----
     stack registers.  */
  static varray_type stack_regs_mentioned_data;
  
+ /* Number of block we are currently working on */
+ static int current_block;
+ 
  /* This is the register file for all register after conversion */
  static rtx
    FP_mode_reg[LAST_STACK_REG+1-FIRST_STACK_REG][(int) MAX_MACHINE_MODE];
*************** static rtx
*** 228,262 ****
  #define FP_MODE_REG(regno,mode)	\
    (FP_mode_reg[(regno)-FIRST_STACK_REG][(int)(mode)])
  
- /* Get the basic block number of an insn.  See note at block_number
-    definition are validity of this information.  */
- 
- #define BLOCK_NUM(INSN)					\
-   ((INSN_UID (INSN) > max_uid)				\
-    ? (abort() , -1) : block_number[INSN_UID (INSN)])
- 
- extern rtx forced_labels;
- 
  /* Forward declarations */
  
  static int stack_regs_mentioned_p	PROTO((rtx pat));
- static void mark_regs_pat		PROTO((rtx, HARD_REG_SET *));
  static void straighten_stack		PROTO((rtx, stack));
  static void pop_stack			PROTO((stack, int));
- static void record_label_references	PROTO((rtx, rtx));
  static rtx *get_true_reg		PROTO((rtx *));
  static int constrain_asm_operands	PROTO((int, rtx *, const char **,
  					       int *, enum reg_class *));
! 
! static void record_asm_reg_life		PROTO((rtx,stack, rtx *, const char **,
  					       int, int));
- static void record_reg_life_pat		PROTO((rtx, HARD_REG_SET *,
- 					       HARD_REG_SET *, int));
  static void get_asm_operand_lengths	PROTO((rtx, int, int *, int *));
- static void record_reg_life		PROTO((rtx, int, stack));
- static void find_blocks			PROTO((rtx));
  static rtx stack_result			PROTO((tree));
! static void stack_reg_life_analysis	PROTO((rtx, HARD_REG_SET *));
  static void replace_reg			PROTO((rtx *, int));
  static void remove_regno_note		PROTO((rtx, enum reg_note, int));
  static int get_hard_regnum		PROTO((stack, rtx));
--- 221,239 ----
  #define FP_MODE_REG(regno,mode)	\
    (FP_mode_reg[(regno)-FIRST_STACK_REG][(int)(mode)])
  
  /* Forward declarations */
  
  static int stack_regs_mentioned_p	PROTO((rtx pat));
  static void straighten_stack		PROTO((rtx, stack));
  static void pop_stack			PROTO((stack, int));
  static rtx *get_true_reg		PROTO((rtx *));
  static int constrain_asm_operands	PROTO((int, rtx *, const char **,
  					       int *, enum reg_class *));
! static int check_asm_stack_operands	PROTO((rtx, rtx *, const char **,
  					       int, int));
  static void get_asm_operand_lengths	PROTO((rtx, int, int *, int *));
  static rtx stack_result			PROTO((tree));
! static int stack_reg_life_analysis	PROTO((void));
  static void replace_reg			PROTO((rtx *, int));
  static void remove_regno_note		PROTO((rtx, enum reg_note, int));
  static int get_hard_regnum		PROTO((stack, rtx));
*************** static void subst_stack_regs_pat	PROTO((
*** 271,282 ****
  static void subst_asm_stack_regs	PROTO((rtx, stack, rtx *, rtx **,
  					       const char **, int, int));
  static void subst_stack_regs		PROTO((rtx, stack));
! static void change_stack		PROTO((rtx, stack, stack, rtx (*) ()));
  
! static void goto_block_pat		PROTO((rtx, stack, rtx));
! static void convert_regs		PROTO((void));
! static void print_blocks		PROTO((FILE *, rtx, rtx));
! static void dump_stack_info		PROTO((FILE *));
  
  /* Return non-zero if any stack register is mentioned somewhere within PAT.  */
  
--- 248,277 ----
  static void subst_asm_stack_regs	PROTO((rtx, stack, rtx *, rtx **,
  					       const char **, int, int));
  static void subst_stack_regs		PROTO((rtx, stack));
! static void change_stack		PROTO((rtx, stack, stack, enum emit_when));
  
! static void convert_regs		PROTO((FILE *));
! static void print_stack			PROTO((FILE *, stack s));
! static rtx emit_insn_after_bb		PROTO((register rtx pattern, register rtx after));
! 
! /* Work equivalenty to emit_insn_after, but update basic block
!    boundaries too (update basic_block_end).
! 
!    We keep current basic block in the current_block variable. If
!    AFTER is last insn of basic block, update end pointer.
! 
!    We don't need to take care for emit_insn_before, because basic block starts
!    by note, so we can just ensure, that we are adding after that note.  */
! 
! static rtx
! emit_insn_after_bb (pattern, after)
!      register rtx pattern, after;
! {
!   rtx r = emit_insn_after (pattern, after);
!   if (current_block >= 0 && BASIC_BLOCK (current_block)->end == after)
!     BASIC_BLOCK (current_block)->end = r;
!   return r;
! }
  
  /* Return non-zero if any stack register is mentioned somewhere within PAT.  */
  
*************** next_flags_user (insn)
*** 361,398 ****
            && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
          return insn;
  
!       if (GET_CODE (insn) == JUMP_INSN
! 	  || GET_CODE (insn) == CODE_LABEL
! 	  || GET_CODE (insn) == CALL_INSN)
  	return NULL_RTX;
      }
  }
  
- /* Mark all registers needed for this pattern.  */
- 
- static void
- mark_regs_pat (pat, set)
-      rtx pat;
-      HARD_REG_SET *set;
- {
-   enum machine_mode mode;
-   register int regno;
-   register int count;
- 
-   if (GET_CODE (pat) == SUBREG)
-     {
-       mode = GET_MODE (pat);
-       regno = SUBREG_WORD (pat);
-       regno += REGNO (SUBREG_REG (pat));
-     }
-   else
-     regno = REGNO (pat), mode = GET_MODE (pat);
- 
-   for (count = HARD_REGNO_NREGS (regno, mode);
-        count; count--, regno++)
-     SET_HARD_REG_BIT (*set, regno);
- }
- 
  /* Reorganise the stack into ascending numbers,
     after this insn.  */
  
--- 356,366 ----
            && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
          return insn;
  
!       if (current_block >= 0 && BASIC_BLOCK (current_block)->end == insn)
  	return NULL_RTX;
      }
  }
  
  /* Reorganise the stack into ascending numbers,
     after this insn.  */
  
*************** straighten_stack (insn, regstack)
*** 416,422 ****
    for (top = temp_stack.top = regstack->top; top >= 0; top--)
      temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
    
!   change_stack (insn, regstack, &temp_stack, emit_insn_after);
  }
  
  /* Pop a register from the stack */
--- 384,390 ----
    for (top = temp_stack.top = regstack->top; top >= 0; top--)
      temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
    
!   change_stack (insn, regstack, &temp_stack, EMIT_AFTER);
  }
  
  /* Pop a register from the stack */
*************** pop_stack (regstack, regno)
*** 449,470 ****
     register file.  FIRST is the first insn in the function, FILE is the
     dump file, if used.
  
!    First compute the beginning and end of each basic block.  Do a
!    register life analysis on the stack registers, recording the result
!    for the head and tail of each basic block.  The convert each insn one
     by one.  Run a last jump_optimize() pass, if optimizing, to eliminate
!    any cross-jumping created when the converter inserts pop insns.*/
  
  void
  reg_to_stack (first, file)
       rtx first;
       FILE *file;
  {
-   register rtx insn;
    register int i;
-   int stack_reg_seen = 0;
    enum machine_mode mode;
!   HARD_REG_SET stackentry;
  
    ix86_flags_rtx = gen_rtx_REG (CCmode, FLAGS_REG);
  
--- 417,436 ----
     register file.  FIRST is the first insn in the function, FILE is the
     dump file, if used.
  
!    First create CFG and do life analysis.  Then convert each insn one
     by one.  Run a last jump_optimize() pass, if optimizing, to eliminate
!    code duplication created when the converter inserts pop insns to the
!    edges.  */
  
  void
  reg_to_stack (first, file)
       rtx first;
       FILE *file;
  {
    register int i;
    enum machine_mode mode;
!   int max_uid;
!   rtx insn = first;
  
    ix86_flags_rtx = gen_rtx_REG (CCmode, FLAGS_REG);
  
*************** reg_to_stack (first, file)
*** 472,655 ****
    VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1,
  		    "stack_regs_mentioned cache");
  
!   CLEAR_HARD_REG_SET (stackentry);
  
!   {
!     static int initialised;
!     if (!initialised)
!       {
! #if 0
! 	initialised = 1;	/* This array can not have been previously
! 				   initialised, because the rtx's are
! 				   thrown away between compilations of
! 				   functions.  */
! #endif
!         for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
! 	  {
! 	    for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
! 		 mode = GET_MODE_WIDER_MODE (mode))
!               FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
! 	    for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode;
! 		 mode = GET_MODE_WIDER_MODE (mode))
!               FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
! 	  }
!       }
!   }
  
!   /* Count the basic blocks.  Also find maximum insn uid.  */
!   {
!     register RTX_CODE prev_code = BARRIER;
!     register RTX_CODE code;
!     register int before_function_beg = 1;
! 
!     max_uid = 0;
!     blocks = 0;
!     for (insn = first; insn; insn = NEXT_INSN (insn))
!       {
! 	/* Note that this loop must select the same block boundaries
! 	   as code in find_blocks.  Also note that this code is not the
! 	   same as that used in flow.c.  */
! 
! 	if (INSN_UID (insn) > max_uid)
! 	  max_uid = INSN_UID (insn);
! 
! 	code = GET_CODE (insn);
! 
! 	if (code == CODE_LABEL
! 	    || (prev_code != INSN
! 		&& prev_code != CALL_INSN
! 		&& prev_code != CODE_LABEL
! 		&& GET_RTX_CLASS (code) == 'i'))
! 	  blocks++;
  
! 	if (code == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
! 	  before_function_beg = 0;
  
! 	/* Remember whether or not this insn mentions an FP regs.
! 	   Check JUMP_INSNs too, in case someone creates a funny PARALLEL.  */
  
! 	if (GET_RTX_CLASS (code) == 'i'
! 	    && stack_regs_mentioned_p (PATTERN (insn)))
  	  {
! 	    stack_reg_seen = 1;
!  	    VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1;
  
! 	    /* Note any register passing parameters.  */
  
- 	    if (before_function_beg && code == INSN
- 	        && GET_CODE (PATTERN (insn)) == USE)
-               record_reg_life_pat (PATTERN (insn), (HARD_REG_SET *) 0,
- 				   &stackentry, 1);
  	  }
- 	else
- 	  VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2;
- 
- 	if (code == CODE_LABEL)
- 	  LABEL_REFS (insn) = insn; /* delete old chain */
- 
- 	if (code != NOTE)
- 	  prev_code = code;
        }
    }
  
!   /* If no stack register reference exists in this insn, there isn't
!      anything to convert.  */
  
!   if (! stack_reg_seen)
      {
!       VARRAY_FREE (stack_regs_mentioned_data);
!       return;
      }
  
-   /* If there are stack registers, there must be at least one block.  */
  
!   if (! blocks)
!     abort ();
! 
!   /* Allocate some tables that last till end of compiling this function
!      and some needed only in find_blocks and life_analysis.  */
! 
!   block_begin = (rtx *) alloca (blocks * sizeof (rtx));
!   block_end = (rtx *) alloca (blocks * sizeof (rtx));
!   block_drops_in = (char *) alloca (blocks);
! 
!   block_stack_in = (stack) alloca (blocks * sizeof (struct stack_def));
!   block_out_reg_set = (HARD_REG_SET *) alloca (blocks * sizeof (HARD_REG_SET));
!   bzero ((char *) block_stack_in, blocks * sizeof (struct stack_def));
!   bzero ((char *) block_out_reg_set, blocks * sizeof (HARD_REG_SET));
! 
!   block_number = (int *) alloca ((max_uid + 1) * sizeof (int));
! 
!   find_blocks (first);
!   stack_reg_life_analysis (first, &stackentry);
! 
!   /* Dump the life analysis debug information before jump
!      optimization, as that will destroy the LABEL_REFS we keep the
!      information in.  */
  
!   if (file)
!     dump_stack_info (file);
! 
!   convert_regs ();
  
    if (optimize)
-     jump_optimize (first, 2, 0, 0);
- 
-   VARRAY_FREE (stack_regs_mentioned_data);
- }
- 
- /* Check PAT, which is in INSN, for LABEL_REFs.  Add INSN to the
-    label's chain of references, and note which insn contains each
-    reference.  */
- 
- static void
- record_label_references (insn, pat)
-      rtx insn, pat;
- {
-   register enum rtx_code code = GET_CODE (pat);
-   register int i;
-   register char *fmt;
- 
-   if (code == LABEL_REF)
      {
!       register rtx label = XEXP (pat, 0);
!       register rtx ref;
! 
!       if (GET_CODE (label) != CODE_LABEL)
! 	abort ();
! 
!       /* If this is an undefined label, LABEL_REFS (label) contains
!          garbage.  */
!       if (INSN_UID (label) == 0)
! 	return;
! 
!       /* Don't make a duplicate in the code_label's chain.  */
! 
!       for (ref = LABEL_REFS (label);
! 	   ref && ref != label;
! 	   ref = LABEL_NEXTREF (ref))
! 	if (CONTAINING_INSN (ref) == insn)
! 	  return;
! 
!       CONTAINING_INSN (pat) = insn;
!       LABEL_NEXTREF (pat) = LABEL_REFS (label);
!       LABEL_REFS (label) = pat;
! 
!       return;
!     }
! 
!   fmt = GET_RTX_FORMAT (code);
!   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
!     {
!       if (fmt[i] == 'e')
! 	record_label_references (insn, XEXP (pat, i));
!       if (fmt[i] == 'E')
! 	{
! 	  register int j;
! 	  for (j = 0; j < XVECLEN (pat, i); j++)
! 	    record_label_references (insn, XVECEXP (pat, i, j));
! 	}
      }
  }
  
  /* Return a pointer to the REG expression within PAT.  If PAT is not a
--- 438,522 ----
    VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1,
  		    "stack_regs_mentioned cache");
  
!   /* See if there is something to do.  With flow analysis is reg-stack quite
!      expensive so we might save some compilation time.  */
!   while (insn)
!     {
!       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
! 	  && stack_regs_mentioned_p (PATTERN (insn)))
! 	{
!  	  VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1;
! 	  break;
! 	}
!       else
! 	VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2;
!       insn = NEXT_INSN (insn);
!     }
  
!   if (! insn)
!     {
!       VARRAY_FREE (stack_regs_mentioned_data);
!       return;
!     }
  
!   /* OK, floating point insns are here.  */
  
!   /* OOPS... the basic block info and life info is corrupt at the time we enter
!      reg-stack (by sched and jump pass).  For now do flow pass once again and
!      sove this issue later.  Once this is resolved we can call flow only
!      in the non-optimizing case.  */
!   {
!     rtx next;
!     /* Strip death notes from insns to let flow re-insert them correctly.  */
  
!     next = first;
!     while (next)
!       {
! 	insn = next;
! 	next = NEXT_INSN (insn);
  
! 	if ((GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN))
  	  {
! 	    rtx next_note, note;
  
! 	    for (note = REG_NOTES (insn); note; note = next_note)
! 	      {
! 		next_note = XEXP (note, 1);
! 		if (REG_NOTE_KIND (note) == REG_DEAD
! 		    || REG_NOTE_KIND (note) == REG_UNUSED)
! 		  remove_note (insn, note);
! 	      }
  
  	  }
        }
    }
+   find_basic_blocks (first, max_reg_num (), file, 0);
+   life_analysis (first, max_reg_num (), file, 0);
  
!   if (! n_basic_blocks)
!     return;
  
!   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
      {
!       for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
! 	   mode = GET_MODE_WIDER_MODE (mode))
! 	FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
!       for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode;
! 	   mode = GET_MODE_WIDER_MODE (mode))
! 	FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
      }
  
  
!   block = (struct block_info *) alloca (n_basic_blocks * sizeof (struct block_info));
!   bzero ((char *) block, n_basic_blocks * sizeof (struct block_info));
  
!   convert_regs (file);
  
    if (optimize)
      {
!       jump_optimize (first, 2, 0, 0);
      }
+   VARRAY_FREE (stack_regs_mentioned_data);
  }
  
  /* Return a pointer to the REG expression within PAT.  If PAT is not a
*************** constrain_asm_operands (n_operands, oper
*** 972,992 ****
    return this_alternative == n_alternatives ? -1 : this_alternative;
  }
  
! /* Record the life info of each stack reg in INSN, updating REGSTACK.
!    N_INPUTS is the number of inputs; N_OUTPUTS the outputs.  CONSTRAINTS
!    is an array of the constraint strings used in the asm statement.
!    OPERANDS is an array of all operands for the insn, and is assumed to
!    contain all output operands, then all inputs operands.
! 
!    There are many rules that an asm statement for stack-like regs must
     follow.  Those rules are explained at the top of this file: the rule
     numbers below refer to that explanation.  */
  
! static void
! record_asm_reg_life (insn, regstack, operands, constraints,
! 		     n_inputs, n_outputs)
       rtx insn;
-      stack regstack;
       rtx *operands;
       const char **constraints;
       int n_inputs, n_outputs;
--- 839,851 ----
    return this_alternative == n_alternatives ? -1 : this_alternative;
  }
  
! /* There are many rules that an asm statement for stack-like regs must
     follow.  Those rules are explained at the top of this file: the rule
     numbers below refer to that explanation.  */
  
! static int
! check_asm_stack_operands (insn, operands, constraints, n_inputs, n_outputs)
       rtx insn;
       rtx *operands;
       const char **constraints;
       int n_inputs, n_outputs;
*************** record_asm_reg_life (insn, regstack, ope
*** 1144,1253 ****
      {
        /* Avoid further trouble with this insn.  */
        PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
!       VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2;
!       return;
!     }
! 
!   /* Process all outputs */
!   for (i = 0; i < n_outputs; i++)
!     {
!       rtx op = operands[i];
! 
!       if (! STACK_REG_P (op))
! 	{
! 	  if (stack_regs_mentioned_p (op))
! 	    abort ();
! 	  else
! 	    continue;
! 	}
! 
!       /* Each destination is dead before this insn.  If the
! 	 destination is not used after this insn, record this with
! 	 REG_UNUSED.  */
! 
!       if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (op)))
! 	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED, op,
! 					      REG_NOTES (insn));
! 
!       CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (op));
!     }
! 
!   /* Process all inputs */
!   for (i = first_input; i < first_input + n_inputs; i++)
!     {
!       if (! STACK_REG_P (operands[i]))
! 	{
! 	  if (stack_regs_mentioned_p (operands[i]))
! 	    abort ();
! 	  else
! 	    continue;
! 	}
! 
!       /* If an input is dead after the insn, record a death note.
! 	 But don't record a death note if there is already a death note,
! 	 or if the input is also an output.  */
! 
!       if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]))
! 	  && operand_matches[i] == -1
! 	  && find_regno_note (insn, REG_DEAD, REGNO (operands[i])) == NULL_RTX)
! 	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, operands[i],
! 					      REG_NOTES (insn));
! 
!       SET_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]));
!     }
! }
! 
! /* Scan PAT, which is part of INSN, and record registers appearing in
!    a SET_DEST in DEST, and other registers in SRC.
! 
!    This function does not know about SET_DESTs that are both input and
!    output (such as ZERO_EXTRACT) - this cannot happen on a 387.  */
! 
! static void
! record_reg_life_pat (pat, src, dest, douse)
!      rtx pat;
!      HARD_REG_SET *src, *dest;
!      int douse;
! {
!   register char *fmt;
!   register int i;
! 
!   if (STACK_REG_P (pat)
!       || (GET_CODE (pat) == SUBREG && STACK_REG_P (SUBREG_REG (pat))))
!     {
!       if (src)
! 	mark_regs_pat (pat, src);
! 
!       if (dest)
! 	mark_regs_pat (pat, dest);
! 
!       return;
!     }
! 
!   if (GET_CODE (pat) == SET)
!     {
!       record_reg_life_pat (XEXP (pat, 0), NULL_PTR, dest, 0);
!       record_reg_life_pat (XEXP (pat, 1), src, NULL_PTR, 0);
!       return;
!     }
! 
!   /* We don't need to consider either of these cases.  */
!   if ((GET_CODE (pat) == USE && !douse) || GET_CODE (pat) == CLOBBER)
!     return;
! 
!   fmt = GET_RTX_FORMAT (GET_CODE (pat));
!   for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
!     {
!       if (fmt[i] == 'E')
! 	{
! 	  register int j;
! 
! 	  for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
! 	    record_reg_life_pat (XVECEXP (pat, i, j), src, dest, 0);
! 	}
!       else if (fmt[i] == 'e')
! 	record_reg_life_pat (XEXP (pat, i), src, dest, 0);
      }
  }
  
  /* Calculate the number of inputs and outputs in BODY, an
--- 1003,1011 ----
      {
        /* Avoid further trouble with this insn.  */
        PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
!       return 0;
      }
+   return 1;
  }
  
  /* Calculate the number of inputs and outputs in BODY, an
*************** get_asm_operand_lengths (body, n_operand
*** 1280,1498 ****
    *n_outputs = n_operands - *n_inputs;
  }
  
- /* Scan INSN, which is in BLOCK, and record the life & death of stack
-    registers in REGSTACK.  This function is called to process insns from
-    the last insn in a block to the first.  The actual scanning is done in
-    record_reg_life_pat.
- 
-    If a register is live after a CALL_INSN, but is not a value return
-    register for that CALL_INSN, then code is emitted to initialize that
-    register.  The block_end[] data is kept accurate.
- 
-    Existing death and unset notes for stack registers are deleted
-    before processing the insn.  */
- 
- static void
- record_reg_life (insn, block, regstack)
-      rtx insn;
-      int block;
-      stack regstack;
- {
-   rtx note, *note_link;
-   int n_operands;
- 
-   if ((GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
-       || INSN_DELETED_P (insn))
-     return;
- 
-   /* Strip death notes for stack regs from this insn */
- 
-   note_link = &REG_NOTES(insn);
-   for (note = *note_link; note; note = XEXP (note, 1))
-     if (STACK_REG_P (XEXP (note, 0))
- 	&& (REG_NOTE_KIND (note) == REG_DEAD
- 	    || REG_NOTE_KIND (note) == REG_UNUSED))
-       *note_link = XEXP (note, 1);
-     else
-       note_link = &XEXP (note, 1);
- 
-   /* Process all patterns in the insn.  */
- 
-   n_operands = asm_noperands (PATTERN (insn));
-   if (n_operands >= 0)
-     {
-       /* This insn is an `asm' with operands.  Decode the operands,
- 	 decide how many are inputs, and record the life information.  */
- 
-       rtx operands[MAX_RECOG_OPERANDS];
-       rtx body = PATTERN (insn);
-       int n_inputs, n_outputs;
-       const char **constraints =
- 	(const char **) alloca (n_operands * sizeof (char *));
- 
-       decode_asm_operands (body, operands, NULL_PTR, constraints, NULL_PTR);
-       get_asm_operand_lengths (body, n_operands, &n_inputs, &n_outputs);
-       record_asm_reg_life (insn, regstack, operands, constraints,
- 			   n_inputs, n_outputs);
-       return;
-     }
- 
-   {
-     HARD_REG_SET src, dest;
-     int regno;
- 
-     CLEAR_HARD_REG_SET (src);
-     CLEAR_HARD_REG_SET (dest);
- 
-     if (GET_CODE (insn) == CALL_INSN)
-       for (note = CALL_INSN_FUNCTION_USAGE (insn);
- 	   note;
- 	   note = XEXP (note, 1))
- 	if (GET_CODE (XEXP (note, 0)) == USE)
- 	  record_reg_life_pat (SET_DEST (XEXP (note, 0)), &src, NULL_PTR, 0);
- 
-     record_reg_life_pat (PATTERN (insn), &src, &dest, 0);
-     for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
-       if (! TEST_HARD_REG_BIT (regstack->reg_set, regno))
- 	{
- 	  if (TEST_HARD_REG_BIT (src, regno)
- 	      && ! TEST_HARD_REG_BIT (dest, regno))
- 	    REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
- 						  FP_MODE_REG (regno, DFmode),
- 						  REG_NOTES (insn));
- 	  else if (TEST_HARD_REG_BIT (dest, regno))
- 	    REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
- 						  FP_MODE_REG (regno, DFmode),
- 						  REG_NOTES (insn));
- 	}
- 
-     if (GET_CODE (insn) == CALL_INSN)
-       {
- 	int reg;
- 
- 	/* There might be a reg that is live after a function call.
- 	   Initialize it to zero so that the program does not crash.  See
- 	   comment towards the end of stack_reg_life_analysis().  */
- 
- 	for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
- 	  if (! TEST_HARD_REG_BIT (dest, reg)
- 	      && TEST_HARD_REG_BIT (regstack->reg_set, reg))
- 	    {
- 	      rtx init, pat;
- 
- 	      /* The insn will use virtual register numbers, and so
- 		 convert_regs is expected to process these.  But BLOCK_NUM
- 		 cannot be used on these insns, because they do not appear in
- 		 block_number[].  */
- 
- 	      pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode),
- 				 CONST0_RTX (DFmode));
- 	      init = emit_insn_after (pat, insn);
- 
- 	      CLEAR_HARD_REG_BIT (regstack->reg_set, reg);
- 
- 	      /* If the CALL_INSN was the end of a block, move the
- 		 block_end to point to the new insn.  */
- 
- 	      if (block_end[block] == insn)
- 		block_end[block] = init;
- 	    }
- 
- 	/* Some regs do not survive a CALL */
- 	AND_COMPL_HARD_REG_SET (regstack->reg_set, call_used_reg_set);
-       }
- 
-     AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
-     IOR_HARD_REG_SET (regstack->reg_set, src);
-   }
- }
- 
- /* Find all basic blocks of the function, which starts with FIRST.
-    For each JUMP_INSN, build the chain of LABEL_REFS on each CODE_LABEL.  */
- 
- static void
- find_blocks (first)
-      rtx first;
- {
-   register rtx insn;
-   register int block;
-   register RTX_CODE prev_code = BARRIER;
-   register RTX_CODE code;
-   rtx label_value_list = 0;
- 
-   /* Record where all the blocks start and end.
-      Record which basic blocks control can drop in to.  */
- 
-   block = -1;
-   for (insn = first; insn; insn = NEXT_INSN (insn))
-     {
-       /* Note that this loop must select the same block boundaries
- 	 as code in reg_to_stack, but that these are not the same
- 	 as those selected in flow.c.  */
- 
-       code = GET_CODE (insn);
- 
-       if (code == CODE_LABEL
- 	  || (prev_code != INSN
- 	      && prev_code != CALL_INSN
- 	      && prev_code != CODE_LABEL
- 	      && GET_RTX_CLASS (code) == 'i'))
- 	{
- 	  block_begin[++block] = insn;
- 	  block_end[block] = insn;
- 	  block_drops_in[block] = prev_code != BARRIER;
- 	}
-       else if (GET_RTX_CLASS (code) == 'i')
- 	block_end[block] = insn;
- 
-       if (GET_RTX_CLASS (code) == 'i')
- 	{
- 	  rtx note;
- 
- 	  /* Make a list of all labels referred to other than by jumps.  */
- 	  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- 	    if (REG_NOTE_KIND (note) == REG_LABEL)
- 	      label_value_list = gen_rtx_EXPR_LIST (VOIDmode, XEXP (note, 0),
- 						    label_value_list);
- 	}
- 
-       block_number[INSN_UID (insn)] = block;
- 
-       if (code != NOTE)
- 	prev_code = code;
-     }
- 
-   if (block + 1 != blocks)
-     abort ();
- 
-   /* generate all label references to the corresponding jump insn */
-   for (block = 0; block < blocks; block++)
-     {
-       insn = block_end[block];
- 
-       if (GET_CODE (insn) == JUMP_INSN)
- 	{
- 	  rtx pat = PATTERN (insn);
- 	  rtx x;
- 
- 	  if (computed_jump_p (insn))
- 	    {
- 	      for (x = label_value_list; x; x = XEXP (x, 1))
- 		record_label_references (insn,
- 					 gen_rtx_LABEL_REF (VOIDmode,
- 							    XEXP (x, 0)));
- 
- 	      for (x = forced_labels; x; x = XEXP (x, 1))
- 		record_label_references (insn,
- 					 gen_rtx_LABEL_REF (VOIDmode,
- 							    XEXP (x, 0)));
- 	    }
- 
- 	  record_label_references (insn, pat);
- 	}
-     }
- }
- 
  /* If current function returns its result in an fp stack register,
     return the REG.  Otherwise, return 0.  */
  
--- 1038,1043 ----
*************** stack_result (decl)
*** 1517,1691 ****
    return result != 0 && STACK_REG_P (result) ? result : 0;
  }
  
! /* Determine the which registers are live at the start of each basic
!    block of the function whose first insn is FIRST.
! 
!    First, if the function returns a real_type, mark the function
!    return type as live at each return point, as the RTL may not give any
!    hint that the register is live.
! 
!    Then, start with the last block and work back to the first block.
!    Similarly, work backwards within each block, insn by insn, recording
!    which regs are dead and which are used (and therefore live) in the
!    hard reg set of block_stack_in[].
! 
!    After processing each basic block, if there is a label at the start
!    of the block, propagate the live registers to all jumps to this block.
! 
!    As a special case, if there are regs live in this block, that are
!    not live in a block containing a jump to this label, and the block
!    containing the jump has already been processed, we must propagate this
!    block's entry register life back to the block containing the jump, and
!    restart life analysis from there.
! 
!    In the worst case, this function may traverse the insns
!    REG_STACK_SIZE times.  This is necessary, since a jump towards the end
!    of the insns may not know that a reg is live at a target that is early
!    in the insns.  So we back up and start over with the new reg live.
! 
!    If there are registers that are live at the start of the function,
!    insns are emitted to initialize these registers.  Something similar is
!    done after CALL_INSNs in record_reg_life.  */
  
! static void
! stack_reg_life_analysis (first, stackentry)
!      rtx first;
!      HARD_REG_SET *stackentry;
  {
!   int reg, block;
!   struct stack_def regstack;
  
-   {
-     rtx retvalue;
  
!     if ((retvalue = stack_result (current_function_decl)))
!       {
!         /* Find all RETURN insns and mark them.  */
  
!         for (block = blocks - 1; --block >= 0;)
! 	  if (GET_CODE (block_end[block]) == JUMP_INSN
! 	      && returnjump_p (block_end[block]))
! 	    mark_regs_pat (retvalue, block_out_reg_set+block);
! 
!         /* Mark off the end of last block if we "fall off" the end of the
! 	   function into the epilogue.  */
! 
!         if (GET_CODE (block_end[blocks-1]) != JUMP_INSN
! 	    || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN)
! 	  mark_regs_pat (retvalue, block_out_reg_set+blocks-1);
!       }
!   }
  
!   /* now scan all blocks backward for stack register use */
! 
!   block = blocks - 1;
!   while (block >= 0)
      {
-       register rtx insn, prev;
- 
        /* current register status at last instruction */
  
!       COPY_HARD_REG_SET (regstack.reg_set, block_out_reg_set[block]);
  
!       prev = block_end[block];
!       do
  	{
! 	  insn = prev;
! 	  prev = PREV_INSN (insn);
! 
! 	  /* If the insn is a CALL_INSN, we need to ensure that
! 	     everything dies.  But otherwise don't process unless there
! 	     are some stack regs present.  */
! 
! 	  if (stack_regs_mentioned (insn) || GET_CODE (insn) == CALL_INSN)
! 	    record_reg_life (insn, block, &regstack);
! 
! 	} while (insn != block_begin[block]);
! 
!       /* Set the state at the start of the block.  Mark that no
! 	 register mapping information known yet.  */
! 
!       COPY_HARD_REG_SET (block_stack_in[block].reg_set, regstack.reg_set);
!       block_stack_in[block].top = -2;
! 
!       /* If there is a label, propagate our register life to all jumps
! 	 to this label.  */
! 
!       if (GET_CODE (insn) == CODE_LABEL)
! 	{
! 	  register rtx label;
! 	  int must_restart = 0;
! 
! 	  for (label = LABEL_REFS (insn); label != insn;
! 	       label = LABEL_NEXTREF (label))
! 	    {
! 	      int jump_block = BLOCK_NUM (CONTAINING_INSN (label));
  
! 	      if (jump_block < block)
! 		IOR_HARD_REG_SET (block_out_reg_set[jump_block],
! 				  block_stack_in[block].reg_set);
! 	      else
! 		{
! 		  /* The block containing the jump has already been
! 		     processed.  If there are registers that were not known
! 		     to be live then, but are live now, we must back up
! 		     and restart life analysis from that point with the new
! 		     life information.  */
! 
! 		  GO_IF_HARD_REG_SUBSET (block_stack_in[block].reg_set,
! 					 block_out_reg_set[jump_block],
! 					 win);
  
! 		  IOR_HARD_REG_SET (block_out_reg_set[jump_block],
! 				    block_stack_in[block].reg_set);
  
- 		  block = jump_block;
- 		  must_restart = 1;
- 		  break;
  
! 		win:
! 		  ;
! 		}
! 	    }
! 	  if (must_restart)
! 	    continue;
! 	}
  
!       if (block_drops_in[block])
! 	IOR_HARD_REG_SET (block_out_reg_set[block-1],
! 			  block_stack_in[block].reg_set);
! 
!       block -= 1;
!     }
! 
!   /* If any reg is live at the start of the first block of a
!      function, then we must guarantee that the reg holds some value by
!      generating our own "load" of that register.  Otherwise a 387 would
!      fault trying to access an empty register.  */
! 
!   /* Load zero into each live register.  The fact that a register
!      appears live at the function start necessarily implies an error
!      in the user program: it means that (unless the offending code is *never*
!      executed) this program is using uninitialised floating point
!      variables.  In order to keep broken code like this happy, we initialise
!      those variables with zero.
! 
!      Note that we are inserting virtual register references here:
!      these insns must be processed by convert_regs later.  Also, these
!      insns will not be in block_number, so BLOCK_NUM() will fail for them.  */
! 
!   for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; reg--)
!     if (TEST_HARD_REG_BIT (block_stack_in[0].reg_set, reg)
!         && ! TEST_HARD_REG_BIT (*stackentry, reg))
!       {
! 	rtx init_rtx;
  
! 	init_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG(reg, DFmode),
! 				CONST0_RTX (DFmode));
! 	block_begin[0] = emit_insn_after (init_rtx, first);
  
! 	CLEAR_HARD_REG_BIT (block_stack_in[0].reg_set, reg);
!       }
  }
  
  /*
--- 1062,1136 ----
    return result != 0 && STACK_REG_P (result) ? result : 0;
  }
  
! /* This function was doing life analysis. We now use the analysis done
!    by flow.c so we only need to check some extra invariants reg-stack
!    expects (such as that all local variables are initialized).
!  
!    The function return 1 when some code was emited to graph edges
!    and commit_edge_insertions needs to be called.  */
  
! static int
! stack_reg_life_analysis ()
  {
!   int reg, blocknum;
!   int inserted = 0;
!   edge e = ENTRY_BLOCK_PTR->succ;
  
  
!   blocknum = n_basic_blocks - 1;
  
!   /* Copy flow.c life information to our structures.  Copy only
!      stack registers to make consistency checks easier.  */
  
!   while (blocknum >= 0)
      {
        /* current register status at last instruction */
  
!       block[blocknum].stack_in.top = -2;
  
!       for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
  	{
! 	  if (REGNO_REG_SET_P (BASIC_BLOCK (blocknum)->global_live_at_end, reg))
! 	    SET_HARD_REG_BIT (block[blocknum].out_reg_set, reg);
! 	  if (REGNO_REG_SET_P (BASIC_BLOCK (blocknum)->global_live_at_start, reg))
! 	    SET_HARD_REG_BIT (block[blocknum].stack_in.reg_set, reg);
! 	}
!       blocknum -= 1;
!     }
  
!   /* Load zero into each live register on the entry of function.
!      Such live registers can be caused by uninitialized variables
!      or functions not returning any value in some paths for example.
!      In order to keep i387 happy (all accesed registers must be initialized
!      for i3887), we initialise those variables by zero.
  
!      Note that we are inserting converted code here.  This code is never
!      seen by the convert_regs pass.  */
  
  
!   while (e)
!     {
!       int index = e->dest->index;
!       block[index].stack_in.top = -1;
!       for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; reg--)
! 	if (TEST_HARD_REG_BIT (block[index].stack_in.reg_set, reg))
! 	  {
! 	    rtx init_rtx;
  
! 	    block[index].stack_in.reg[++block[index].stack_in.top] = reg;
  
! 	    /* This is converted represenation ldz instruction.  So we will
! 	       have to change it once reg-stack will use other RTL
! 	       representation.  */
! 	    init_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (FIRST_STACK_REG, DFmode),
! 				    CONST0_RTX (DFmode));
! 	    insert_insn_on_edge (init_rtx, e);
  
! 	    inserted = 1;
! 	  }
!       e = e->succ_next;
!     }
!   return inserted;
  }
  
  /*
*************** emit_swap_insn (insn, regstack, reg)
*** 1846,1856 ****
    regstack->reg[other_reg] = regstack->reg[regstack->top];
    regstack->reg[regstack->top] = tmp;
  
!   /* Find the previous insn involving stack regs, but don't go past
!      any labels, calls or jumps.  */
!   i1 = prev_nonnote_insn (insn);
!   while (i1 && GET_CODE (i1) == INSN && !stack_regs_mentioned (i1))
!     i1 = prev_nonnote_insn (i1);
  
    if (i1)
      i1set = single_set (i1);
--- 1291,1305 ----
    regstack->reg[other_reg] = regstack->reg[regstack->top];
    regstack->reg[regstack->top] = tmp;
  
!   /* Find the previous insn involving stack regs, but don't pass basic
!      block boundary */
! 
!   i1 = PREV_INSN (insn);
!   while (i1 && ((GET_CODE (i1) == NOTE 
!                  && NOTE_LINE_NUMBER (i1) != NOTE_INSN_BASIC_BLOCK)
! 	        || GET_CODE (i1) == INSN)
!          && ! stack_regs_mentioned(i1))
!     i1 = PREV_INSN (i1);
  
    if (i1)
      i1set = single_set (i1);
*************** emit_swap_insn (insn, regstack, reg)
*** 1879,1885 ****
  
    swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode),
  			 FP_MODE_REG (FIRST_STACK_REG, XFmode));
!   swap_insn = emit_insn_after (swap_rtx, i1);
  }
  
  /* Handle a move to or from a stack register in PAT, which is in INSN.
--- 1328,1337 ----
  
    swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode),
  			 FP_MODE_REG (FIRST_STACK_REG, XFmode));
!   if (i1)
!     swap_insn = emit_insn_after (swap_rtx, i1);
!   else
!     swap_insn = emit_insn_before (swap_rtx, insn);
  }
  
  /* Handle a move to or from a stack register in PAT, which is in INSN.
*************** move_for_stack_reg (insn, regstack, pat)
*** 1925,1931 ****
  
  	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
  	    {
! 	      emit_pop_insn (insn, regstack, src, emit_insn_after);
  
  	      delete_insn_for_stacker (insn);
  	      return;
--- 1377,1383 ----
  
  	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
  	    {
! 	      emit_pop_insn (insn, regstack, src, emit_insn_after_bb);
  
  	      delete_insn_for_stacker (insn);
  	      return;
*************** move_for_stack_reg (insn, regstack, pat)
*** 1951,1957 ****
        if (REGNO (src) == REGNO (dest))
  	{
  	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
! 	    emit_pop_insn (insn, regstack, dest, emit_insn_after);
  
  	  delete_insn_for_stacker (insn);
  	  return;
--- 1403,1409 ----
        if (REGNO (src) == REGNO (dest))
  	{
  	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
! 	    emit_pop_insn (insn, regstack, dest, emit_insn_after_bb);
  
  	  delete_insn_for_stacker (insn);
  	  return;
*************** compare_for_stack_reg (insn, regstack, p
*** 2217,2223 ****
  	  remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0)));
  
  	  emit_pop_insn (insn, regstack, XEXP (src2_note, 0),
! 			 emit_insn_after);
  	}
      }
  }
--- 1669,1675 ----
  	  remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0)));
  
  	  emit_pop_insn (insn, regstack, XEXP (src2_note, 0),
! 			 emit_insn_after_bb);
  	}
      }
  }
*************** subst_stack_regs_pat (insn, regstack, pa
*** 2236,2241 ****
--- 1688,1711 ----
    rtx src1_note, src2_note;
    rtx pat_src;
  
+   /* Handle deads in USE insns. They can happen in non optimizing
+      compilation so handle them by popping dying register, but they
+      are nonsense in optimizing so abort in such case.  */
+   if (GET_CODE (pat) == USE)
+     {
+       src = get_true_reg (&XEXP (pat, 0));
+       if (STACK_REG_P (*src) 
+           && find_regno_note (insn, REG_DEAD, REGNO (*src)))
+         {
+ 	   if (optimize && 0)
+              abort();
+ 	   emit_pop_insn (insn, regstack, *src, emit_insn_after_bb);
+ 	   return;
+         }
+       /* Uninitialized USE may not happen (I expect).  */
+       else if (get_hard_regnum (regstack, *src) == -1)
+ 	abort();
+     }
    if (GET_CODE (pat) != SET)
      return;
  
*************** subst_stack_regs_pat (insn, regstack, pa
*** 2521,2527 ****
  		    remove_regno_note (insn, REG_DEAD,
  				       REGNO (XEXP (src_note [i], 0)));
  		    emit_pop_insn (insn, regstack, XEXP (src_note[i], 0),
! 				   emit_insn_after);
  		  }
  		else
  		  {
--- 1991,1997 ----
  		    remove_regno_note (insn, REG_DEAD,
  				       REGNO (XEXP (src_note [i], 0)));
  		    emit_pop_insn (insn, regstack, XEXP (src_note[i], 0),
! 				   emit_insn_after_bb);
  		  }
  		else
  		  {
*************** subst_asm_stack_regs (insn, regstack, op
*** 2591,2600 ****
    rtx note;
    int i;
  
    /* Find out what the constraints required.  If no constraint
       alternative matches, that is a compiler bug: we should have caught
!      such an insn during the life analysis pass (and reload should have
!      caught it regardless).  */
  
    i = constrain_asm_operands (n_operands, operands, constraints,
  			      operand_matches, operand_class);
--- 2061,2074 ----
    rtx note;
    int i;
  
+   /* ??? This checking can be done much sooner, such as in the parsing.  */
+ 
+   if (! check_asm_stack_operands (insn, operands, constraints, n_inputs, 
+ 				  n_outputs)) return;
+ 
    /* Find out what the constraints required.  If no constraint
       alternative matches, that is a compiler bug: we should have caught
!      such an insn during the reload pass.  */
  
    i = constrain_asm_operands (n_operands, operands, constraints,
  			      operand_matches, operand_class);
*************** subst_asm_stack_regs (insn, regstack, op
*** 2715,2721 ****
    /* emit insns before INSN to make sure the reg-stack is in the right
       order.  */
  
!   change_stack (insn, regstack, &temp_stack, emit_insn_before);
  
    /* Make the needed input register substitutions.  Do death notes and
       clobbers too, because these are for inputs, not outputs.  */
--- 2189,2195 ----
    /* emit insns before INSN to make sure the reg-stack is in the right
       order.  */
  
!   change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
  
    /* Make the needed input register substitutions.  Do death notes and
       clobbers too, because these are for inputs, not outputs.  */
*************** subst_asm_stack_regs (insn, regstack, op
*** 2820,2826 ****
  	      && note_kind[j] == REG_UNUSED)
  	    {
  	      insn = emit_pop_insn (insn, regstack, operands[i],
! 				    emit_insn_after);
  	      break;
  	    }
        }
--- 2294,2300 ----
  	      && note_kind[j] == REG_UNUSED)
  	    {
  	      insn = emit_pop_insn (insn, regstack, operands[i],
! 				    emit_insn_after_bb);
  	      break;
  	    }
        }
*************** subst_asm_stack_regs (insn, regstack, op
*** 2836,2842 ****
  	      && TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i])))
  	    {
  	      insn = emit_pop_insn (insn, regstack, operands[i],
! 				    emit_insn_after);
  	      break;
  	    }
        }
--- 2310,2316 ----
  	      && TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i])))
  	    {
  	      insn = emit_pop_insn (insn, regstack, operands[i],
! 				    emit_insn_after_bb);
  	      break;
  	    }
        }
*************** subst_stack_regs (insn, regstack)
*** 2935,2941 ****
      if (REG_NOTE_KIND (note) == REG_UNUSED && STACK_REG_P (XEXP (note, 0)))
        {
  	*note_link = XEXP (note, 1);
! 	insn = emit_pop_insn (insn, regstack, XEXP (note, 0), emit_insn_after);
        }
      else
        note_link = &XEXP (note, 1);
--- 2409,2422 ----
      if (REG_NOTE_KIND (note) == REG_UNUSED && STACK_REG_P (XEXP (note, 0)))
        {
  	*note_link = XEXP (note, 1);
! 	
! 	/* The REG_UNUSED notes are also generated for registers clobbered by
! 	   the insn.  Such registers are already dead, so ensure that register
! 	   we want to kill is really still alive.  */
! 
! 	if (get_hard_regnum (regstack, XEXP (note, 0)) >= FIRST_STACK_REG)
! 	  insn = emit_pop_insn (insn, regstack, XEXP (note, 0), 
! 				emit_insn_after_bb);
        }
      else
        note_link = &XEXP (note, 1);
*************** subst_stack_regs (insn, regstack)
*** 2945,2952 ****
     block.  Some registers might have to be popped, but there can never be
     a register live in the new block that is not now live.
  
!    Insert any needed insns before or after INSN.  WHEN is emit_insn_before
!    or emit_insn_after. OLD is the original stack layout, and NEW is
     the desired form.  OLD is updated to reflect the code emitted, ie, it
     will be the same as NEW upon return.
  
--- 2426,2433 ----
     block.  Some registers might have to be popped, but there can never be
     a register live in the new block that is not now live.
  
!    Insert any needed insns before or after INSN (according to EMIT_BEFORE
!    parameter). OLD is the original stack layout, and NEW is
     the desired form.  OLD is updated to reflect the code emitted, ie, it
     will be the same as NEW upon return.
  
*************** change_stack (insn, old, new, when)
*** 2958,2973 ****
       rtx insn;
       stack old;
       stack new;
!      rtx (*when)();
  {
    int reg;
  
    /* We will be inserting new insns "backwards", by calling emit_insn_before.
       If we are to insert after INSN, find the next insn, and insert before
       it.  */
  
!   if (when == emit_insn_after)
!     insn = NEXT_INSN (insn);
  
    /* Pop any registers that are not needed in the new block.  */
  
--- 2439,2461 ----
       rtx insn;
       stack old;
       stack new;
!      enum emit_when when;
  {
    int reg;
+   int update_end = 0;
  
    /* We will be inserting new insns "backwards", by calling emit_insn_before.
       If we are to insert after INSN, find the next insn, and insert before
       it.  */
  
!   /* To keep basic block boundaries consistent, we need to emit before
!      end of basic block.  So create temporary insn.  */
!   if (when == EMIT_AFTER)
!     {
!        if (current_block >= 0 && BASIC_BLOCK (current_block)->end == insn)
! 	 update_end = 1;
!        insn = NEXT_INSN (insn);
!     }
  
    /* Pop any registers that are not needed in the new block.  */
  
*************** change_stack (insn, old, new, when)
*** 3045,3174 ****
  	if (old->reg[reg] != new->reg[reg])
  	  abort ();
      }
  }
  
! /* Check PAT, which points to RTL in INSN, for a LABEL_REF.  If it is
!    found, ensure that a jump from INSN to the code_label to which the
!    label_ref points ends up with the same stack as that at the
!    code_label.  Do this by inserting insns just before the code_label to
!    pop and rotate the stack until it is in the correct order.  REGSTACK
!    is the order of the register stack in INSN.
! 
!    Any code that is emitted here must not be later processed as part
!    of any block, as it will already contain hard register numbers.  */
! 
  static void
! goto_block_pat (insn, regstack, pat)
!      rtx insn;
!      stack regstack;
!      rtx pat;
  {
!   rtx label;
!   rtx new_jump, new_label, new_barrier;
!   rtx *ref;
!   stack label_stack;
!   struct stack_def temp_stack;
!   int reg;
! 
!   switch (GET_CODE (pat))
!     {
!     case RETURN:
!       straighten_stack (PREV_INSN (insn), regstack);
!       return;
!     default:
!       {
! 	int i, j;
! 	char *fmt = GET_RTX_FORMAT (GET_CODE (pat));
! 
! 	for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
! 	  {
! 	    if (fmt[i] == 'e')
! 	      goto_block_pat (insn, regstack, XEXP (pat, i));
! 	    if (fmt[i] == 'E')
! 	      for (j = 0; j < XVECLEN (pat, i); j++)
! 		goto_block_pat (insn, regstack, XVECEXP (pat, i, j));
! 	  }
! 	return;
!       }
!     case LABEL_REF:;
!     }
! 
!   label = XEXP (pat, 0);
!   if (GET_CODE (label) != CODE_LABEL)
!     abort ();
! 
!   /* First, see if in fact anything needs to be done to the stack at all.  */
!   if (INSN_UID (label) <= 0)
      return;
! 
!   label_stack = &block_stack_in[BLOCK_NUM (label)];
! 
!   if (label_stack->top == -2)
!     {
!       /* If the target block hasn't had a stack order selected, then
! 	 we need merely ensure that no pops are needed.  */
! 
!       for (reg = regstack->top; reg >= 0; reg--)
! 	if (! TEST_HARD_REG_BIT (label_stack->reg_set, regstack->reg[reg]))
! 	  break;
! 
!       if (reg == -1)
! 	{
! 	  /* change_stack will not emit any code in this case.  */
! 
! 	  change_stack (label, regstack, label_stack, emit_insn_after);
! 	  return;
! 	}
!     }
!   else if (label_stack->top == regstack->top)
      {
!       for (reg = label_stack->top; reg >= 0; reg--)
! 	if (label_stack->reg[reg] != regstack->reg[reg])
! 	  break;
! 
!       if (reg == -1)
! 	return;
      }
- 
-   /* At least one insn will need to be inserted before label.  Insert
-      a jump around the code we are about to emit.  Emit a label for the new
-      code, and point the original insn at this new label. We can't use
-      redirect_jump here, because we're using fld[4] of the code labels as
-      LABEL_REF chains, no NUSES counters.  */
- 
-   new_jump = emit_jump_insn_before (gen_jump (label), label);
-   record_label_references (new_jump, PATTERN (new_jump));
-   JUMP_LABEL (new_jump) = label;
- 
-   new_barrier = emit_barrier_after (new_jump);
- 
-   new_label = gen_label_rtx ();
-   emit_label_after (new_label, new_barrier);
-   LABEL_REFS (new_label) = new_label;
- 
-   /* The old label_ref will no longer point to the code_label if now uses,
-      so strip the label_ref from the code_label's chain of references.  */
- 
-   for (ref = &LABEL_REFS (label); *ref != label; ref = &LABEL_NEXTREF (*ref))
-     if (*ref == pat)
-       break;
- 
-   if (*ref == label)
-     abort ();
- 
-   *ref = LABEL_NEXTREF (*ref);
- 
-   XEXP (pat, 0) = new_label;
-   record_label_references (insn, PATTERN (insn));
- 
-   if (JUMP_LABEL (insn) == label)
-     JUMP_LABEL (insn) = new_label;
- 
-   /* Now emit the needed code.  */
- 
-   temp_stack = *regstack;
- 
-   change_stack (new_label, &temp_stack, label_stack, emit_insn_after);
  }
  
  /* Traverse all basic blocks in a function, converting the register
--- 2533,2562 ----
  	if (old->reg[reg] != new->reg[reg])
  	  abort ();
      }
+   if (update_end)
+     BASIC_BLOCK (current_block)->end = PREV_INSN (insn);
  }
  
! /* Print stack configuration */
  static void
! print_stack (file,s)
! 	FILE *file;
! 	stack s;
  {
!   if (! file)
      return;
!   if (s->top == -2)
!     fprintf (file, "undefined\n");
!   else if (s->top == -1)
!     fprintf (file, "empty\n");
!   else
      {
!       int i;
!       fprintf (file, "[ ");
!       for (i = 0; i <= s->top; i++)
! 	fprintf (file, "%i ", s->reg[i]);
!       fprintf (file, "]\n");
      }
  }
  
  /* Traverse all basic blocks in a function, converting the register
*************** goto_block_pat (insn, regstack, pat)
*** 3176,3382 ****
     the stack-like registers the 387 uses.  */
  
  static void
! convert_regs ()
  {
!   register int block, reg;
    register rtx insn, next;
    struct stack_def regstack;
  
!   for (block = 0; block < blocks; block++)
      {
!       if (block_stack_in[block].top == -2)
! 	{
! 	  /* This block has not been previously encountered.  Choose a
! 	     default mapping for any stack regs live on entry */
! 
! 	  block_stack_in[block].top = -1;
  
! 	  for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; reg--)
! 	    if (TEST_HARD_REG_BIT (block_stack_in[block].reg_set, reg))
! 	      block_stack_in[block].reg[++block_stack_in[block].top] = reg;
  	}
  
!       /* Process all insns in this block.  Keep track of `next' here,
! 	 so that we don't process any insns emitted while making
! 	 substitutions in INSN.  */
! 
!       next = block_begin[block];
!       regstack = block_stack_in[block];
!       do
  	{
! 	  insn = next;
! 	  next = NEXT_INSN (insn);
  
! 	  /* Don't bother processing unless there is a stack reg
! 	     mentioned or if it's a CALL_INSN (register passing of
! 	     floating point values).  */
! 
! 	  if (stack_regs_mentioned (insn) || GET_CODE (insn) == CALL_INSN)
! 	    subst_stack_regs (insn, &regstack);
! 
! 	} while (insn != block_end[block]);
!       
!       /* For all further actions, INSN needs to be the last insn in
!          this basic block.  If subst_stack_regs inserted additional
!          instructions after INSN, it is no longer the last one at
!          this point.  */
!       next = PREV_INSN (next);
! 
!       /* If subst_stack_regs inserted something after a JUMP_INSN, that
!          is almost certainly a bug.  */
!       if (GET_CODE (insn) == JUMP_INSN && insn != next)
! 	abort ();
!       insn = next;
  
-       /* Something failed if the stack life doesn't match.  */
  
!       GO_IF_HARD_REG_EQUAL (regstack.reg_set, block_out_reg_set[block], win);
  
!       abort ();
  
!     win:
  
!       /* Adjust the stack of this block on exit to match the stack of
! 	 the target block, or copy stack information into stack of
! 	 jump target if the target block's stack order hasn't been set
! 	 yet.  */
  
!       if (GET_CODE (insn) == JUMP_INSN)
! 	goto_block_pat (insn, &regstack, PATTERN (insn));
  
!       /* Likewise handle the case where we fall into the next block.  */
  
!       if ((block < blocks - 1) && block_drops_in[block+1])
! 	change_stack (insn, &regstack, &block_stack_in[block+1],
! 		      emit_insn_after);
!     }
  
!   /* If the last basic block is the end of a loop, and that loop has
!      regs live at its start, then the last basic block will have regs live
!      at its end that need to be popped before the function returns.  */
  
!   {
!     int value_reg_low, value_reg_high;
!     value_reg_low = value_reg_high = -1;
!     {
!       rtx retvalue;
!       if ((retvalue = stack_result (current_function_decl)))
! 	{
! 	  value_reg_low = REGNO (retvalue);
! 	  value_reg_high = value_reg_low +
! 	    HARD_REGNO_NREGS (value_reg_low, GET_MODE (retvalue)) - 1;
! 	}
  
!     }
!     for (reg = regstack.top; reg >= 0; reg--)
!       if (regstack.reg[reg] < value_reg_low
! 	  || regstack.reg[reg] > value_reg_high)
! 	insn = emit_pop_insn (insn, &regstack,
! 			      FP_MODE_REG (regstack.reg[reg], DFmode),
! 			      emit_insn_after);
!   }
!   straighten_stack (insn, &regstack);
! }
! 
! /* Check expression PAT, which is in INSN, for label references.  if
!    one is found, print the block number of destination to FILE.  */
  
! static void
! print_blocks (file, insn, pat)
!      FILE *file;
!      rtx insn, pat;
! {
!   register RTX_CODE code = GET_CODE (pat);
!   register int i;
!   register char *fmt;
  
!   if (code == LABEL_REF)
!     {
!       register rtx label = XEXP (pat, 0);
  
!       if (GET_CODE (label) != CODE_LABEL)
! 	abort ();
  
!       fprintf (file, " %d", BLOCK_NUM (label));
  
!       return;
!     }
  
!   fmt = GET_RTX_FORMAT (code);
!   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
!     {
!       if (fmt[i] == 'e')
! 	print_blocks (file, insn, XEXP (pat, i));
!       if (fmt[i] == 'E')
! 	{
! 	  register int j;
! 	  for (j = 0; j < XVECLEN (pat, i); j++)
! 	    print_blocks (file, insn, XVECEXP (pat, i, j));
! 	}
!     }
! }
! 
! /* Write information about stack registers and stack blocks into FILE.
!    This is part of making a debugging dump.  */
  
! static void
! dump_stack_info (file)
!      FILE *file;
! {
!   register int block;
  
!   fprintf (file, "\n%d stack blocks.\n", blocks);
!   for (block = 0; block < blocks; block++)
!     {
!       register rtx head, jump, end;
!       register int regno;
  
!       fprintf (file, "\nStack block %d: first insn %d, last %d.\n",
! 	       block, INSN_UID (block_begin[block]),
! 	       INSN_UID (block_end[block]));
  
!       head = block_begin[block];
  
!       fprintf (file, "Reached from blocks: ");
!       if (GET_CODE (head) == CODE_LABEL)
! 	for (jump = LABEL_REFS (head);
! 	     jump != head;
! 	     jump = LABEL_NEXTREF (jump))
! 	  {
! 	    register int from_block = BLOCK_NUM (CONTAINING_INSN (jump));
! 	    fprintf (file, " %d", from_block);
  	  }
-       if (block_drops_in[block])
- 	fprintf (file, " previous");
- 
-       fprintf (file, "\nlive stack registers on block entry: ");
-       for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
- 	{
- 	  if (TEST_HARD_REG_BIT (block_stack_in[block].reg_set, regno))
- 	    fprintf (file, "%d ", regno);
- 	}
- 
-       fprintf (file, "\nlive stack registers on block exit: ");
-       for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
- 	{
- 	  if (TEST_HARD_REG_BIT (block_out_reg_set[block], regno))
- 	    fprintf (file, "%d ", regno);
  	}
! 
!       end = block_end[block];
! 
!       fprintf (file, "\nJumps to blocks: ");
!       if (GET_CODE (end) == JUMP_INSN)
! 	print_blocks (file, end, PATTERN (end));
! 
!       if (block + 1 < blocks && block_drops_in[block+1])
! 	fprintf (file, " next");
!       else if (block + 1 == blocks
! 	       || (GET_CODE (end) == JUMP_INSN
! 		   && GET_CODE (PATTERN (end)) == RETURN))
! 	fprintf (file, " return");
! 
!       fprintf (file, "\n");
      }
  }
  #endif /* STACK_REGS */
--- 2564,2872 ----
     the stack-like registers the 387 uses.  */
  
  static void
! convert_regs (file)
!      FILE *file;
  {
!   int inserted = 0;
!   int changed = 1;
!   register int blocknum, reg;
    register rtx insn, next;
    struct stack_def regstack;
+   struct stack_def output_stack;
+   int i;
+   int value_reg_low, value_reg_high;
+   rtx retvalue;
+   value_reg_low = value_reg_high = -1;
  
!   inserted = stack_reg_life_analysis ();
!   if ((retvalue = stack_result (current_function_decl)))
      {
!       value_reg_low = REGNO (retvalue);
!       value_reg_high = value_reg_low +
! 	HARD_REGNO_NREGS (value_reg_low, GET_MODE (retvalue)) - 1;
!     }
  
!   bzero ((char *) &output_stack, sizeof (output_stack));
!   if (value_reg_low == -1)
!     output_stack.top = -1;
!   else
!     {
!       output_stack.top = value_reg_high - value_reg_low;
!       for (i = value_reg_low; i <= value_reg_high; i++)
! 	{
! 	  output_stack.reg[i - value_reg_low] = i;
! 	  SET_HARD_REG_BIT (output_stack.reg_set, i);
  	}
+     }
+   if (file)
+     {
+       fprintf (file, "; Output stack configuration :");
+       print_stack (file, &output_stack);
+     }
  
!   /* We iterate over the graph and convert the reached edges. The changed
!      value is set to 1 before entering the loop.  Then cleared and reset
!      in case internal loop handled some new blocks.  If it is still 0
!      on the end of internal loop, we set it to -1 to indicate that we are
!      in the last turn.  In this turn we convert all unreachable blocks to
!      keep output routine happy.  */
!   while (changed)
!     {
!       if (changed != -1)
! 	changed = 0;
!       for (blocknum = 0; blocknum < n_basic_blocks; blocknum++)
  	{
! 	  if (block[blocknum].done)
! 	    continue;
! 	  current_block = blocknum;
! 	  if (file)
! 	    {
! 	      fprintf (file, "; Basic block %i\n\n; input stack:", blocknum);
! 	      print_stack (file, &block[blocknum].stack_in);
! 	    }
! 	  if (block[blocknum].stack_in.top == -2)
! 	    {
! 	      edge e = BASIC_BLOCK (blocknum)->pred;
! 	      /* This block has not been previously encountered.  
! 	         Check whether it is an entry block.  If so, choose a
! 	         default mapping for any stack regs live on entry.
! 	         Otherwise delay it and process in later iterations.
! 	         (this can avoid unnecesary stack reorders) */
! 
! 	      while (e && e->src != ENTRY_BLOCK_PTR)
! 		e = e->pred_next;
! 	      if (optimize && ! e && changed != -1)
! 		continue;
! 
! 	      block[blocknum].stack_in.top = -1;
! 
! 	      for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; reg--)
! 		if (TEST_HARD_REG_BIT (block[blocknum].stack_in.reg_set, reg))
! 		  block[blocknum].stack_in.reg[++block[blocknum].stack_in.top] = reg;
! 	    }
  
! 	  /* Avoid processing block twice */
! 	  block[blocknum].done = 1;
! 	  if (! changed)
! 	    changed = 1;
! 
! 	  /* Process all insns in this block.  Keep track of `next' here,
! 	     so that we don't process any insns emitted while making
! 	     substitutions in INSN.  */
  
  
! 	  next = BASIC_BLOCK (blocknum)->head;
! 	  regstack = block[blocknum].stack_in;
! 	  do
! 	    {
! 	      insn = next;
! 	      next = NEXT_INSN (insn);
  
! 	      /* Ensure that we have not missed basic block boundary */
! 	      if (next == NULL)
! 		abort ();
! 	      if (insn == BASIC_BLOCK (blocknum)->end)
! 		next = NULL;
  
! 	      /* Don't bother processing unless there is a stack reg
! 	         mentioned or if it's a CALL_INSN (register passing of
! 	         floating point values).  */
  
! 	      if (stack_regs_mentioned (insn) || GET_CODE (insn) == CALL_INSN)
! 		{
! 		  if (file)
! 		    {
! 		      fprintf (file, "; insn: %i input stack:", INSN_UID (insn));
! 		      print_stack (file, &regstack);
! 		    }
! 		  subst_stack_regs (insn, &regstack);
! 		}
! 	    }
! 	  while (next);
  
! 	  if (file)
! 	    {
! 	      int i;
! 	      fprintf (file, "; expected live registers [");
! 	      for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
! 		if (TEST_HARD_REG_BIT (block[blocknum].out_reg_set, i))
! 		  fprintf (file, " %i", i);
! 	      fprintf (file, " ]\n; output stack:");
! 	      print_stack (file, &regstack);
! 	      fprintf (file, "\n");
! 	    }
  
! 	  insn = BASIC_BLOCK (blocknum)->end;
! 	  if (GET_CODE (insn) == JUMP_INSN)
! 	    insn = PREV_INSN (insn);
  
! 	  /* if function is declared to return value, but returns it
! 	     only in some cases, some registers might become live here.
! 	     Emit necesary moves for them. */
  
! 	  for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
! 	    {
! 	      if (TEST_HARD_REG_BIT (block[blocknum].out_reg_set, i)
! 		  && ! TEST_HARD_REG_BIT (regstack.reg_set, i))
! 		{
! 		  if (file)
! 		    {
! 		      fprintf (file, "; Emiting insn (to initialize uninitialized reg %i) input stack:", i);
! 		      print_stack (file, &regstack);
! 		    }
! 		  insn = emit_insn_after_bb (
! 			     gen_rtx_SET (VOIDmode, FP_MODE_REG (i, DFmode),
! 					  CONST0_RTX (DFmode)),
! 					      insn);
! 		  subst_stack_regs (insn, &regstack);
  
! 		}
! 	    }
! 	  /* Something failed if the stack life doesn't match.  */
  
! 	  GO_IF_HARD_REG_EQUAL (regstack.reg_set, block[blocknum].out_reg_set,
! 			        win);
  
! 	  abort ();
  
! 	win:
  
! 	  /* Adjust the stack of this block on exit to match the stack of
! 	     the target block, or copy stack information into stack of
! 	     jump target if the target block's stack order hasn't been set
! 	     yet.  */
  
! 	  {
! 	    edge e = BASIC_BLOCK (blocknum)->succ;
! 	    while (e)
! 	      {
! 		stack target_stack;
! 		basic_block target = e->dest;
  
! 		if (target == EXIT_BLOCK_PTR)
! 		  target_stack = &output_stack;
! 		else
! 		  target_stack = &block[target->index].stack_in;
  
! 		if (file)
! 		  fprintf (file, "; Edge to block %i:", target->index);
  
! 		if (target_stack->top == -2)
! 		  {
! 		    /* If the target block hasn't had a stack order selected,
! 		       then we need merely ensure that no pops are needed.  */
  
! 		    for (reg = regstack.top; reg >= 0; reg--)
! 		      if (! TEST_HARD_REG_BIT (target_stack->reg_set, 
! 					       regstack.reg[reg]))
! 			break;
! 
! 		    if (reg == -1)
! 		      {
! 			/* change_stack kills values in regstack */
! 			struct stack_def regs = regstack;
! 			/* change_stack will not emit any code in this case.  */
! 
! 			if (file)
! 			  fprintf (file, "New block - copying stack position\n");
! 
! 			change_stack (BASIC_BLOCK (blocknum)->end, &regs,
! 				      target_stack, EMIT_AFTER);
! 			e = e->succ_next;
! 			continue;
! 		      }
! 		    if (file)
! 		      fprintf (file, "New block - pops needed - ");
! 		  }
! 		else if (target_stack->top == regstack.top)
! 		  {
! 		    for (reg = target_stack->top; reg >= 0; reg--)
! 		      if (target_stack->reg[reg] != regstack.reg[reg])
! 			break;
! 
! 		    if (reg == -1)
! 		      {
! 			if (file)
! 			  fprintf (file, "No changes needed\n");
! 			e = e->succ_next;
! 			continue;
! 		      }
! 		  }
! 		if (file)
! 		  {
! 		    fprintf (file, "correcting stack to: ");
! 		    print_stack (file, target_stack);
! 		  }
  
! 		/* It is better to output directly to the end of the block
! 		   instead to the edge, because emit_swap can schedule insns */
  
! 		if (e->succ_next == NULL && BASIC_BLOCK (blocknum)->succ == e 
! 		    && !(e->flags & EDGE_ABNORMAL))
! 		  {
! 		    /* change_stack kills values in regstack */
! 		    struct stack_def regs = regstack;
! 		    if (file)
! 		      fprintf (file, "; (on the end of basic block)\n");
! 		    if (GET_CODE (BASIC_BLOCK (blocknum)->end) == JUMP_INSN)
! 		      change_stack (BASIC_BLOCK (blocknum)->end, &regs,
! 				    target_stack, EMIT_BEFORE);
! 		    else
! 		      change_stack (BASIC_BLOCK (blocknum)->end, &regs,
! 				    target_stack, EMIT_AFTER);
! 		  }
! 		else
! 		  {
! 		    rtx seq;
! 		    rtx after;
! 		    /* change_stack kills values in regstack */
! 		    struct stack_def regs = regstack;
! 
! 		    /* We don't support abnormal critical edges. Global.c
! 		       takes care to avoid any live registers on them, so we
! 		       might never get here.  */
! 
! 		    if ((e->flags & (EDGE_ABNORMAL | EDGE_CRITICAL))
! 			== (EDGE_ABNORMAL | EDGE_CRITICAL))
! 			abort ();
! 
! 		    current_block = -1;
! 		    start_sequence ();
! 
! 		    /* Ugly...hmm... but change_stack needs some point to
! 		       emit insns after.  */
! 
! 		    after = emit_note (NULL, NOTE_INSN_DELETED);
! 		    change_stack (after, &regs, target_stack, EMIT_BEFORE);
! 
! 		    /* We need to keep at least one note there, otherwise
! 		       in case change_stack generated exactly one insn,
! 		       gen_sequence attempts to avoid generating sequence
! 		       and strips reg_dead notes.  We can re-enable deleting
! 		       once reg_dead notes abuse is fixed.  */
! 
! 		    /*remove_insn (after); */
! 		    seq = gen_sequence ();
! 		    end_sequence ();
! 
! 		    if (file)
! 		      fprintf (file, "(on the edge)\n");
! 		    insert_insn_on_edge (seq, e);
! 		    inserted = 1;
! 		    current_block = blocknum;
! 		  }
  
! 		e = e->succ_next;
! 	      }
  	  }
  	}
!       if (changed == -1)
! 	changed = 0;
!       else if (! changed)
! 	changed = -1;
      }
+ 
+   if (inserted)
+     commit_edge_insertions ();
  }
  #endif /* STACK_REGS */
*** global.c.orig	Fri Feb 26 00:45:19 1999
--- global.c	Fri Jul  2 09:53:45 1999
*************** global_conflicts ()
*** 673,686 ****
  #ifdef STACK_REGS
  	{
  	  /* Pseudos can't go in stack regs at the start of a basic block
! 	     that can be reached through a computed goto, since reg-stack
! 	     can't handle computed gotos.  */
! 	  /* ??? Seems more likely that reg-stack can't handle any abnormal
! 	     edges, critical or not, computed goto or otherwise.  */
  
  	  edge e;
  	  for (e = BASIC_BLOCK (b)->pred; e ; e = e->pred_next)
! 	    if (e->flags & EDGE_ABNORMAL)
  	      break;
  
  	  if (e != NULL)
--- 673,684 ----
  #ifdef STACK_REGS
  	{
  	  /* Pseudos can't go in stack regs at the start of a basic block
! 	     that is reached by abnormal critical edge.  */
  
  	  edge e;
  	  for (e = BASIC_BLOCK (b)->pred; e ; e = e->pred_next)
! 	    if ((e->flags & (EDGE_ABNORMAL | EDGE_CRITICAL))
! 		== (EDGE_ABNORMAL | EDGE_CRITICAL))
  	      break;
  
  	  if (e != NULL)
*** expr.c.orig	Mon May 17 09:21:14 1999
--- expr.c	Fri Jul  2 09:50:57 1999
*************** expand_builtin_apply_args ()
*** 9884,9896 ****
  
  	tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
  
- #ifdef STACK_REGS
-         /* For reg-stack.c's stack register household.
- 	   Compare with a similar piece of code in function.c.  */
- 
-         emit_insn (gen_rtx_USE (mode, tem));
- #endif
- 
  	emit_move_insn (change_address (registers, mode,
  					plus_constant (XEXP (registers, 0),
  						       size)),
--- 9884,9889 ----
*** function.c.orig	Fri May 21 00:22:34 1999
--- function.c	Fri Jul  2 09:51:33 1999
*************** assign_parms (fndecl, second_time)
*** 4647,4663 ****
  	}
  #endif /* 0 */
  
- #ifdef STACK_REGS
-       /* We need this "use" info, because the gcc-register->stack-register
- 	 converter in reg-stack.c needs to know which registers are active
- 	 at the start of the function call.  The actual parameter loading
- 	 instructions are not always available then anymore, since they might
- 	 have been optimised away.  */
- 
-       if (GET_CODE (entry_parm) == REG && !(hide_last_arg && last_named))
- 	  emit_insn (gen_rtx_USE (GET_MODE (entry_parm), entry_parm));
- #endif
- 
        /* ENTRY_PARM is an RTX for the parameter as it arrives,
  	 in the mode in which it arrives.
  	 STACK_PARM is an RTX for a stack slot where the parameter can live
--- 4647,4652 ----


More information about the Gcc-patches mailing list