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]

Re: (C++) tree inlining patch RFD


>>>>> Mark Mitchell <mark@codesourcery.com> writes:

 > The back-end wants the BLOCK_BEG/BLOCK_END notes emitted to match up
 > exactly with the BLOCK tree.  So, the algorithm I proposed ensures
 > that this will indeed happen.  In semantics.c we're going to walk the
 > statement-tree putting out block-notes for SCOPE_STMTs; if we walk in
 > that same order earlier, building the BLOCK tree, we'll be sure to
 > have things in sync.

Except that not all of the BLOCKs come from the frontend.  The problem in
tlist.cc is due to expand_fixup trying to add a cleanup block; it's hitting
the same problem I had seen before with the rtl-based inliner.  Again,
we're in a sequence for the STMT_EXPR, so retrofit_block can't find any
previous block notes and so blithely puts the new block at the beginning of
the function.

This is, of course, broken.  In fact, it can never be correct, so we should
abort rather than try to come up with a default.  To that end, I've checked
in the following patch, which should make this problem more visible to
folks who don't use -gdwarf-2.

And now, I'd like to leave the rest of the solution to you; I've spent too
much time on this already, sorry.  The two outstanding problems:

1) The sequence problem described above.
2) SCOPE_STMTs for cleanups have no BLOCK, so when they wind up in
   id->scope_stmt new blocks have no idea where to go.

1999-12-15  Jason Merrill  <jason@casey.cygnus.com>

	* function.c (retrofit_block): Abort if we don't find a suitable insn.
	(insert_block_after_note): Abort if we don't have a previous block.
	Remove FN parameter.
	* function.h: Adjust.

cp/:
1999-12-15  Jason Merrill  <jason@casey.cygnus.com>

	* tree.c (walk_tree): Walk operand subtrees in forward order.
	* optimize.c (expand_call_inline): Likewise.
	(optimize_function): Initialize id->scope_stmt to something useful.
	(remap_block): Assume id->scope_stmt has a useful value.

Index: function.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.c,v
retrieving revision 1.141
diff -c -p -r1.141 function.c
*** function.c	1999/12/15 15:34:03	1.141
--- function.c	1999/12/16 00:02:18
*************** round_trampoline_addr (tramp)
*** 5495,5516 ****
  
  /* Insert the BLOCK in the block-tree, knowing that the previous
     block-note is for OLD_BLOCK.  BEGIN_P is non-zero if the previous
!    block-note was the for the beginning of a BLOCK.  FN is the
!    FUNCTION_DECL into which the BLOCK is being inserted.  */
  
  void 
! insert_block_after_note (block, old_block, begin_p, fn)
       tree block;
       tree old_block;
       int begin_p;
