Reg stack improvement/cleanup

Jan Hubicka hubicka@atrey.karlin.mff.cuni.cz
Sat Oct 30 16:13:00 GMT 1999


Hi
This patch takes some fruits from the new flow implementation.
It splits out the global stuff from basic conversion - the blocks are
put together in separate pass.
This adds some flexibility. Basically I can change the basic block
interface to fit my needs, as Richard suggested about loop.
Also I can output common code for all edges to the end of basic block.
This is actually much smarter than jump, because it results in different
common code, so jump is unable to do it.

I've also added code to collect information about transparency of the
block. This can be used by future global optimizer (in long term I would
like to split out the analysys from real reg-stacking so I can first
do the analysis, then decide interfaces and then do the real conversion).
For now the the transparency info is used by emit_swap_insn.
I've already made simple global optimizer for swaps. I will send this 
code later.

Note that I am not much statisfied by the way fixed_regs is handled currently,
but it may be easier to change once the replacing code is cleaned up.

Fri Oct 30 17:44:30 CEST 1999  Jan Hubicka  <hubicka@freesoft.cz>
	* reg-stack.c (struct block_info_def): New fields fixed_regs,
	stack_out and rename.
	(emit_swap_insn): New "final" parameter, update basic block info
	to avoid fxch.
	(change_stack): Likewise, update call of change_to_regmap.
	(change_to_regmap): Likewise, update call of emit_swap_insn.
	(emit_basic_block_corrections): New.
	(emit_common_basic_block_corrections): New.
	(convert_regs_1): Do not return integer, do not emit correction code,
	initialize rename map.
	(straighten_stack): Update call of emit_swap_insn.
	(compare_for_stack_reg): Likewise.
	(subst_stack_regs_pat): Likewise.
	(move_for_stack_reg): Likewise; update rename map, propagate fixed regs,
	(subst_asm_stack_regs): Update call of change_to_regmap.
	(replace_reg): Set register as fixed.
	(emit_pop_insn): Likewise.
	(find_common_map): New function.
	(remove_incomplette_cycles): New function.
	(convert_regs): Call emit_common_basic_block_corrections
	and emit_basic_block_corrections.



*** reg-stack.c.old1	Sat Oct 30 17:39:39 1999
--- reg-stack.c	Sat Oct 30 17:40:31 1999
*************** typedef struct stack_def
*** 193,199 ****
--- 193,204 ----
  typedef struct block_info_def
  {
    struct stack_def stack_in;	/* Input stack configuration.  */
+   struct stack_def stack_out;	/* Output stack configuration.  */
    HARD_REG_SET out_reg_set;	/* Stack regs live on output.  */
+   HARD_REG_SET fixed_regs;	/* Set for registers that must appear at
+ 				   position given by stack_out.  */
+   char rename[REG_STACK_SIZE];  /* This map is used to keep track of renames
+ 				   done by reg-reg with REG_DEAD note.  */
    int done;			/* True if block already converted.  */
  } *block_info;
  
