[PATCH] Fix tree body copying

Richard Guenther rguenther@suse.de
Tue Jul 7 11:12:00 GMT 2009


This is a split-out from the gimplify-unit-at-a-time patch which relies
on copy_tree_body_r properly copying GENERIC bodies.

There are several issues with the current implementation, the most
prominent being that statement-list copying is completely hosed
because of the 'optimization' tsi_link_after performs.  Fixed by
providing a non-optimizing variant for tsi_link_after.

Other issues are that the FE requires the type on the statement-list
properly copied and TARGET_EXPR handled the same as SAVE_EXPR.

Separate bootstrap and regtest is running, I will apply this after
it succeeded.

Thanks,
Richard.

2009-07-07  Richard Guenther  <rguenther@suse.de>

        * tree-inline.c (copy_statement_list): Properly copy STATEMENT_LIST.
        (copy_tree_body_r): Properly copy STATEMENT_LIST.
        Properly handle TARGET_EXPR like SAVE_EXPR.
        (unsave_r): Likewise.
        * tree-iterator.h (tsi_link_stmt_after): Declare.
        * tree-iterator.c (tsi_link_after_1): New helper split out from ...
        (tsi_link_after): ... here.
        (tsi_link_stmt_after): New function.

Index: gcc/tree-inline.c
===================================================================
*** gcc/tree-inline.c.orig	2009-07-07 12:51:02.000000000 +0200
--- gcc/tree-inline.c	2009-07-07 12:52:11.000000000 +0200
*************** copy_statement_list (tree *tp)
*** 603,609 ****
    *tp = new_tree;
  
    for (; !tsi_end_p (oi); tsi_next (&oi))
!     tsi_link_after (&ni, tsi_stmt (oi), TSI_NEW_STMT);
  }
  
  static void
--- 603,609 ----
    *tp = new_tree;
  
    for (; !tsi_end_p (oi); tsi_next (&oi))
!     tsi_link_stmt_after (&ni, tsi_stmt (oi), TSI_NEW_STMT);
  }
  
  static void
*************** copy_tree_body_r (tree *tp, int *walk_su
*** 919,926 ****
        *walk_subtrees = 0;
      }
    else if (TREE_CODE (*tp) == STATEMENT_LIST)