-      tree fn;
  {
    if (begin_p)
      {
!       /* If there was no previous block, use the top-level block for
! 	 the function.  */
        if (!old_block)
! 	old_block = DECL_INITIAL (fn);
  
        BLOCK_SUPERCONTEXT (block) = old_block;
        BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (old_block);
--- 5495,5516 ----
  
  /* Insert the BLOCK in the block-tree, knowing that the previous
     block-note is for OLD_BLOCK.  BEGIN_P is non-zero if the previous
!    block-note was the for the beginning of a BLOCK.  */
  
  void 
! insert_block_after_note (block, old_block, begin_p)
       tree block;
       tree old_block;
       int begin_p;
  {
    if (begin_p)
      {
!       /* If there was no previous block, something's gone terribly
!          wrong.  We used to try to use DECL_INITIAL for the current
!          function, but that will never be correct, and completely
!          hoses the block structure.  */
        if (!old_block)
! 	abort ();
  
        BLOCK_SUPERCONTEXT (block) = old_block;
        BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (old_block);
*************** retrofit_block (block, last_insn)
*** 5545,5556 ****
  	    || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
        break;
  
    insert_block_after_note (block, 
! 			   insn ? NOTE_BLOCK (insn) : NULL_TREE,
! 			   insn 
! 			   ? (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
! 			   : 1,
! 			   current_function_decl);
  }
  
  /* The functions identify_blocks and reorder_blocks provide a way to
--- 5545,5556 ----
  	    || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
        break;
  
+   if (insn == NULL_RTX)
+     abort ();
+ 
    insert_block_after_note (block, 
! 			   NOTE_BLOCK (insn),
! 			   NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG);
  }
  
  /* The functions identify_blocks and reorder_blocks provide a way to
Index: function.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.h,v
retrieving revision 1.38
diff -c -p -r1.38 function.h
*** function.h	1999/12/15 15:34:03	1.38
--- function.h	1999/12/16 00:02:18
***************
*** 1,5 ****
  /* Structure for saving state for a nested function.
!    Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
  
  This file is part of GNU CC.
  
--- 1,5 ----
  /* Structure for saving state for a nested function.
!    Copyright (C) 1989, 92-97, 1998, 1999 Free Software Foundation, Inc.
  
  This file is part of GNU CC.
  
*************** extern struct function *outer_function_c
*** 545,553 ****
  extern void identify_blocks PROTO((tree, rtx));
  /* Insert the BLOCK in the block-tree, knowing that the previous
     block-note is for OLD_BLOCK.  BEGIN_P is non-zero if the previous
!    block-note was the for the beginning of a BLOCK.  FN is the
!    FUNCTION_DECL into which the BLOCK is being inserted.  */
! extern void insert_block_after_note PROTO((tree, tree, int, tree));
  /* Insert a new BLOCK at an appropriate place in the block tree.  */
  extern void retrofit_block PROTO((tree, rtx));
  
--- 545,552 ----
  extern void identify_blocks PROTO((tree, rtx));
  /* Insert the BLOCK in the block-tree, knowing that the previous
     block-note is for OLD_BLOCK.  BEGIN_P is non-zero if the previous
!    block-note was the for the beginning of a BLOCK.  */
! extern void insert_block_after_note PROTO((tree, tree, int));
  /* Insert a new BLOCK at an appropriate place in the block tree.  */
  extern void retrofit_block PROTO((tree, rtx));
  
Index: cp/optimize.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/optimize.c,v
retrieving revision 1.9
diff -c -p -r1.9 optimize.c
*** cp/optimize.c	1999/12/15 19:33:38	1.9
--- cp/optimize.c	1999/12/16 00:02:19
*************** remap_block (scope_stmt, decls, id)
*** 176,188 ****
        /* We put the BLOCK_VARS in reverse order; fix that now.  */
        BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
        /* Graft the new block into the tree.  */
!       insert_block_after_note (new_block, 
! 			       (id->scope_stmt 
! 				? SCOPE_STMT_BLOCK (id->scope_stmt)
! 				: NULL_TREE),
! 			       (id->scope_stmt
! 				? SCOPE_BEGIN_P (id->scope_stmt) : 1),
! 			       VARRAY_TREE (id->fns, 0));
        /* Remember that this is now the last scope statement with
  	 an associated block.  */
        id->scope_stmt = scope_stmt;
--- 176,184 ----
        /* We put the BLOCK_VARS in reverse order; fix that now.  */
        BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
        /* Graft the new block into the tree.  */
!       insert_block_after_note (new_block,
! 			       SCOPE_STMT_BLOCK (id->scope_stmt),
! 			       SCOPE_BEGIN_P (id->scope_stmt));
        /* Remember that this is now the last scope statement with
  	 an associated block.  */
        id->scope_stmt = scope_stmt;
*************** expand_call_inline (tp, walk_subtrees, d
*** 536,542 ****
       inside the body of a TARGET_EXPR.  */
    if (TREE_CODE (*tp) == TARGET_EXPR)
      {
!       int i;
  
        /* We're walking our own subtrees.  */
        *walk_subtrees = 0;
--- 532,538 ----
       inside the body of a TARGET_EXPR.  */
    if (TREE_CODE (*tp) == TARGET_EXPR)
      {
!       int i, len = first_rtl_op (TARGET_EXPR);
  
        /* We're walking our own subtrees.  */
        *walk_subtrees = 0;
*************** expand_call_inline (tp, walk_subtrees, d
*** 544,550 ****
        /* Actually walk over them.  This loop is the body of
  	 walk_trees, omitting the case where the TARGET_EXPR
  	 itself is handled.  */
!       for (i = first_rtl_op (TARGET_EXPR) - 1; i >= 0; --i)
  	{
  	  if (i == 2)
  	    ++id->in_target_cleanup_p;
--- 540,546 ----
        /* Actually walk over them.  This loop is the body of
  	 walk_trees, omitting the case where the TARGET_EXPR
  	 itself is handled.  */
!       for (i = 0; i < len; ++i)
  	{
  	  if (i == 2)
  	    ++id->in_target_cleanup_p;
*************** expand_call_inline (tp, walk_subtrees, d
*** 615,621 ****
    id->scope_stmt = scope_stmt;
  
    /* Tell the debugging backends that this block represents the
!      outermost scope of the inlined function.  */
    if (SCOPE_STMT_BLOCK (scope_stmt))
      BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
  
--- 611,618 ----
    id->scope_stmt = scope_stmt;
  
    /* Tell the debugging backends that this block represents the
!      outermost scope of the inlined function.  FIXME what to do for
!      inlines in cleanups?  */
    if (SCOPE_STMT_BLOCK (scope_stmt))
      BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
  
*************** optimize_function (fn)
*** 725,730 ****
--- 722,734 ----
  	    VARRAY_PUSH_TREE (id.fns, s->function_decl);
  	    prev_fn = s->function_decl;
  	  }
+ 
+       /* Initialize id->scope_stmt with a fake SCOPE_STMT for the outermost
+ 	 block of the function (i.e. the BLOCK with __FUNCTION__ et al).  */
+       id.scope_stmt = build_min_nt (SCOPE_STMT,
+ 				    BLOCK_SUBBLOCKS (DECL_INITIAL (fn)));
+       SCOPE_BEGIN_P (id.scope_stmt) = 1;
+ 
        /* Replace all calls to inline functions with the bodies of those
  	 functions.  */
        expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.168
diff -c -p -r1.168 tree.c
*** cp/tree.c	1999/12/15 09:51:24	1.168
--- cp/tree.c	1999/12/16 00:02:19
*************** walk_tree (tp, func, data)
*** 1623,1643 ****
        || TREE_CODE_CLASS (code) == 'r'
        || TREE_CODE_CLASS (code) == 's')
      {
!       int i;
  
        /* Walk over all the sub-trees of this operand.  */
!       i = first_rtl_op (code) - 1;
        /* TARGET_EXPRs are peculiar: operands 1 and 3 can be the same.
  	 But, we only want to walk once.  */
        if (code == TARGET_EXPR
  	  && TREE_OPERAND (*tp, 3) == TREE_OPERAND (*tp, 1))
! 	--i;
!       /* Go through the subtrees.  */
!       while (i >= 0)
! 	{
! 	  WALK_SUBTREE (TREE_OPERAND (*tp, i));
! 	  --i;
! 	}
  
        /* For statements, we also walk the chain so that we cover the
  	 entire statement tree.  */
--- 1623,1641 ----
        || TREE_CODE_CLASS (code) == 'r'
        || TREE_CODE_CLASS (code) == 's')
      {
!       int i, len;
  
        /* Walk over all the sub-trees of this operand.  */
!       len = first_rtl_op (code);
        /* TARGET_EXPRs are peculiar: operands 1 and 3 can be the same.
  	 But, we only want to walk once.  */
        if (code == TARGET_EXPR
  	  && TREE_OPERAND (*tp, 3) == TREE_OPERAND (*tp, 1))
! 	--len;
!       /* Go through the subtrees.  We need to do this in forward order so
!          that the scope of a FOR_EXPR is handled properly.  */
!       for (i = 0; i < len; ++i)
! 	WALK_SUBTREE (TREE_OPERAND (*tp, i));
  
        /* For statements, we also walk the chain so that we cover the
  	 entire statement tree.  */


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