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


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

[Committed] Some more reg-stack.c clean-ups


The patch below is yet another set of clean-ups following the split
of reg-stack.c into two phases.  The routine compensate_edge is now
only called during the second phase when we actually emit stack
manipulation instructions on edges.  As such it should treat the
block_info structures as read-only, but a few of the existing
consistency checks were using "stack->top = -1" instead of asserting
that "stack->top == -1".  We can also simplify this checking code
for "complex" edges by reordering the tests appropriately.

There are also some performance improvements.  We now try to do the
minimum possible work before testing whether any compensation code is
needed.  Identical (empty) stacks is by far the most common case, so
by avoiding copying structures and initializing variables unnecessarily
we speed up the code a little.  We were also copying a reg_stack struct
into a temporary and from there into a second temporary to avoid
clobbering the original.  Clearly we only need to copy it once.

I moved the setting of the "done" flag for a basic block from
convert_regs_2 to convert_regs_1 so that the entirety of per BB
processing is in convert_regs_1 leaving only CFG traversal in c_r_2.
Further improvements to reg-stack may require alternate BB traversal
strategies (i.e. alternate implementations of convert_regs_2), so
reusing as much as possible in convert_regs_1 is desirable.


The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all default languages, and regression tested with
a top-level "make -k check" with no new failures.  There should be
no functional changes with this clean-up.

Committed to mainline CVS.



2005-06-04  Roger Sayle  <roger@eyesopen.com>

	* reg-stack.c (struct block_info_def): Correct grammar typo.
	(compensate_edge): Clean-up.  Perform as little work as possible
	when src and dest stacks match.  Avoid modifying block_info.
	Reorder and simplify assertion checks.  Avoid unnecessary copying
	of regstack structure.
	(convert_regs_1): Set the done flag here...
	(convert_regs_2): ... instead of here.


Index: reg-stack.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reg-stack.c,v
retrieving revision 1.182
diff -c -3 -p -r1.182 reg-stack.c
*** reg-stack.c	30 May 2005 18:02:08 -0000	1.182
--- reg-stack.c	4 Jun 2005 18:29:26 -0000
*************** typedef struct block_info_def
*** 208,214 ****
    struct stack_def stack_out;	/* Output stack configuration.  */
    HARD_REG_SET out_reg_set;	/* Stack regs live on output.  */
    int done;			/* True if block already converted.  */
!   int predecessors;		/* Number of predecessors that needs
  				   to be visited.  */
  } *block_info;

--- 208,214 ----
    struct stack_def stack_out;	/* Output stack configuration.  */
    HARD_REG_SET out_reg_set;	/* Stack regs live on output.  */
    int done;			/* True if block already converted.  */
!   int predecessors;		/* Number of predecessors that need
  				   to be visited.  */
  } *block_info;

*************** propagate_stack (edge e)
*** 2629,2652 ****
  static bool
  compensate_edge (edge e, FILE *file)
  {
!   basic_block block = e->src, target = e->dest;
!   block_info bi = BLOCK_INFO (block);
!   struct stack_def regstack, tmpstack;
    stack target_stack = &BLOCK_INFO (target)->stack_in;
    int reg;

-   current_block = block;
-   regstack = bi->stack_out;
    if (file)
!     fprintf (file, "Edge %d->%d: ", block->index, target->index);

    gcc_assert (target_stack->top != -2);

    /* Check whether stacks are identical.  */
!   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)
--- 2629,2650 ----
  static bool
  compensate_edge (edge e, FILE *file)
  {
!   basic_block source = e->src, target = e->dest;
    stack target_stack = &BLOCK_INFO (target)->stack_in;
+   stack source_stack = &BLOCK_INFO (source)->stack_out;
+   struct stack_def regstack;
    int reg;

    if (file)
!     fprintf (file, "Edge %d->%d: ", source->index, target->index);

    gcc_assert (target_stack->top != -2);

    /* Check whether stacks are identical.  */
!   if (target_stack->top == source_stack->top)
      {
        for (reg = target_stack->top; reg >= 0; --reg)
! 	if (target_stack->reg[reg] != source_stack->reg[reg])
  	  break;

        if (reg == -1)
*************** compensate_edge (edge e, FILE *file)
*** 2663,2730 ****
        print_stack (file, target_stack);
      }

!   /* Care for non-call EH edges specially.  The normal return path have
!      values in registers.  These will be popped en masse by the unwind
!      library.  */
!   if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH)
!     target_stack->top = -1;
!
!   /* Other calls may appear to have values live in st(0), but the
       abnormal return path will not have actually loaded the values.  */