!     copy_statement_list (tp);
!   else if (TREE_CODE (*tp) == SAVE_EXPR)
      remap_save_expr (tp, id->decl_map, walk_subtrees);
    else if (TREE_CODE (*tp) == LABEL_DECL
  	   && (! DECL_CONTEXT (*tp)
--- 919,931 ----
        *walk_subtrees = 0;
      }
    else if (TREE_CODE (*tp) == STATEMENT_LIST)
!     {
!       tree new_type = remap_type (TREE_TYPE (*tp), id);
!       copy_statement_list (tp);
!       TREE_TYPE (*tp) = new_type;
!     }
!   else if (TREE_CODE (*tp) == SAVE_EXPR
! 	   || TREE_CODE (*tp) == TARGET_EXPR)
      remap_save_expr (tp, id->decl_map, walk_subtrees);
    else if (TREE_CODE (*tp) == LABEL_DECL
  	   && (! DECL_CONTEXT (*tp)
*************** unsave_r (tree *tp, int *walk_subtrees,
*** 3917,3923 ****
      gcc_unreachable ();
    else if (TREE_CODE (*tp) == BIND_EXPR)
      copy_bind_expr (tp, walk_subtrees, id);
!   else if (TREE_CODE (*tp) == SAVE_EXPR)
      remap_save_expr (tp, st, walk_subtrees);
    else
      {
--- 3922,3929 ----
      gcc_unreachable ();
    else if (TREE_CODE (*tp) == BIND_EXPR)
      copy_bind_expr (tp, walk_subtrees, id);
!   else if (TREE_CODE (*tp) == SAVE_EXPR
! 	   || TREE_CODE (*tp) == TARGET_EXPR)
      remap_save_expr (tp, st, walk_subtrees);
    else
      {
Index: gcc/tree-iterator.c
===================================================================
*** gcc/tree-iterator.c.orig	2009-07-07 12:51:02.000000000 +0200
--- gcc/tree-iterator.c	2009-07-07 12:52:01.000000000 +0200
*************** tsi_link_before (tree_stmt_iterator *i,
*** 137,176 ****
      }
  }
  
! /* Links a statement, or a chain of statements, after the current stmt.  */
  
! void
! tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
  {
!   struct tree_statement_list_node *head, *tail, *cur;
! 
!   /* Die on looping.  */
!   gcc_assert (t != i->container);
! 
!   if (TREE_CODE (t) == STATEMENT_LIST)
!     {
!       head = STATEMENT_LIST_HEAD (t);
!       tail = STATEMENT_LIST_TAIL (t);
!       STATEMENT_LIST_HEAD (t) = NULL;
!       STATEMENT_LIST_TAIL (t) = NULL;
! 
!       free_stmt_list (t);
! 
!       /* Empty statement lists need no work.  */
!       if (!head || !tail)
! 	{
! 	  gcc_assert (head == tail);
! 	  return;
! 	}
!     }
!   else
!     {
!       head = GGC_NEW (struct tree_statement_list_node);
!       head->prev = NULL;
!       head->next = NULL;
!       head->stmt = t;
!       tail = head;
!     }
  
    TREE_SIDE_EFFECTS (i->container) = 1;
  
--- 137,152 ----
      }
  }
  
! /* Links a statement, or a chain of statements, specified by HEAD and TAIL
!    after the current stmt.  */
  
! static void
! tsi_link_after_1 (tree_stmt_iterator *i,
! 		  struct tree_statement_list_node *head,
! 		  struct tree_statement_list_node *tail,
! 		  enum tsi_iterator_update mode)
  {
!   struct tree_statement_list_node *cur;
  
    TREE_SIDE_EFFECTS (i->container) = 1;
  
*************** tsi_link_after (tree_stmt_iterator *i, t
*** 211,216 ****
--- 187,250 ----
      }
  }
  
+ /* Links a statement after the current stmt.  */
+ 
+ void
+ tsi_link_stmt_after (tree_stmt_iterator *i, tree t,
+ 		     enum tsi_iterator_update mode)
+ {
+   struct tree_statement_list_node *head, *tail;
+ 
+   /* Die on looping.  */
+   gcc_assert (t != i->container);
+ 
+   head = GGC_NEW (struct tree_statement_list_node);
+   head->prev = NULL;
+   head->next = NULL;
+   head->stmt = t;
+   tail = head;
+ 
+   tsi_link_after_1 (i, head, tail, mode);
+ }
+ 
+ /* Links a statement, or a chain of statements, after the current stmt.  */
+ 
+ void
+ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
+ {
+   struct tree_statement_list_node *head, *tail;
+ 
+   /* Die on looping.  */
+   gcc_assert (t != i->container);
+ 
+   if (TREE_CODE (t) == STATEMENT_LIST)
+     {
+       head = STATEMENT_LIST_HEAD (t);
+       tail = STATEMENT_LIST_TAIL (t);
+       STATEMENT_LIST_HEAD (t) = NULL;
+       STATEMENT_LIST_TAIL (t) = NULL;
+ 
+       free_stmt_list (t);
+ 
+       /* Empty statement lists need no work.  */
+       if (!head || !tail)
+ 	{
+ 	  gcc_assert (head == tail);
+ 	  return;
+ 	}
+     }
+   else
+     {
+       head = GGC_NEW (struct tree_statement_list_node);
+       head->prev = NULL;
+       head->next = NULL;
+       head->stmt = t;
+       tail = head;
+     }
+ 
+   tsi_link_after_1 (i, head, tail, mode);
+ }
+ 
  /* Remove a stmt from the tree list.  The iterator is updated to point to
     the next stmt.  */
  
Index: gcc/tree-iterator.h
===================================================================
*** gcc/tree-iterator.h.orig	2009-07-07 12:51:02.000000000 +0200
--- gcc/tree-iterator.h	2009-07-07 12:52:01.000000000 +0200
*************** extern void tsi_link_before (tree_stmt_i
*** 110,115 ****
--- 110,117 ----
  			     enum tsi_iterator_update);
  extern void tsi_link_after (tree_stmt_iterator *, tree,
  			    enum tsi_iterator_update);
+ extern void tsi_link_stmt_after (tree_stmt_iterator *, tree,
+ 				 enum tsi_iterator_update);
  
  void tsi_delink (tree_stmt_iterator *);
  



More information about the Gcc-patches mailing list