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]

Re: [tree-ssa] Get rid of LOOP_EXPRs


Hello,

here is the patch for the regressions removing LOOP_EXPRs would
cause.

>  >2) In the following testcase it happens that start of BIND_EXPR is the last
>  >   statement of a block; when bsi_insert_after is called on it,
>  >   statement is inserted after end of BIND_EXPR block, which is far away
>  >   from the position where it should be, thus causing misscompilation.
>  >   Also reproducible with tree-ssa-branch using explicit gotos, testcase

this in fact turned out to be a problem with bsi_next_in_block that in
this case returned the BIND_EXPR as a statement.

The patch also makes the BIND_EXPRs to start/end basic blocks as Jeff
suggested.

Zdenek

	* tree-cfg.c (make_bind_expr_blocks, make_blocks, stmt_ends_bb_p):
	Create new block with start of BIND_EXPR.
	(remove_unreachable_block):  Work for empty blocks.
	(remove_bb): Don't remove BIND_EXPRs with reachable inner parts.
	(debug_tree_bb_n): New.
	(bsi_next_in_bb): Work correctly when the block ends with start
	of BIND_EXPR.

Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.154
diff -c -3 -p -r1.1.4.154 tree-cfg.c
*** tree-cfg.c	21 Aug 2003 17:23:51 -0000	1.1.4.154
--- tree-cfg.c	22 Aug 2003 17:16:15 -0000
*************** static void create_block_annotation (bas
*** 85,98 ****
  static void free_blocks_annotations (void);
  static void clear_blocks_annotations (void);
  static basic_block make_blocks (tree *, tree, tree, basic_block, tree);
  static void make_loop_expr_blocks (tree *, basic_block, tree);
  static void make_cond_expr_blocks (tree *, tree, basic_block, tree);
  static void make_catch_expr_blocks (tree *, tree, basic_block, tree);
  static void make_eh_filter_expr_blocks (tree *, tree, basic_block, tree);
  static void make_try_expr_blocks (tree *, tree, basic_block, tree);
  static void make_switch_expr_blocks (tree *, tree, basic_block, tree);
! static basic_block make_bind_expr_blocks (tree *, tree, basic_block, tree,
! 					  tree);
  static inline void add_stmt_to_bb (tree *, basic_block, tree);
  static inline void append_stmt_to_bb (tree *, basic_block, tree);
  static inline void set_parent_stmt (tree *, tree);
--- 85,97 ----
  static void free_blocks_annotations (void);
  static void clear_blocks_annotations (void);
  static basic_block make_blocks (tree *, tree, tree, basic_block, tree);
  static void make_loop_expr_blocks (tree *, basic_block, tree);
  static void make_cond_expr_blocks (tree *, tree, basic_block, tree);
  static void make_catch_expr_blocks (tree *, tree, basic_block, tree);
  static void make_eh_filter_expr_blocks (tree *, tree, basic_block, tree);
  static void make_try_expr_blocks (tree *, tree, basic_block, tree);
  static void make_switch_expr_blocks (tree *, tree, basic_block, tree);
! static void make_bind_expr_blocks (tree *, tree, basic_block, tree);
  static inline void add_stmt_to_bb (tree *, basic_block, tree);
  static inline void append_stmt_to_bb (tree *, basic_block, tree);
  static inline void set_parent_stmt (tree *, tree);
*************** make_blocks (tree *first_p, tree next_bl
*** 450,510 ****
  	make_try_expr_blocks (stmt_p, next_block_link, bb, scope);
        else if (code == BIND_EXPR)
  	{
- 	  int num_blocks_before;
- 	  basic_block last_bb;
- 
- 	  /* BIND_EXPR nodes are a special case.  We neither force a new
- 	     block for their bodies, nor force a new block after creating
- 	     the subgraph.  On return from make_bind_expr_blocks, LAST_BB
- 	     will be the last basic block of the BIND_EXPR's subgraph.  We
- 	     point STMT to LAST_BB's last statement to determine if we
- 	     should start a new block or not.  */
-  	  num_blocks_before = n_basic_blocks;
  	  assign_vars_to_scope (stmt);
  	  get_stmt_ann (stmt)->scope_level =
  		  get_stmt_ann (scope)->scope_level + 1;
  
! 	  last_bb = make_bind_expr_blocks (stmt_p, next_block_link, bb,
! 	                                   parent_stmt, stmt);
! 	  if (last_bb)
! 	    {
! 	      bb = last_bb;
! 	      stmt = last_stmt (bb);
! 	    }
! 
! 	  /* FIXME.  Obscene hack to work around iterator limitations.  If
! 	     during processing of the BIND_EXPR body we were forced to
! 	     create new blocks (i.e., the BIND_EXPR body contains control
! 	     flow structures), then force the creation of a new basic block
! 	     for the next iteration.  This avoids the following problem
! 	     (assume that all the Si statements are regular GIMPLE
! 	     statements):
! 
! 		    1	s1;		<-- BLOCK #0
! 		    2	{
! 		    3	  s2;
! 		    4	  s3;
! 		    5	  if ()
! 		    6	    s4;		<-- BLOCK #1
! 		    7	  s5;		<-- BLOCK #2
! 		    8	}
! 		    9	s6;
! 
! 	     Since s5 and s6 are two regular statements, they could both be
! 	     in block #2.  However, if we started an iterator on block #2,
! 	     the iterator would have no way of knowing how to go from
! 	     statement s5 to statement s6 because the iterator was started
! 	     in the middle of its BIND_EXPR's body, so bsi_step_in_bb() has
! 	     not enough context to determine how to get to s6.  */
! 	  if (n_basic_blocks > num_blocks_before)
! 	    {
! 	      start_new_block = true;
! 
! 	      /* If we are starting the new block just to work around
! 		 iterator limitations, keep track of it.  */
! 	      if (!stmt || !stmt_ends_bb_p (stmt))
! 		cfg_stats.num_failed_bind_expr_merges++;
! 	    }
  	}
  
        /* If STMT is a basic block terminator, set START_NEW_BLOCK for the
--- 444,454 ----
  	make_try_expr_blocks (stmt_p, next_block_link, bb, scope);
        else if (code == BIND_EXPR)
  	{
  	  assign_vars_to_scope (stmt);
  	  get_stmt_ann (stmt)->scope_level =
  		  get_stmt_ann (scope)->scope_level + 1;
  
! 	  make_bind_expr_blocks (stmt_p, next_block_link, bb, stmt);
  	}
  
        /* If STMT is a basic block terminator, set START_NEW_BLOCK for the
*************** make_switch_expr_blocks (tree *switch_e_
*** 788,798 ****
  }
  
  
! /* Create the blocks for the BIND_EXPR node pointed by BIND_P.  In contrast
!    with the other make_*_blocks functions, this function will not start a
!    new basic block for the statements in the BIND_EXPR body.  Rather, the
!    statements in the BIND_EXPR body are added to the block ENTRY and use
!    the same PARENT_STMT.
  
     NEXT_BLOCK_LINK is the first statement of the successor basic block for
        the block holding *BIND_P.  If *BIND_P is the last statement inside a
--- 682,688 ----
  }
  
  
! /* Create the blocks for the BIND_EXPR node pointed by BIND_P.
  
     NEXT_BLOCK_LINK is the first statement of the successor basic block for
        the block holding *BIND_P.  If *BIND_P is the last statement inside a
*************** make_switch_expr_blocks (tree *switch_e_
*** 801,822 ****
  
     ENTRY is the block whose last statement is *SWITCH_E_P.
  
-    Return the last basic block added to the BIND_EXPR's subgraph.  This
-    allows the caller to determine whether a new block should be started or
-    not.
-    
     SCOPE is the BIND_EXPR node holding *BIND_P (in fact it is equal to
     *BIND_P).  */
  
! static basic_block
  make_bind_expr_blocks (tree *bind_p, tree next_block_link,
! 		       basic_block entry, tree parent_stmt, tree scope)
  {
    tree_stmt_iterator si;
!   tree bind = *bind_p;
  
!   /* Determine NEXT_BLOCK_LINK for statements inside the BIND_EXPR
!      body.  */
    si = tsi_start (bind_p);
    tsi_next (&si);
  
--- 691,708 ----
  
     ENTRY is the block whose last statement is *SWITCH_E_P.
  
     SCOPE is the BIND_EXPR node holding *BIND_P (in fact it is equal to
     *BIND_P).  */
  
! static void
  make_bind_expr_blocks (tree *bind_p, tree next_block_link,
! 		       basic_block entry, tree scope)
  {
    tree_stmt_iterator si;
!   tree expr = *bind_p;
!   entry->flags |= BB_CONTROL_EXPR;
  
!   /* Determine NEXT_BLOCK_LINK for statements inside the body.  */
    si = tsi_start (bind_p);
    tsi_next (&si);
  
*************** make_bind_expr_blocks (tree *bind_p, tre
*** 827,840 ****
    if (!tsi_end_p (si) && tsi_stmt (si) != NULL_TREE)
      next_block_link = *(tsi_container (si));
  
!   /* By passing the current block ENTRY to make_blocks, we will keep adding
!      statements to ENTRY until we find a block terminating statement inside
!      the body of the BIND_EXPR.  On return from make_blocks, our caller
!      will start a new basic block only if the body of the BIND_EXPR node
!      ends with a block terminating statement.  */
!   STRIP_CONTAINERS (bind);
!   return make_blocks (&BIND_EXPR_BODY (bind), next_block_link, parent_stmt,
! 		      entry, scope);
  }
  
  
--- 713,720 ----
    if (!tsi_end_p (si) && tsi_stmt (si) != NULL_TREE)
      next_block_link = *(tsi_container (si));
  
!   STRIP_CONTAINERS (expr);
!   make_blocks (&BIND_EXPR_BODY (expr), next_block_link, expr, NULL, scope);
  }
  
  
*************** remove_unreachable_block (basic_block bb
*** 1903,1915 ****
  
  	 The entry block (line 2) is unreachable but its body isn't.  */
        find_contained_blocks (last_p, subblocks, &dummy_p);
        if (blocks_unreachable_p (subblocks))
  	{
  	  remove_blocks (subblocks);
  	}
        else
  	{
- 
  	  /* If we have reachable subblocks, then we can not remove
  	     control statements.  But we also can't simply leave them
  	     as-is since they may refer to SSA variables which will
--- 1746,1759 ----
  
  	 The entry block (line 2) is unreachable but its body isn't.  */
        find_contained_blocks (last_p, subblocks, &dummy_p);
+       /* Always include the removed block.  */
+       bitmap_set_bit (subblocks, bb->index);
        if (blocks_unreachable_p (subblocks))
  	{
  	  remove_blocks (subblocks);
  	}
        else
  	{
  	  /* If we have reachable subblocks, then we can not remove
  	     control statements.  But we also can't simply leave them
  	     as-is since they may refer to SSA variables which will
*************** remove_bb (basic_block bb, int remove_st
*** 1994,2000 ****
        set_bb_for_stmt (stmt, NULL);
        if (remove_stmt_flags)
          {
! 	  int ctrl_stmt = is_ctrl_stmt (stmt);
  
  	  loc.file = get_filename (stmt);
  	  loc.line = get_lineno (stmt);
--- 1838,1844 ----
        set_bb_for_stmt (stmt, NULL);
        if (remove_stmt_flags)
          {
! 	  int ctrl_stmt = is_ctrl_stmt (stmt) || TREE_CODE (stmt) == BIND_EXPR;
  
  	  loc.file = get_filename (stmt);
  	  loc.line = get_lineno (stmt);
*************** debug_tree_bb (basic_block bb)
*** 2859,2864 ****
--- 2658,2673 ----
  }
  
  
+ /* Dump a basic block N on stderr.  */
+ 
+ basic_block
+ debug_tree_bb_n (int n)
+ {
+   dump_tree_bb (stderr, "", BASIC_BLOCK (n), 0);
+ 
+   return BASIC_BLOCK (n);
+ }
+ 
  /* Dump the CFG on stderr.
  
     FLAGS are the same used by the tree dumping functions
*************** stmt_ends_bb_p (tree t)
*** 3293,3299 ****
  
    return (code == COND_EXPR
  	  || code == SWITCH_EXPR
! 	  || code == LOOP_EXPR
  	  || code == EH_FILTER_EXPR
  	  || code == TRY_CATCH_EXPR
  	  || code == TRY_FINALLY_EXPR
--- 3093,3100 ----
  
    return (code == COND_EXPR
  	  || code == SWITCH_EXPR
! 	  || code == LOOP_EXPR
! 	  || code == BIND_EXPR
  	  || code == EH_FILTER_EXPR
  	  || code == TRY_CATCH_EXPR
  	  || code == TRY_FINALLY_EXPR
*************** bsi_next_in_bb (block_stmt_iterator *i, 
*** 3540,3547 ****
  	    }
  	  else
  	    bind.context = tmp;
- 	  *i = bind;
  	}
      }
  
    if (i->tp == NULL && i->context != NULL_TREE)
--- 3320,3327 ----
  	    }
  	  else
  	    bind.context = tmp;
  	}
+       *i = bind;
      }
  
    if (i->tp == NULL && i->context != NULL_TREE)


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