!   else if (e->flags & EDGE_ABNORMAL_CALL)
      {
        /* Assert that the lifetimes are as we expect -- one value
           live at st(0) on the end of the source block, and no
           values live at the beginning of the destination block.  */
!       HARD_REG_SET tmp;

!       CLEAR_HARD_REG_SET (tmp);
!       GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1);
!       gcc_unreachable ();
!     eh1:

!       /* We are sure that there is st(0) live, otherwise we won't compensate.
! 	 For complex return values, we may have st(1) live as well.  */
!       SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
!       if (TEST_HARD_REG_BIT (regstack.reg_set, FIRST_STACK_REG + 1))
!         SET_HARD_REG_BIT (tmp, FIRST_STACK_REG + 1);
!       GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
!       gcc_unreachable ();
!     eh2:

!       target_stack->top = -1;
!     }

    /* 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.  */
!   else if (EDGE_COUNT (block->succs) == 1 && !(e->flags & EDGE_ABNORMAL))
      {
!       /* change_stack kills values in regstack.  */
!       tmpstack = regstack;
!
!       change_stack (BB_END (block), &tmpstack, target_stack,
! 		    (JUMP_P (BB_END (block))
! 		     ? 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 we should never
-          have to insert instructions on such edges.  */
-       gcc_assert (!(e->flags & EDGE_ABNORMAL));
-
        current_block = NULL;
        start_sequence ();

        /* ??? change_stack needs some point to emit insns after.  */
        after = emit_note (NOTE_INSN_DELETED);

!       tmpstack = regstack;
!       change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);

        seq = get_insns ();
        end_sequence ();
--- 2661,2716 ----
        print_stack (file, target_stack);
      }

!   /* Abnormal calls may appear to have values live in st(0), but the
       abnormal return path will not have actually loaded the values.  */
!   if (e->flags & EDGE_ABNORMAL_CALL)
      {
        /* Assert that the lifetimes are as we expect -- one value
           live at st(0) on the end of the source block, and no
           values live at the beginning of the destination block.  */
!       gcc_assert (source_stack->top == 0);
!       gcc_assert (target_stack->top == -1);
!       return false;
!     }

!   /* Handle non-call EH edges specially.  The normal return path have
!      values in registers.  These will be popped en masse by the unwind
!      library.  */
!   if (e->flags & EDGE_EH)
!     {
!       gcc_assert (target_stack->top == -1);
!       return false;
!     }

!   /* We don't support abnormal edges.  Global takes care to
!      avoid any live register across them, so we should never
!      have to insert instructions on such edges.  */
!   gcc_assert (! (e->flags & EDGE_ABNORMAL));

!   /* Make a copy of source_stack as change_stack is destructive.  */
!   regstack = *source_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 (EDGE_COUNT (source->succs) == 1)
      {
!       current_block = source;
!       change_stack (BB_END (source), &regstack, target_stack,
! 		    (JUMP_P (BB_END (source)) ? EMIT_BEFORE : EMIT_AFTER));
      }
    else
      {
        rtx seq, after;

        current_block = NULL;
        start_sequence ();

        /* ??? change_stack needs some point to emit insns after.  */
        after = emit_note (NOTE_INSN_DELETED);

!       change_stack (after, &regstack, target_stack, EMIT_BEFORE);

        seq = get_insns ();
        end_sequence ();
*************** convert_regs_1 (FILE *file, basic_block
*** 2928,2933 ****
--- 2914,2920 ----
    gcc_assert (any_malformed_asm);
   win:
    bi->stack_out = regstack;
+   bi->done = true;
  }

  /* Convert registers in all blocks reachable from BLOCK.  */
*************** convert_regs_2 (FILE *file, basic_block
*** 2975,2981 ****
  	  }

        convert_regs_1 (file, block);
-       BLOCK_INFO (block)->done = 1;
      }
    while (sp != stack);

--- 2962,2967 ----


Roger
--


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