*************** static int get_hard_regnum		PROTO((stack
*** 243,249 ****
  static void delete_insn_for_stacker	PROTO((rtx));
  static rtx emit_pop_insn		PROTO((rtx, stack, rtx,
  					       enum emit_where));
! static void emit_swap_insn		PROTO((rtx, stack, rtx));
  static void move_for_stack_reg		PROTO((rtx, stack, rtx));
  static int swap_rtx_condition_1		PROTO((rtx));
  static int swap_rtx_condition		PROTO((rtx));
--- 248,254 ----
  static void delete_insn_for_stacker	PROTO((rtx));
  static rtx emit_pop_insn		PROTO((rtx, stack, rtx,
  					       enum emit_where));
! static void emit_swap_insn		PROTO((rtx, stack, rtx, int));
  static void move_for_stack_reg		PROTO((rtx, stack, rtx));
  static int swap_rtx_condition_1		PROTO((rtx));
  static int swap_rtx_condition		PROTO((rtx));
*************** static void subst_stack_regs_pat	PROTO((
*** 252,265 ****
  static void subst_asm_stack_regs	PROTO((rtx, stack));
  static void subst_stack_regs		PROTO((rtx, stack));
  static int change_stack			PROTO((rtx, stack, stack,
! 					       enum emit_where));
  static int change_to_regmap		PROTO((rtx, stack, int *,
! 					       enum emit_where));
  static int convert_regs_entry		PROTO((void));
  static void convert_regs_exit		PROTO((void));
! static int convert_regs_1		PROTO((FILE *, basic_block));
  static int convert_regs_2		PROTO((FILE *, basic_block));
  static int convert_regs			PROTO((FILE *));
  static void print_stack 		PROTO((FILE *, stack));
  
  /* Return non-zero if any stack register is mentioned somewhere within PAT.  */
--- 257,272 ----
  static void subst_asm_stack_regs	PROTO((rtx, stack));
  static void subst_stack_regs		PROTO((rtx, stack));
  static int change_stack			PROTO((rtx, stack, stack,
! 					       enum emit_where, int));
  static int change_to_regmap		PROTO((rtx, stack, int *,
! 					       enum emit_where, int));
  static int convert_regs_entry		PROTO((void));
  static void convert_regs_exit		PROTO((void));
! static void convert_regs_1		PROTO((FILE *, basic_block));
  static int convert_regs_2		PROTO((FILE *, basic_block));
  static int convert_regs			PROTO((FILE *));
+ static int emit_basic_block_corrections PROTO((FILE *));
+ static int emit_common_basic_block_corrections PROTO((FILE *));
  static void print_stack 		PROTO((FILE *, stack));
  
  /* Return non-zero if any stack register is mentioned somewhere within PAT.  */
*************** straighten_stack (insn, regstack)
*** 375,381 ****
    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 */
--- 377,383 ----
    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, 0);
  }
  
  /* Pop a register from the stack */
--- 499,504 ----
*************** replace_reg (reg, regno)
*** 832,837 ****
--- 780,788 ----
        || ! STACK_REG_P (*reg))
      abort ();
  
+   /* Mark register fixed.  */
+   SET_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs, true_regnum (*reg));
+ 
    switch (GET_MODE_CLASS (GET_MODE (*reg)))
      {
      default: abort ();
*************** get_hard_regnum (regstack, reg)
*** 889,896 ****
  }
  
  /* Delete INSN from the RTL.  Mark the insn, but don't remove it from
!    the chain of insns.  Doing so could confuse block_begin and block_end
!    if this were the only insn in the block.  */
  
  static void
  delete_insn_for_stacker (insn)
--- 840,846 ----
  }
  
  /* Delete INSN from the RTL.  Mark the insn, but don't remove it from
!    the chain of insns.  Doing so could confuse CFG. */
  
  static void
  delete_insn_for_stacker (insn)
*************** emit_pop_insn (insn, regstack, reg, wher
*** 923,928 ****
--- 873,882 ----
    if (hard_regno < FIRST_STACK_REG)
      abort ();
  
+   /* mark popped register as fixed.  */
+   if (current_block)
+     SET_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs, true_regnum (reg));
+ 
    pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
  			 FP_MODE_REG (FIRST_STACK_REG, DFmode));
  
*************** emit_pop_insn (insn, regstack, reg, wher
*** 948,964 ****
     is updated to reflect the swap.  A swap insn is represented as a
     PARALLEL of two patterns: each pattern moves one reg to the other.
  
!    If REG is already at the top of the stack, no insn is emitted.  */
  
  static void
! emit_swap_insn (insn, regstack, reg)
       rtx insn;
       stack regstack;
       rtx reg;
  {
    int hard_regno;
    rtx swap_rtx;
!   int tmp, other_reg;		/* swap regno temps */
    rtx i1;			/* the stack-reg insn prior to INSN */
    rtx i1set = NULL_RTX;		/* the SET rtx within I1 */
  
--- 902,921 ----
     is updated to reflect the swap.  A swap insn is represented as a
     PARALLEL of two patterns: each pattern moves one reg to the other.
  
!    If REG is already at the top of the stack, no insn is emitted.
!    If FINAL is not set, swap insn is allowed to do changes in the basic
!    block interface.  */
  
  static void
! emit_swap_insn (insn, regstack, reg, final)
       rtx insn;
       stack regstack;
       rtx reg;
+      int final;
  {
    int hard_regno;
    rtx swap_rtx;
!   int other_regno, other_reg;	/* swap regno temps */
    rtx i1;			/* the stack-reg insn prior to INSN */
    rtx i1set = NULL_RTX;		/* the SET rtx within I1 */
  
*************** emit_swap_insn (insn, regstack, reg)
*** 971,979 ****
  
    other_reg = regstack->top - (hard_regno - FIRST_STACK_REG);
  
!   tmp = regstack->reg[other_reg];
!   regstack->reg[other_reg] = regstack->reg[regstack->top];
!   regstack->reg[regstack->top] = tmp;
  
    /* Find the previous insn involving stack regs, but don't pass a
       block boundary.  */
--- 928,963 ----
  
    other_reg = regstack->top - (hard_regno - FIRST_STACK_REG);
  
!   other_regno = regstack->reg[regstack->top];
!   regstack->reg[regstack->top] = regstack->reg[other_reg];
!   regstack->reg[other_reg] = other_regno;
! 
!   /* Attempt to solve swap by changing input permutation.  */
!   if (!final
!       && !TEST_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs, other_regno)
!       && !TEST_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs,
! 			     REGNO (reg)))
!     {
!       block_info bi = BLOCK_INFO (current_block);
!       int src = bi->rename[other_regno - FIRST_STACK_REG];
!       int dest = bi->rename[REGNO (reg) - FIRST_STACK_REG];
!       int i;
! 
!       /* If none of operands is top of stack, we may change one fxch to two.
!          ??? This test can be more curefull later.  */
!       if (bi->stack_in.reg [bi->stack_in.top] == src
! 	  || bi->stack_in.reg [bi->stack_in.top] == dest)
! 	{
! 	  for (i = 0; i <= bi->stack_in.top; i++)
! 	    {
! 	      if (bi->stack_in.reg[i] == src)
! 		bi->stack_in.reg[i] = dest;
! 	      else if (bi->stack_in.reg[i] == dest)
! 		bi->stack_in.reg[i] = src;
! 	    }
! 	  return;
! 	}
!     }
  
    /* Find the previous insn involving stack regs, but don't pass a
       block boundary.  */
*************** move_for_stack_reg (insn, regstack, pat)
*** 1045,1050 ****
--- 1029,1035 ----
    rtx *psrc =  get_true_reg (&SET_SRC (pat));
    rtx *pdest = get_true_reg (&SET_DEST (pat));
    rtx src, dest;
+   int ren;
    rtx note;
  
    src = *psrc; dest = *pdest;
*************** move_for_stack_reg (insn, regstack, pat)
*** 1089,1094 ****
--- 1074,1089 ----
  
  	  delete_insn_for_stacker (insn);
  
+ 	  /* Update rename map and propagate fixed register flag.  */
+ 
+ 	  ren = BLOCK_INFO (current_block)->rename[REGNO (src) - FIRST_STACK_REG];
+ 
+ 	  BLOCK_INFO (current_block)->rename[REGNO (dest) - FIRST_STACK_REG] 
+ 	   = ren;
+ 	  if (TEST_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs, ren))
+ 	    SET_HARD_REG_BIT (BLOCK_INFO (current_block)->fixed_regs,
+ 			      REGNO (dest));
+ 
  	  return;
  	}
  
*************** move_for_stack_reg (insn, regstack, pat)
*** 1124,1130 ****
  	 only top of stack may be saved, emit an exchange first if
  	 needs be.  */
  
!       emit_swap_insn (insn, regstack, src);
  
        note = find_regno_note (insn, REG_DEAD, REGNO (src));
        if (note)
--- 1119,1125 ----
  	 only top of stack may be saved, emit an exchange first if
  	 needs be.  */
  
!       emit_swap_insn (insn, regstack, src, 0);
  
        note = find_regno_note (insn, REG_DEAD, REGNO (src));
        if (note)
*************** compare_for_stack_reg (insn, regstack, p
*** 1325,1331 ****
    else
      src2_note = NULL_RTX;
  
!   emit_swap_insn (insn, regstack, *src1);
  
    replace_reg (src1, FIRST_STACK_REG);
  
--- 1315,1321 ----
    else
      src2_note = NULL_RTX;
  
!   emit_swap_insn (insn, regstack, *src1, 0);
  
    replace_reg (src1, FIRST_STACK_REG);
  
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1489,1495 ****
  	    if (src1 == 0)
  	      src1 = get_true_reg (&XEXP (pat_src, 0));
  
! 	    emit_swap_insn (insn, regstack, *src1);
  
  	    src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
  
--- 1479,1485 ----
  	    if (src1 == 0)
  	      src1 = get_true_reg (&XEXP (pat_src, 0));
  
! 	    emit_swap_insn (insn, regstack, *src1, 0);
  
  	    src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
  
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1536,1542 ****
  	       must be top of stack.  */
  
  	    if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2))
! 	      emit_swap_insn (insn, regstack, *dest);
  	    else
  	      {
  		/* Both operands are REG.  If neither operand is already
--- 1526,1532 ----
  	       must be top of stack.  */
  
  	    if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2))
! 	      emit_swap_insn (insn, regstack, *dest, 0);
  	    else
  	      {
  		/* Both operands are REG.  If neither operand is already
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1552,1558 ****
  
  		if (src1_hard_regnum != FIRST_STACK_REG
  		    && src2_hard_regnum != FIRST_STACK_REG)
! 		  emit_swap_insn (insn, regstack, *dest);
  	      }
  
  	    if (STACK_REG_P (*src1))
--- 1542,1548 ----
  
  		if (src1_hard_regnum != FIRST_STACK_REG
  		    && src2_hard_regnum != FIRST_STACK_REG)
! 		  emit_swap_insn (insn, regstack, *dest, 0);
  	      }
  
  	    if (STACK_REG_P (*src1))
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1631,1637 ****
  
  		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
  
! 		emit_swap_insn (insn, regstack, *src1);
  
  		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
  
--- 1621,1627 ----
  
  		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
  
! 		emit_swap_insn (insn, regstack, *src1, 0);
  
  		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
  
*************** subst_stack_regs_pat (insn, regstack, pa
*** 1687,1693 ****
  	       have to handle it here. */
  	    if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
  		&& REGNO (*dest) != regstack->reg[regstack->top])
! 	      emit_swap_insn (insn, regstack, *dest);	
  
  	    src1 = get_true_reg (&XEXP (pat_src, 1));
  	    src2 = get_true_reg (&XEXP (pat_src, 2));
--- 1677,1683 ----
  	       have to handle it here. */
  	    if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
  		&& REGNO (*dest) != regstack->reg[regstack->top])
! 	      emit_swap_insn (insn, regstack, *dest, 0);
  
  	    src1 = get_true_reg (&XEXP (pat_src, 1));
  	    src2 = get_true_reg (&XEXP (pat_src, 2));
*************** subst_asm_stack_regs (insn, regstack)
*** 1897,1903 ****
    /* Emit insns before INSN to make sure the reg-stack is in the right
       order.  */
  
!   change_to_regmap (insn, regstack, regmap, EMIT_BEFORE);
  
    /* Make the needed input register substitutions.  Do death notes and
       clobbers too, because these are for inputs, not outputs.  */
--- 1887,1893 ----
    /* Emit insns before INSN to make sure the reg-stack is in the right
       order.  */
  
!   change_to_regmap (insn, regstack, regmap, EMIT_BEFORE, 0);
  
    /* Make the needed input register substitutions.  Do death notes and
       clobbers too, because these are for inputs, not outputs.  */
*************** find_path (registermap, s)
*** 2177,2187 ****
     interface.
   */
  static int
! change_to_regmap (insn, old, regmap, where)
       rtx insn;
       stack old;
       int *regmap;
       enum emit_where where;
  {
    int update_end = 0;
    int ninsns = 0;
--- 2167,2178 ----
     interface.
   */
  static int
! change_to_regmap (insn, old, regmap, where, final)
       rtx insn;
       stack old;
       int *regmap;
       enum emit_where where;
+      int final;
  {
    int update_end = 0;
    int ninsns = 0;
*************** change_to_regmap (insn, old, regmap, whe
*** 2237,2243 ****
  	}
  
        if (regmap[(int) old->reg[newpos]] != -1)
! 	emit_swap_insn (insn, old, FP_MODE_REG (old->reg[newpos], DFmode));
        else
  	emit_pop_insn (insn, old, FP_MODE_REG (old->reg[newpos], DFmode), EMIT_BEFORE);
        ninsns++;
--- 2228,2234 ----
  	}
  
        if (regmap[(int) old->reg[newpos]] != -1)
! 	emit_swap_insn (insn, old, FP_MODE_REG (old->reg[newpos], DFmode), final);
        else
  	emit_pop_insn (insn, old, FP_MODE_REG (old->reg[newpos], DFmode), EMIT_BEFORE);
        ninsns++;
*************** change_to_regmap (insn, old, regmap, whe
*** 2257,2269 ****
     WHERE.  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.
   */
  static int
! change_stack (insn, old, new, where)
       rtx insn;
       stack old;
       stack new;
       enum emit_where where;
  {
    int reg;
    int ninsns = 0;
--- 2248,2264 ----
     WHERE.  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.
+ 
+    When final is nonzero, change_stack is not allowed to modify basic block
+    interface.
   */
  static int
! change_stack (insn, old, new, where, final)
       rtx insn;
       stack old;
       stack new;
       enum emit_where where;
+      int final;
  {
    int reg;
    int ninsns = 0;
*************** win1:
*** 2282,2288 ****
    for (reg = 0 ; reg <= new->top ; reg++)
      regmap [(int) new->reg[reg]] = reg;
  
!   ninsns = change_to_regmap (insn, old, regmap, where);
  
    GO_IF_HARD_REG_EQUAL (old->reg_set, new->reg_set, win2);
    abort ();
--- 2277,2283 ----
    for (reg = 0 ; reg <= new->top ; reg++)
      regmap [(int) new->reg[reg]] = reg;
  
!   ninsns = change_to_regmap (insn, old, regmap, where, final);
  
    GO_IF_HARD_REG_EQUAL (old->reg_set, new->reg_set, win2);
    abort ();
*************** convert_regs_exit ()
*** 2428,2451 ****
  
  /* Convert stack register references in one block.  */
  
! static int
  convert_regs_1 (file, block)
       FILE *file;
       basic_block block;
  {
!   struct stack_def regstack, tmpstack;
    block_info bi = BLOCK_INFO (block);
!   int inserted, reg;
    rtx insn, next;
    edge e;
  
    current_block = block;
!   
    if (file)
      {
!       fprintf (file, "\nBasic block %d\nInput stack: ", block->index);
        print_stack (file, &bi->stack_in);
      }
  
    /* Process all insns in this block.  Keep track of NEXT so that we
       don't process insns emitted while substituting in INSN.  */
--- 2423,2449 ----
  
  /* Convert stack register references in one block.  */
  
! static void
  convert_regs_1 (file, block)
       FILE *file;
       basic_block block;
  {
!   struct stack_def regstack;
    block_info bi = BLOCK_INFO (block);
!   int reg;
    rtx insn, next;
    edge e;
+   int i;
  
    current_block = block;
! 
    if (file)
      {
!       fprintf (file, "\nBasic block %d\n Proposed input stack: ", block->index);
        print_stack (file, &bi->stack_in);
      }
+   for (i = 0 ; i < REG_STACK_SIZE ; i++)
+     bi->rename[i]=i+FIRST_STACK_REG;
  
    /* Process all insns in this block.  Keep track of NEXT so that we
       don't process insns emitted while substituting in INSN.  */
*************** convert_regs_1 (file, block)
*** 2480,2490 ****
  
    if (file)
      {
!       fprintf (file, "Expected live registers [");
        for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
  	if (TEST_HARD_REG_BIT (bi->out_reg_set, reg))
  	  fprintf (file, " %d", reg);
!       fprintf (file, " ]\nOutput stack: ");
        print_stack (file, &regstack);
      }
  
--- 2478,2490 ----
  
    if (file)
      {
!       fprintf (file, " Expected live registers [");
        for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
  	if (TEST_HARD_REG_BIT (bi->out_reg_set, reg))
  	  fprintf (file, " %d", reg);
!       fprintf (file, " ]\n Input stack: ");
!       print_stack (file, &bi->stack_in);
!       fprintf (file, " Output stack: ");
        print_stack (file, &regstack);
      }
  
*************** convert_regs_1 (file, block)
*** 2499,2505 ****
    for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
      {
        if (TEST_HARD_REG_BIT (bi->out_reg_set, reg)
! 	  && ! TEST_HARD_REG_BIT (regstack.reg_set, reg))
  	{
  	  rtx set;
  
--- 2499,2505 ----
    for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
      {
        if (TEST_HARD_REG_BIT (bi->out_reg_set, reg)
! 	  && !TEST_HARD_REG_BIT (regstack.reg_set, reg))
  	{
  	  rtx set;
  
*************** convert_regs_1 (file, block)
*** 2519,2569 ****
    /* Something failed if the stack lives don't match.  */
    GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->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 info into the stack of the successor
       of the successor hasn't been processed yet.  */
!   inserted = 0;
!   for (e = block->succ; e ; e = e->succ_next)
      {
        basic_block target = e->dest;
        stack target_stack = &BLOCK_INFO (target)->stack_in;
  
-       if (file)
- 	fprintf (file, "Edge to block %d: ", target->index);
- 
        if (target_stack->top == -2)
  	{
  	  /* The target block hasn't had a stack order selected.
! 	     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)
! 	    {
! 	      if (file)
! 		fprintf (file, "new block; copying stack position\n");
  
! 	      /* change_stack kills values in regstack.  */
! 	      tmpstack = regstack;
  
! 	      change_stack (block->end, &tmpstack,
! 			    target_stack, EMIT_AFTER);
! 	      continue;
! 	    }
  
! 	  if (file)
! 	    fprintf (file, "new block; pops needed\n");
  	}
!       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)
--- 2519,2691 ----
    /* Something failed if the stack lives don't match.  */
    GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
    abort ();
! win:
  
!   /* copy stack info into the stack of the successor
       of the successor hasn't been processed yet.  */
! 
!   for (e = block->succ; e; e = e->succ_next)
      {
        basic_block target = e->dest;
        stack target_stack = &BLOCK_INFO (target)->stack_in;
  
        if (target_stack->top == -2)
  	{
+ 	  int pops = 0;
+ 	  struct stack_def newstack = regstack;
+ 
  	  /* The target block hasn't had a stack order selected.
! 	     We need only to pop the registers.  */
! 	  for (reg = 0; reg <= regstack.top; reg++)
! 	    if (!TEST_HARD_REG_BIT (target_stack->reg_set,
! 				    regstack.reg[reg]))
! 	      {
! 		pop_stack (&newstack, regstack.reg[reg]);
! 		pops++;
! 	      }
  
! 	  if (file)
! 	    fprintf (file, "  New block %d reached; copying stack position; %i pops\n",
! 		     target->index,
! 		     pops);
  
! 	  *target_stack = newstack;
! 	}
!     }
!   bi->stack_out = regstack;
!   return;
! }
  
! /* Convert registers in all blocks reachable from BLOCK.  */
  
! static int
! convert_regs_2 (file, block)
!      FILE *file;
!      basic_block block;
! {
!   basic_block *stack, *sp;
!   int inserted;
! 
!   stack = (basic_block *) alloca (sizeof (*stack) * n_basic_blocks);
!   sp = stack;
! 
!   *sp++ = block;
!   BLOCK_INFO (block)->done = 1;
! 
!   inserted = 0;
!   do
!     {
!       edge e;
! 
!       block = *--sp;
!       convert_regs_1 (file, block);
! 
!       for (e = block->succ; e ; e = e->succ_next)
! 	if (! BLOCK_INFO (e->dest)->done)
! 	  {
! 	    *sp++ = e->dest;
! 	    BLOCK_INFO (e->dest)->done = 1;
! 	  }
!     }
!   while (sp != stack);
! 
!   return inserted;
! }
! 
! /* Set the map of permutation common for all output edges.  */
! static void
! find_common_map (blockno, registermap)
!      int blockno;
!      int *registermap;
! {
!   basic_block block = BASIC_BLOCK (blockno);
!   edge e = block->succ;
!   block_info bi = BLOCK_INFO (e->dest);
!   int i;
! 
!   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
!     registermap[i] = -2;
!   for (i = 0; i <= bi->stack_in.top; i++)
!     registermap[(int) bi->stack_in.reg[i]] = i;
!   if (!e)
!     return;
! 
!   /* Find positions common for all edges.  */
!   for (; e; e = e->succ_next)
!     {
!       bi = BLOCK_INFO (e->dest);
! 
!       for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
! 	if (!TEST_HARD_REG_BIT (bi->stack_in.reg_set, i))
! 	  registermap[i] = -2;
! 
!       for (i = 0; i <= bi->stack_in.top; i++)
! 	if (registermap[(int) bi->stack_in.reg[i]] != i)
! 	  registermap[(int) bi->stack_in.reg[i]] = -2;
!     }
! }
! 
! /* Remove all incomplette cycles in the permutation.  */
! static void
! remove_incomplette_cycles (registermap, s)
!      int *registermap;
!      stack s;
! {
!   int i;
!   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
!     {
!       int y;
!       y = registermap[i];
!       if (y >= 0)
! 	do
! 	  y = registermap[(int) s->reg[y]];
! 	while (y != registermap[i] && y >= 0);
!       if (y < 0)
! 	registermap[i] = -2;
!     }
! }
! 
! /* Emit code to correct different permutations of the registers
!    on the starts of basic blocks. */
! 
! static int
! emit_basic_block_corrections (file)
!      FILE *file;
! {
!   int inserted = 0;
!   basic_block block;
!   struct stack_def tmpstack;
!   stack regstack;
!   int i;
!   edge e;
!   int reg;
!   int ninsns;
! 
!   current_block = NULL;
!   for (i = 0; i < n_basic_blocks; ++i)
!     {
!       block = BASIC_BLOCK (i);
!       regstack = &BLOCK_INFO (block)->stack_out;
!       if (file)
! 	{
! 	  fprintf (file, "\n\nBasic block %d\nOutput stack: ", block->index);
! 	  print_stack (file, regstack);
  	}
!       for (e = block->succ; e; e = e->succ_next)
  	{
! 	  basic_block target = e->dest;
! 	  stack target_stack = &BLOCK_INFO (target)->stack_in;
! 	  rtx seq, after;
! 
! 	  if (file)
! 	    fprintf (file, "  Edge to block %d: ", target->index);
! 
! 	  if (target_stack->top == -2)
! 	    abort ();
! 	  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)
*************** convert_regs_1 (file, block)
*** 2579,2603 ****
  	      fprintf (file, "correcting stack to ");
  	      print_stack (file, target_stack);
  	    }
- 	}
  
-       /* It is better to output directly to the end of the block
- 	 instead of to the edge, because emit_swap can do minimal
- 	 insn scheduling.  We can do this when there is only one
- 	 edge out, and it is not abnormal.  */
-       if (block->succ->succ_next == NULL
- 	  && ! (e->flags & EDGE_ABNORMAL))
- 	{
- 	  /* change_stack kills values in regstack.  */
- 	  tmpstack = regstack;
- 
- 	  change_stack (block->end, &tmpstack, target_stack,
- 			(GET_CODE (block->end) == JUMP_INSN
- 			 ? EMIT_BEFORE : EMIT_AFTER));
- 	}
-       else
- 	{
- 	  rtx seq, after;
  
  	  /* We don't support abnormal edges.  Global takes
  	     care to avoid any live register across them, so
--- 2701,2707 ----
*************** convert_regs_1 (file, block)
*** 2605,2670 ****
  	  if (e->flags & EDGE_ABNORMAL)
  	    abort ();
  
- 	  current_block = NULL;
  	  start_sequence ();
! 		  
  	  /* ??? change_stack needs some point to emit insns after. 
  	     Also needed to keep gen_sequence from returning a 
  	     pattern as opposed to a sequence, which would lose
  	     REG_DEAD notes.  */
  	  after = emit_note (NULL, NOTE_INSN_DELETED);
  
! 	  tmpstack = regstack;
! 	  change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
  
  	  seq = gen_sequence ();
  	  end_sequence ();
  
  	  insert_insn_on_edge (seq, e);
  	  inserted = 1;
! 	  current_block = block;
  	}
      }
- 
    return inserted;
  }
! 
! /* Convert registers in all blocks reachable from BLOCK.  */
  
  static int
! convert_regs_2 (file, block)
       FILE *file;
-      basic_block block;
  {
!   basic_block *stack, *sp;
!   int inserted;
! 
!   stack = (basic_block *) alloca (sizeof (*stack) * n_basic_blocks);
!   sp = stack;
! 
!   *sp++ = block;
!   BLOCK_INFO (block)->done = 1;
  
!   inserted = 0;
!   do
      {
!       edge e;
! 
!       block = *--sp;
!       inserted |= convert_regs_1 (file, block);
! 
!       for (e = block->succ; e ; e = e->succ_next)
! 	if (! BLOCK_INFO (e->dest)->done)
! 	  {
! 	    *sp++ = e->dest;
! 	    BLOCK_INFO (e->dest)->done = 1;
! 	  }
      }
-   while (sp != stack);
- 
    return inserted;
  }
! 
  /* Traverse all basic blocks in a function, converting the register
     references in each insn from the "flat" register file that gcc uses,
     to the stack-like registers the 387 uses.  */
--- 2709,2783 ----
  	  if (e->flags & EDGE_ABNORMAL)
  	    abort ();
  
  	  start_sequence ();
! 
  	  /* ??? change_stack needs some point to emit insns after. 
  	     Also needed to keep gen_sequence from returning a 
  	     pattern as opposed to a sequence, which would lose
  	     REG_DEAD notes.  */
  	  after = emit_note (NULL, NOTE_INSN_DELETED);
  
! 	  tmpstack = *regstack;
! 	  ninsns = change_stack (after, &tmpstack, target_stack,
! 				 EMIT_BEFORE, 1);
  
  	  seq = gen_sequence ();
  	  end_sequence ();
  
  	  insert_insn_on_edge (seq, e);
  	  inserted = 1;
! 	  if (file)
! 	    fprintf (file, "   %i insns emited.\n", ninsns);
  	}
      }
    return inserted;
  }
! /* Emit correction code common for all outgoing edges to the end of basic
!    block.  Jump optimization can't do this job for us well, because
!    change_stack may choose different strategy for each edge resulting
!    in no common code at all.  */
  
  static int
! emit_common_basic_block_corrections (file)
       FILE *file;
  {
!   int registermap[LAST_STACK_REG + 1];
!   int inserted = 0;
!   basic_block block;
!   stack regstack;
!   int i;
!   edge e;
!   int ninsns;
  
!   for (i = 0; i < n_basic_blocks; ++i)
      {
!       block = BASIC_BLOCK (i);
!       current_block = block;
!       regstack = &BLOCK_INFO (block)->stack_out;
! 
!       e = block->succ;
!       if (!e)
! 	continue;
! 
!       for (; e && !(e->flags & EDGE_ABNORMAL); e = e->succ_next);
!       if (e)
! 	continue;
! 
!       find_common_map (i, registermap);
!       remove_incomplette_cycles (registermap, regstack);
!       ninsns = change_to_regmap (block->end, regstack, registermap,
! 				 (GET_CODE (block->end) == JUMP_INSN
! 				  ? EMIT_BEFORE : EMIT_AFTER), 1);
!       if (file)
! 	{
! 	  fprintf (file, "\n%i insns emited to the basic block %i.\n New output stack:",
! 		   ninsns, block->index);
! 	  print_stack (file, regstack);
! 	}
      }
    return inserted;
  }
! 
  /* Traverse all basic blocks in a function, converting the register
     references in each insn from the "flat" register file that gcc uses,
     to the stack-like registers the 387 uses.  */
*************** convert_regs (file)
*** 2683,2692 ****
    convert_regs_exit ();
    BLOCK_INFO (EXIT_BLOCK_PTR)->done = 1;
  
-   /* ??? Future: process inner loops first, and give them arbitrary
-      initial stacks which emit_swap_insn can modify.  This ought to
-      prevent double fxch that aften appears at the head of a loop.  */
- 
    /* Process all blocks reachable from all entry points.  */
    for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
      inserted |= convert_regs_2 (file, e->dest);
--- 2796,2801 ----
*************** convert_regs (file)
*** 2712,2717 ****
--- 2821,2831 ----
  	}
      }
  
+   if (optimize)
+     emit_common_basic_block_corrections (file);
+ 
+   inserted |= emit_basic_block_corrections (file);
+ 
    if (inserted)
      commit_edge_insertions ();
  


More information about the Gcc-patches mailing list