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]

[tree-ssa] COMPOUND_EXPR removal


Hello,

this patch replaces the COMPOUND_EXPRs by the double linked list of
containers, thus finally making the manipulation with cfg reasonably
simple.

It bootstraps on i686.  As you probably noticed, the last few patches of
mine destabilized the branch a bit; I am somewhat unsure whether it is
better to fix the problems first and then add this patch or vice versa
(commiting the patch first would mean less work, fixing them first might
be seen more safe).

Zdenek

	* Makefile.in (gimple-low.o): Add GGC_H dependency.
	* basic-block.h (struct basic_block_def): Fields head_tree_p,
	end_tree_p removed, head_tree, end_tree added.
	(tree_cell_root): Declare.
	* c-call-graph.c (construct_call_graph): Disable code to dump cfg
	statistics.
	* cfg.c (compact_blocks): Update tree_cell_root entries.
	* gimple-low.c: Include ggc.h.
	(struct lower_data): New field last.
	(lower_function_body, lower_stmt, lower_cond_expr, lower_bind_expr):
	Return the chain of cells.
	(appendm tree_cell_alloc, unchain, dump_chain): New.
	* tree-cfg.c (tree_cell_root): New variable.
	(prepend_stmt_to_bb, first_exec_stmt, bsi_init,
	bsi_update_from_tsi, bsi_link_after): Removed.
	(append_stmt_to_bb, create_bb): Update tree_cell_root.
	(remove_stmt, replace_stmt, make_blocks, remove_bsi_from_block,
	tree_try_redirect_by_replacing_jump, build_tree_cfg,
	factor_computed_gotos, remove_bb, bsi_move_after, bsi_move_before,
	bsi_move_to_bb_end, remove_stmt, bsi_start, bsi_last, bsi_insert_after,
	bsi_insert_before, bsi_insert_on_edge_immediate, tree_split_edge,
	tree_make_forwarder_block, tree_try_redirect_by_replacing_jump): Work over
	chains of cells.
	(bsi_remove_leave_annot): New.
	(bsi_remove): Always remove annotations.
	(nonlocal_goto_p): New.
	(make_edges): Make entry edge fallthru.
	(make_ctrl_stmt_edges): Use nonlocal_goto_p.
	(cleanup_cond_expr_graph): Reset edge flags.
	(tree_cfg2dot): Use head_tree instead of head_tree_p.
	(delete_tree_cfg): Return chain of statements.
	(tree_move_block_after, tree_cleanup_block_edges): New.
	(bsi_prev): Moved to tree-flow-inline.h.
	(push_bsi, pop_bsi, bsi_next_in_bb): Removed.
	(tree_verify_flow_info): New checks added.
	* tree-flow-inline.h (bsi_end_p, bsi_next, bsi_stmt_ptr, bsi_stmt,
	tsi_from_bsi): Work over chains of cells.
	(bsi_container): Removed
	(bsi_cell): New.
	(struct bsi_list_d, new_bsi_list, empty_bsi_stack): Removed.
	(FOR_EACH_STMT_IN_REVERSE, FOR_EACH_BSI_IN_REVERSE): Removed.
	* tree-flow.h (struct tree_container, tree_cell): New.
	(block_stmt_iterator): Base it on cells.
	(bsi_prev, build_tree_cfg, delete_tree_cfg, lower_function_body):
	Declaration changed.
	(bsi_container, bsi_from_tsi, bsi_next_in_bb): Removed.
	(bsi_cell, bsi_remove_leave_annot, tree_move_block_after,
	tree_cleanup_block_edges, tree_cell_alloc, unchain, dump_chain):
	Declare.
	* tree-optimize.c (optimize_function_tree): Made static, works over
	chain of cells.  Verify_flow_info calls added.
	(tree_rest_of_compilation): Work with chain of cells.
	* tree-pretty-print.c (dump_block_info): Use head_tree instead of
	head_tree_p.
	* tree-ssa-dce.c (remove_dead_stmts): Don't use
	FOR_EACH_BSI_IN_REVERSE.
	* tree-ssa-live.c (build_tree_conflict_graph): Don't use
	FOR_EACH_STMT_IN_REVERSE.
	* tree-ssa-pre.c (split_critical_edges): Use split_edge.
	* tree.c (tsi_link_after, tsi_link_chain_after): Don't update bb
	boundaries.
	* tree.h (optimize_function_tree): Declaration removed.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.903.2.127
diff -c -3 -p -r1.903.2.127 Makefile.in
*** Makefile.in	5 Nov 2003 13:39:22 -0000	1.903.2.127
--- Makefile.in	5 Nov 2003 15:43:44 -0000
*************** gimplify.o : gimplify.c $(CONFIG_H) $(SY
*** 1593,1599 ****
  gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \
     diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \
     langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \
!    flags.h $(RTL_H) function.h
  tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \
     $(TREE_H) errors.h tree-inline.h diagnostic.h $(HASHTAB_H) \
     $(TM_H) coretypes.h
--- 1593,1599 ----
  gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \
     diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \
     langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \
!    flags.h $(RTL_H) function.h $(GGC_H)
  tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \
     $(TREE_H) errors.h tree-inline.h diagnostic.h $(HASHTAB_H) \
     $(TM_H) coretypes.h
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.153.2.32
diff -c -3 -p -r1.153.2.32 basic-block.h
*** basic-block.h	1 Nov 2003 20:27:15 -0000	1.153.2.32
--- basic-block.h	5 Nov 2003 15:43:44 -0000
*************** typedef struct basic_block_def {
*** 205,212 ****
    rtx head, end;
  
    /* Pointers to the first and last trees of the block.  */
!   tree *head_tree_p;
!   tree *end_tree_p;
  
    /* The edges into and out of the block.  */
    edge pred, succ;
--- 205,212 ----
    rtx head, end;
  
    /* Pointers to the first and last trees of the block.  */
!   struct tree_container *head_tree;
!   struct tree_container *end_tree;
  
    /* The edges into and out of the block.  */
    edge pred, succ;
*************** extern int n_edges;
*** 284,289 ****
--- 284,292 ----
  /* Index by basic block number, get basic block struct info.  */
  
  extern varray_type basic_block_info;
+ 
+ /* The root of tree_cell lists for garbage collector.  */
+ extern GTY((param_is (struct tree_container))) varray_type tree_cell_root;
  
  #define BASIC_BLOCK(N)  (VARRAY_BB (basic_block_info, (N)))
  
Index: c-call-graph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/c-call-graph.c,v
retrieving revision 1.1.4.14
diff -c -3 -p -r1.1.4.14 c-call-graph.c
*** c-call-graph.c	5 Nov 2003 13:39:23 -0000	1.1.4.14
--- c-call-graph.c	5 Nov 2003 15:43:44 -0000
*************** construct_call_graph (pretty_printer *bu
*** 119,130 ****
--- 119,132 ----
  			 ((nb_statements == 0) ? 0.0 :
  			  ((float)decision_points / (float)nb_statements)));
  
+ #if 0
  	  /* Control flow statistics.  */
  	  init_flow ();
  	  build_tree_cfg (&DECL_SAVED_TREE (node));
  	  pp_printf (buffer, " CFG-edges=\"%d\" CFG-BB=\"%d\" McCabe=\"%d\">\n",
  			 n_edges, n_basic_blocks, n_edges - n_basic_blocks + 2);
  	  delete_tree_cfg ();
+ #endif
  
  	  /* End of the node.  */
  	  INDENT (spc);
Index: cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfg.c,v
retrieving revision 1.34.2.14
diff -c -3 -p -r1.34.2.14 cfg.c
*** cfg.c	14 Oct 2003 17:31:31 -0000	1.34.2.14
--- cfg.c	5 Nov 2003 15:43:44 -0000
*************** compact_blocks (void)
*** 263,274 ****
--- 263,283 ----
    FOR_EACH_BB (bb)
      {
        BASIC_BLOCK (i) = bb;
+       if (tree_cell_root)
+ 	VARRAY_GENERIC_PTR (tree_cell_root, i) = bb->head_tree;
        bb->index = i;
        i++;
      }
  
    if (i != n_basic_blocks)
      abort ();
+ 
+   for (; i < last_basic_block; i++)
+     {
+       BASIC_BLOCK (i) = NULL;
+       if (tree_cell_root)
+ 	VARRAY_GENERIC_PTR (tree_cell_root, i) = NULL_TREE;
+     }
  
    last_basic_block = n_basic_blocks;
  }
Index: gimple-low.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimple-low.c,v
retrieving revision 1.1.4.6
diff -c -3 -p -r1.1.4.6 gimple-low.c
*** gimple-low.c	5 Nov 2003 13:39:23 -0000	1.1.4.6
--- gimple-low.c	5 Nov 2003 15:43:44 -0000
*************** Software Foundation, 59 Temple Place - S
*** 40,52 ****
--- 40,57 ----
  #include "function.h"
  #include "expr.h"
  #include "toplev.h"
+ #include "ggc.h"
  
  struct lower_data
  {
    /* Block the current statement belongs to.  */
    tree block;
+ 
+   /* The last transformed statement.  */
+   tree_cell last;
  };
  
+ static void append (tree_cell *, tree);
  static void lower_stmt_body (tree *, struct lower_data *);
  static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
  static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *);
*************** static void lower_cond_expr (tree_stmt_i
*** 54,64 ****
  static bool simple_goto_p (tree);
  
  /* Lowers the BODY.  */
! void
  lower_function_body (tree *body)
  {
    struct lower_data data;
!   tree root;
  
    if (TREE_CODE (*body) != BIND_EXPR)
      abort ();
--- 59,69 ----
  static bool simple_goto_p (tree);
  
  /* Lowers the BODY.  */
! tree_cell
  lower_function_body (tree *body)
  {
    struct lower_data data;
!   tree_cell root = NULL;
  
    if (TREE_CODE (*body) != BIND_EXPR)
      abort ();
*************** lower_function_body (tree *body)
*** 66,82 ****
    data.block = DECL_INITIAL (current_function_decl);
    BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
    BLOCK_CHAIN (data.block) = NULL_TREE;
  
    record_vars (BIND_EXPR_VARS (*body));
!   root = BIND_EXPR_BODY (*body);
!   lower_stmt_body (&root, &data);
  
    if (data.block != DECL_INITIAL (current_function_decl))
      abort ();
    BLOCK_SUBBLOCKS (data.block) =
  	  blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
  
!   *body = root;
  }
  
  /* Lowers the EXPR.  Unlike gimplification the statements are not relowered
--- 71,90 ----
    data.block = DECL_INITIAL (current_function_decl);
    BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
    BLOCK_CHAIN (data.block) = NULL_TREE;
+   data.last = NULL;
  
    record_vars (BIND_EXPR_VARS (*body));
!   lower_stmt_body (&BIND_EXPR_BODY (*body), &data);
  
    if (data.block != DECL_INITIAL (current_function_decl))
      abort ();
    BLOCK_SUBBLOCKS (data.block) =
  	  blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
  
!   for (root = data.last; root && root->prev; root = root->prev)
!     continue;
! 
!   return root;
  }
  
  /* Lowers the EXPR.  Unlike gimplification the statements are not relowered
*************** lower_stmt (tree_stmt_iterator *tsi, str
*** 105,118 ****
      {
      case BIND_EXPR:
        lower_bind_expr (tsi, data);
!       /* Avoid moving the tsi -- it has already been moved by delinking the
! 	 statement.  */
!       return;
  
      case COMPOUND_EXPR:
        abort ();
  
      case NOP_EXPR:
      case ASM_EXPR:
      case RETURN_EXPR:
      case MODIFY_EXPR:
--- 113,126 ----
      {
      case BIND_EXPR:
        lower_bind_expr (tsi, data);
!       break;
  
      case COMPOUND_EXPR:
        abort ();
  
      case NOP_EXPR:
+       break;
+ 
      case ASM_EXPR:
      case RETURN_EXPR:
      case MODIFY_EXPR:
*************** lower_stmt (tree_stmt_iterator *tsi, str
*** 122,127 ****
--- 130,136 ----
      case VA_ARG_EXPR:
      case RESX_EXPR:
      case SWITCH_EXPR:
+       append (&data->last, stmt);
        break;
  
      case COND_EXPR:
*************** lower_bind_expr (tree_stmt_iterator *tsi
*** 188,198 ****
  	      blocks_nreverse (BLOCK_SUBBLOCKS (data->block));
        data->block = old_block;
      }
- 
-   /* The BIND_EXPR no longer carries any useful information, so get rid
-      of it.  */
-   tsi_link_chain_before (tsi, BIND_EXPR_BODY (stmt), TSI_SAME_STMT);
-   tsi_delink (tsi);
  }
  
  /* Checks whether EXPR is a simple local goto.  */
--- 197,202 ----
*************** lower_cond_expr (tree_stmt_iterator *tsi
*** 215,223 ****
    tree stmt = tsi_stmt (*tsi);
    bool then_is_goto, else_is_goto;
    tree then_branch, else_branch, then_label, else_label, end_label;
!   
!   lower_stmt_body (&COND_EXPR_THEN (stmt), data);
!   lower_stmt_body (&COND_EXPR_ELSE (stmt), data);
  
    /* Find out whether the branches are ordinary local gotos.  */
    then_branch = COND_EXPR_THEN (stmt);
--- 219,226 ----
    tree stmt = tsi_stmt (*tsi);
    bool then_is_goto, else_is_goto;
    tree then_branch, else_branch, then_label, else_label, end_label;
!  
!   append (&data->last, stmt);
  
    /* Find out whether the branches are ordinary local gotos.  */
    then_branch = COND_EXPR_THEN (stmt);
*************** lower_cond_expr (tree_stmt_iterator *tsi
*** 249,273 ****
    end_label = NULL_TREE;
    if (then_label)
      {
!       tsi_link_after (tsi, then_label, TSI_CONTINUE_LINKING);
!       tsi_link_chain_after (tsi, then_branch, TSI_CONTINUE_LINKING);
    
        if (else_label)
  	{
  	  end_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
! 	  tsi_link_after (tsi, build_and_jump (&LABEL_EXPR_LABEL (end_label)),
! 			  TSI_CONTINUE_LINKING);
  	}
      }
    
    if (else_label)
      {
!       tsi_link_after (tsi, else_label, TSI_CONTINUE_LINKING);
!       tsi_link_chain_after (tsi, else_branch, TSI_CONTINUE_LINKING);
      }
  
    if (end_label)
!     tsi_link_after (tsi, end_label, TSI_CONTINUE_LINKING);
  }
  
  /* Expand those variables in the unexpanded_var_list that are used.  */
--- 252,275 ----
    end_label = NULL_TREE;
    if (then_label)
      {
!       append (&data->last, then_label);
!       lower_stmt_body (&then_branch, data);
    
        if (else_label)
  	{
  	  end_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
! 	  append (&data->last, build_and_jump (&LABEL_EXPR_LABEL (end_label)));
  	}
      }
    
    if (else_label)
      {
!       append (&data->last, else_label);
!       lower_stmt_body (&else_branch, data);
      }
  
    if (end_label)
!     append (&data->last, end_label);
  }
  
  /* Expand those variables in the unexpanded_var_list that are used.  */
*************** expand_used_vars (void)
*** 304,307 ****
--- 306,385 ----
      }
  
    cfun->unexpanded_var_list = NULL_TREE;
+ }
+ 
+ /* Allocate a new tree_cell for tree T.  */
+ 
+ tree_cell
+ tree_cell_alloc (tree t)
+ {
+   tree_cell nw = ggc_alloc (sizeof (struct tree_container));
+ 
+   nw->stmt = t;
+   nw->prev = nw->next = NULL;
+ 
+   return nw;
+ }
+ 
+ /* Appends statement STMT to the end of list AFTER.  */
+ 
+ static void
+ append (tree_cell *after, tree stmt)
+ {
+   tree_cell nw = tree_cell_alloc (stmt);
+ 
+   nw->next = NULL;
+   nw->prev = *after;
+   if (*after)
+     (*after)->next = nw;
+   *after = nw;
+ }
+ 
+ /* Replaces tree_cells in CHAIN by COMPOUND_EXPRs.  */
+ 
+ tree
+ unchain (tree_cell chain)
+ {
+   tree ret = NULL;
+   tree_stmt_iterator tsi = tsi_start (&ret);
+ 
+   for (; chain; chain = chain->next)
+     tsi_link_after (&tsi, chain->stmt, TSI_NEW_STMT);
+ 
+   if (!ret)
+     ret = build_empty_stmt ();
+ 
+   return ret;
+ }
+ 
+ /* Dump CHAIN of statements of function FNDECL to STREAM, with details given
+    by flags.  */
+ 
+ void
+ dump_chain (FILE *stream, tree fndecl, tree_cell chain, int flags)
+ {
+   tree arg;
+ 
+   fprintf (stream, "\n;; Function %s",
+ 	    (*lang_hooks.decl_printable_name) (fndecl, 2));
+   fprintf (stream, " (%s)\n",
+ 	    IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)));
+   fprintf (stream, "\n");
+ 
+   fprintf (stream, "%s (", (*lang_hooks.decl_printable_name) (fndecl, 2));
+ 
+   arg = DECL_ARGUMENTS (fndecl);
+   while (arg)
+     {
+       print_generic_expr (stream, arg, 0);
+       if (TREE_CHAIN (arg))
+ 	fprintf (stream, ", ");
+       arg = TREE_CHAIN (arg);
+     }
+   fprintf (stream, ")\n{\n");
+ 
+   for (; chain; chain = chain->next)
+     print_generic_stmt (stream, chain->stmt, flags);
+ 
+   fprintf (stream, "}\n\n");
  }
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.193
diff -c -3 -p -r1.1.4.193 tree-cfg.c
*** tree-cfg.c	5 Nov 2003 13:39:23 -0000	1.1.4.193
--- tree-cfg.c	5 Nov 2003 15:43:44 -0000
*************** static tree factored_computed_goto_label
*** 85,98 ****
     the destination of computed gotos when unfactoring them.  */
  static tree factored_computed_goto;
  
  /* Basic blocks and flowgraphs.  */
  static void create_blocks_annotations (void);
  static void create_block_annotation (basic_block);
  static void free_blocks_annotations (void);
  static void clear_blocks_annotations (void);
! static basic_block make_blocks (tree *, basic_block);
! static inline void append_stmt_to_bb (tree *, basic_block);
! static inline void prepend_stmt_to_bb (tree *, basic_block);
  static void factor_computed_gotos (void);
  
  /* Edges.  */
--- 85,100 ----
     the destination of computed gotos when unfactoring them.  */
  static tree factored_computed_goto;
  
+ /* The root of tree_cell lists for garbage collector.  */
+ varray_type tree_cell_root;
+ 
  /* Basic blocks and flowgraphs.  */
  static void create_blocks_annotations (void);
  static void create_block_annotation (basic_block);
  static void free_blocks_annotations (void);
  static void clear_blocks_annotations (void);
! static void make_blocks (tree_cell);
! static inline void append_stmt_to_bb (tree_cell, basic_block);
  static void factor_computed_gotos (void);
  
  /* Edges.  */
*************** static void make_switch_expr_edges (basi
*** 104,110 ****
  static void make_goto_expr_edges (basic_block);
  
  /* Various helpers.  */
- static tree *first_exec_stmt (tree *);
  static inline bool stmt_starts_bb_p (tree, tree);
  static inline bool stmt_ends_bb_p (tree);
  static int tree_verify_flow_info (void);
--- 106,111 ----
*************** static bool tree_forwarder_block_p (basi
*** 117,137 ****
  /* Flowgraph optimization and cleanup.  */
  
  static void remove_bb (basic_block);
! static void remove_stmt (tree *, bool);
  static bool cleanup_control_flow (void);
  static edge find_taken_edge_cond_expr (basic_block, tree);
  static edge find_taken_edge_switch_expr (basic_block, tree);
  static tree find_case_label_for_value (tree, tree);
! static void replace_stmt (tree *, tree *);
  static int phi_alternatives_equal (basic_block, edge, edge);
! 
! /* Block iterator helpers.  */
! static void remove_bsi_from_block (block_stmt_iterator *, bool);
! static block_stmt_iterator bsi_init (tree *, basic_block);
! static inline void bsi_update_from_tsi (block_stmt_iterator *,
! 					tree_stmt_iterator);
! static tree_stmt_iterator bsi_link_after (tree_stmt_iterator *, tree,
! 					  basic_block);
  
  /* Location to track pending stmt for edge insertion.  */
  #define PENDING_STMT(e)	((tree)(e->insns))
--- 118,132 ----
  /* Flowgraph optimization and cleanup.  */
  
  static void remove_bb (basic_block);
! static void remove_stmt (tree_cell, basic_block, bool);
  static bool cleanup_control_flow (void);
  static edge find_taken_edge_cond_expr (basic_block, tree);
  static edge find_taken_edge_switch_expr (basic_block, tree);
  static tree find_case_label_for_value (tree, tree);
! static void replace_stmt (tree_cell, tree);
  static int phi_alternatives_equal (basic_block, edge, edge);
! static edge tree_try_redirect_by_replacing_jump (edge, basic_block);
! static bool nonlocal_goto_p (tree);
  
  /* Location to track pending stmt for edge insertion.  */
  #define PENDING_STMT(e)	((tree)(e->insns))
*************** static tree_stmt_iterator bsi_link_after
*** 156,165 ****
     function to process.  */
  
  void
! build_tree_cfg (tree *fnbody)
  {
-   tree *first_p;
- 
    timevar_push (TV_TREE_CFG);
  
    /* Register specific tree functions.  */
--- 151,158 ----
     function to process.  */
  
  void
! build_tree_cfg (tree_cell fnbody)
  {
    timevar_push (TV_TREE_CFG);
  
    /* Register specific tree functions.  */
*************** build_tree_cfg (tree *fnbody)
*** 169,174 ****
--- 162,168 ----
    n_basic_blocks = 0;
    last_basic_block = 0;
    VARRAY_BB_INIT (basic_block_info, initial_cfg_capacity, "basic_block_info");
+   VARRAY_GENERIC_PTR_INIT (tree_cell_root, initial_cfg_capacity, "tree_cell_root");
    memset ((void *) &cfg_stats, 0, sizeof (cfg_stats));
  
    /* Build a mapping of labels to their associated blocks.  */
*************** build_tree_cfg (tree *fnbody)
*** 178,246 ****
    ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR;
    EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR;
  
!   first_p = first_exec_stmt (fnbody);
!   if (first_p)
      {
!       found_computed_goto = 0;
!       make_blocks (first_p, NULL);
  
!       /* Computed gotos are hell to deal with, especially if there are
! 	 lots of them with a large number of destinations.  So we factor
! 	 them to a common computed goto location before we build the
! 	 edge list.  After we convert back to normal form, we will un-factor
! 	 the computed gotos since factoring introduces an unwanted jump.  */
!       if (found_computed_goto)
! 	factor_computed_gotos ();
! 
!       if (n_basic_blocks > 0)
! 	{
! 	  /* Adjust the size of the array.  */
! 	  VARRAY_GROW (basic_block_info, n_basic_blocks);
! 
! 	  /* Create block annotations.  */
! 	  create_blocks_annotations ();
! 
! 	  /* Create the edges of the flowgraph.  */
! 	  make_edges ();
! 	}
      }
  
! #if 0
!   {
!     /* The loop analyzer should be initialized right after the CFG
!        construction because some loops will need latch blocks, and these
!        need to be added before we do anything else.  If you use this
!        structure you'll have to ensure that optimizers don't invalidate the
!        information gathered in the loops structure via modifications to the
!        underlying structure: the CFG.  */
!     struct loops *loops = loop_optimizer_init (NULL);
! 
!     /* Once initialized, it's not really necessary to keep the loop data
!        structures around.  They may be rescanned using flow_loops_find.  */
!     loop_optimizer_finalize (loops, NULL);
!   }
! #endif
  
    timevar_pop (TV_TREE_CFG);
  
    /* Debugging dumps.  */
!   if (n_basic_blocks > 0)
      {
!       /* Write the flowgraph to a dot file.  */
!       dump_file = dump_begin (TDI_dot, &dump_flags);
!       if (dump_file)
! 	{
! 	  tree_cfg2dot (dump_file);
! 	  dump_end (TDI_dot, dump_file);
! 	}
  
!       /* Dump a textual representation of the flowgraph.  */
!       dump_file = dump_begin (TDI_cfg, &dump_flags);
!       if (dump_file)
! 	{
! 	  dump_tree_cfg (dump_file, dump_flags);
! 	  dump_end (TDI_cfg, dump_file);
! 	}
      }
  }
  
--- 172,227 ----
    ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR;
    EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR;
  
!   if (!fnbody)
      {
!       timevar_pop (TV_TREE_CFG);
!       return;
!     }
!       
!   /* Create block annotations.  */
!   create_blocks_annotations ();
  
!   make_blocks (fnbody);
! 
!   /* Computed gotos are hell to deal with, especially if there are
!      lots of them with a large number of destinations.  So we factor
!      them to a common computed goto location before we build the
!      edge list.  After we convert back to normal form, we will un-factor
!      the computed gotos since factoring introduces an unwanted jump.  */
!   if (found_computed_goto)
!     factor_computed_gotos ();
! 
!   if (!n_basic_blocks)
!     {
!       timevar_pop (TV_TREE_CFG);
!       return;
      }
+     
+   /* Adjust the size of the array.  */
+   VARRAY_GROW (basic_block_info, n_basic_blocks);
+   VARRAY_GROW (tree_cell_root, n_basic_blocks);
  
!   /* Create the edges of the flowgraph.  */
!   make_edges ();
  
    timevar_pop (TV_TREE_CFG);
  
    /* Debugging dumps.  */
! 
!   /* Write the flowgraph to a dot file.  */
!   dump_file = dump_begin (TDI_dot, &dump_flags);
!   if (dump_file)
      {
!       tree_cfg2dot (dump_file);
!       dump_end (TDI_dot, dump_file);
!     }
  
!   /* Dump a textual representation of the flowgraph.  */
!   dump_file = dump_begin (TDI_cfg, &dump_flags);
!   if (dump_file)
!     {
!       dump_tree_cfg (dump_file, dump_flags);
!       dump_end (TDI_cfg, dump_file);
      }
  }
  
*************** build_tree_cfg (tree *fnbody)
*** 252,258 ****
  static void
  factor_computed_gotos (void)
  {
!   basic_block bb;
    tree factored_label_decl = NULL;
    tree var = NULL;
  
--- 233,239 ----
  static void
  factor_computed_gotos (void)
  {
!   basic_block bb, new_bb;
    tree factored_label_decl = NULL;
    tree var = NULL;
  
*************** factor_computed_gotos (void)
*** 274,289 ****
        if (is_computed_goto (last))
  	{
  	  tree assignment;
! 	  block_stmt_iterator bsi = bsi_last (bb);
  
  	  /* The first time we find a computed goto we need to create
  	     the factored goto block and the variable each original
  	     computed goto will use for their goto destination.  */
  	  if (! factored_computed_goto)
  	    {
- 	      tree compound;
- 	      tree_stmt_iterator tsi = tsi_from_bsi (bsi);
- 
  	      /* Create the destination of the factored goto.  Each original
  		 computed goto will put its desired destination into this
  		 variable and jump to the label we create immediately
--- 255,267 ----
        if (is_computed_goto (last))
  	{
  	  tree assignment;
! 	  block_stmt_iterator bsi = bsi_last (bb), new_bsi;
  
  	  /* The first time we find a computed goto we need to create
  	     the factored goto block and the variable each original
  	     computed goto will use for their goto destination.  */
  	  if (! factored_computed_goto)
  	    {
  	      /* Create the destination of the factored goto.  Each original
  		 computed goto will put its desired destination into this
  		 variable and jump to the label we create immediately
*************** factor_computed_gotos (void)
*** 302,325 ****
  	      modify_stmt (factored_computed_goto);
  
  	      /* Cram the new label and the computed goto into a container.  */
! 	      compound = build (COMPOUND_EXPR, void_type_node,
! 				factored_computed_goto_label,
! 				factored_computed_goto);
! 
! 	      /* Ugh.  We want to pass the address of the container to
! 		 make_blocks call below.  But we certainly don't want to
! 		 to pass along the address of a global.  There's got to be
! 		 a better way to do this than to create a dummy container.  */
! 	      compound = build (COMPOUND_EXPR, void_type_node, compound, NULL);
! 
! 	      /* Put the new statements into a new basic block.  This must
! 		 be done before we link them into the statement chain!  */
! 	      make_blocks (&TREE_OPERAND (compound, 0), NULL);
! 
! 	      /* Now it is safe to link in the new statements.  */
! 	      tsi_link_chain_after (&tsi,
! 				    TREE_OPERAND (compound, 0),
! 				    TSI_CHAIN_START);
  	    }
  
  	  /* Copy the original computed goto's destination into VAR.  */
--- 280,292 ----
  	      modify_stmt (factored_computed_goto);
  
  	      /* Cram the new label and the computed goto into a container.  */
! 	      new_bb = create_bb ();
! 	      new_bsi = bsi_start (new_bb);
! 	      
! 	      bsi_insert_after (&new_bsi, factored_computed_goto_label,
! 				BSI_NEW_STMT);
! 	      bsi_insert_after (&new_bsi, factored_computed_goto,
! 				BSI_NEW_STMT);
  	    }
  
  	  /* Copy the original computed goto's destination into VAR.  */
*************** factor_computed_gotos (void)
*** 337,345 ****
  	}
      }
  }
  /* Create annotations for all the basic blocks.  */
  
! static void create_blocks_annotations (void)
  {
    basic_block bb;
    static int initialized;
--- 304,314 ----
  	}
      }
  }
+ 
  /* Create annotations for all the basic blocks.  */
  
! static void
! create_blocks_annotations (void)
  {
    basic_block bb;
    static int initialized;
*************** static void create_blocks_annotations (v
*** 354,367 ****
      abort ();
    
    first_block_tree_ann_obj = obstack_alloc (&block_tree_ann_obstack, 0);
!   
    FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
      create_block_annotation (bb);
  }
  
  /* Create annotations for a single basic block.  */
  
! static void create_block_annotation (basic_block bb)
  {
    /* Verify that the tree_annotations field is clear.  */
    if (bb->tree_annotations || !first_block_tree_ann_obj)
--- 323,337 ----
      abort ();
    
    first_block_tree_ann_obj = obstack_alloc (&block_tree_ann_obstack, 0);
! 
    FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
      create_block_annotation (bb);
  }
  
  /* Create annotations for a single basic block.  */
  
! static void
! create_block_annotation (basic_block bb)
  {
    /* Verify that the tree_annotations field is clear.  */
    if (bb->tree_annotations || !first_block_tree_ann_obj)
*************** clear_blocks_annotations (void)
*** 404,495 ****
     a recursive invocation built a sub-graph whose last block can accept
     more statements or not.  */
  
! static basic_block
! make_blocks (tree *first_p, basic_block bb)
  {
!   tree_stmt_iterator i;
!   tree stmt, last;
!   bool start_new_block;
  
!   if (first_p == NULL
!       || *first_p == error_mark_node)
!     return NULL;
  
!   start_new_block = (bb == NULL);
!   stmt = last = NULL;
!   for (i = tsi_start (first_p); !tsi_end_p (i); tsi_next (&i))
      {
!       enum tree_code code;
!       tree prev_stmt;
!       tree *stmt_p = tsi_container (i);
! 
!       prev_stmt = stmt;
!       stmt = tsi_stmt (i);
  
!       /* If the statement starts a new basic block or if we have determined
! 	 in a previous pass that we need to create a new block for STMT, do
! 	 so now.  */
!       if (start_new_block || stmt_starts_bb_p (stmt, prev_stmt))
  	{
  	  bb = create_bb ();
- 	  start_new_block = false;
  	}
  
!       code = TREE_CODE (stmt);
! 
!       /* Now add STMT to BB and create the subgraphs for special statement
! 	 codes.  */
!       append_stmt_to_bb (stmt_p, bb);
! 
!       if (is_computed_goto (*stmt_p))
  	found_computed_goto = true;
  
-       /* All BIND_EXPRs except for the outermost one are lowered already.  */
-       if (code == BIND_EXPR)
- 	abort ();
- 
-       /* If STMT is a basic block terminator, set START_NEW_BLOCK for the
- 	 next iteration.  Also compute any reachable exception handlers
- 	 for STMT.  */
-       if (stmt && stmt_ends_bb_p (stmt))
- 	start_new_block = true;
  
!       last = stmt;
      }
- 
-   if (last)
-     return bb_for_stmt (last);
- 
-   return NULL;
- }
- 
- 
- static inline void
- append_stmt_to_bb (tree *stmt_p, basic_block bb)
- {
-   set_bb_for_stmt (*stmt_p, bb);
- 
-   /* Update the head and tail of the block.  */
-   if (bb->head_tree_p == NULL)
-     bb->head_tree_p = stmt_p;
- 
-   bb->end_tree_p = stmt_p;
  }
  
! 
! /* Add statement pointed by STMT_P to basic block BB and update BB's
     boundaries accordingly.  */
  
  static inline void
! prepend_stmt_to_bb (tree *stmt_p, basic_block bb)
  {
!   set_bb_for_stmt (*stmt_p, bb);
  
    /* Update the head and tail of the block.  */
!   bb->head_tree_p = stmt_p;
  
!   if (bb->end_tree_p == NULL)
!     bb->end_tree_p = stmt_p;
  }
  
  
--- 374,432 ----
     a recursive invocation built a sub-graph whose last block can accept
     more statements or not.  */
  
! static void
! make_blocks (tree_cell stmt)
  {
!   tree_cell act, next;
!   basic_block bb = NULL;
!   tree prev_stmt;
  
!   if (stmt == NULL
!       || stmt->stmt == error_mark_node)
!     return;
  
!   for (act = stmt; act; act = next)
      {
!       next = act->next;
  
!       prev_stmt = act->prev ? act->prev->stmt : NULL_TREE;
!       if (!bb || stmt_starts_bb_p (act->stmt, prev_stmt))
  	{
+ 	  if (act->prev)
+ 	    act->prev->next = NULL;
+ 	  act->prev = NULL;
  	  bb = create_bb ();
  	}
  
!       append_stmt_to_bb (act, bb);
!       if (is_computed_goto (act->stmt))
  	found_computed_goto = true;
  
  
!       if (stmt_ends_bb_p (act->stmt))
! 	{
! 	  bb = NULL;
! 	  act->next = NULL;
! 	}
      }
  }
  
! /* Add statement STMT to basic block BB and update BB's
     boundaries accordingly.  */
  
  static inline void
! append_stmt_to_bb (tree_cell stmt, basic_block bb)
  {
!   set_bb_for_stmt (stmt->stmt, bb);
  
    /* Update the head and tail of the block.  */
!   if (bb->head_tree == NULL)
!     {
!       bb->head_tree = stmt;
!       VARRAY_GENERIC_PTR (tree_cell_root, bb->index) = bb->head_tree;
!     }
  
!   bb->end_tree = stmt;
  }
  
  
*************** basic_block
*** 499,524 ****
  create_bb (void)
  {
    basic_block bb;
  
    /* Create and initialize a new basic block.  */
    bb = alloc_block ();
    memset (bb, 0, sizeof (*bb));
  
    bb->index = last_basic_block;
    bb->flags = BB_NEW;
  
    /* Add the new block to the linked list of blocks.  */
!   if (n_basic_blocks > 0)
!     link_block (bb, BASIC_BLOCK (n_basic_blocks - 1));
!   else
!     link_block (bb, ENTRY_BLOCK_PTR);
  
    /* Grow the basic block array if needed.  */
!   if ((size_t) n_basic_blocks == VARRAY_SIZE (basic_block_info))
!     VARRAY_GROW (basic_block_info, n_basic_blocks + (n_basic_blocks + 3) / 4);
  
    /* Add the newly created block to the array.  */
!   BASIC_BLOCK (n_basic_blocks) = bb;
    n_basic_blocks++;
    last_basic_block++;
  
--- 436,478 ----
  create_bb (void)
  {
    basic_block bb;
+   edge e;
+   int l;
  
    /* Create and initialize a new basic block.  */
    bb = alloc_block ();
    memset (bb, 0, sizeof (*bb));
+   create_block_annotation (bb);
  
    bb->index = last_basic_block;
    bb->flags = BB_NEW;
  
    /* Add the new block to the linked list of blocks.  */
!   link_block (bb, EXIT_BLOCK_PTR->prev_bb);
! 
!   /* Fixup exit predecessor.  */
!   for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
!     if (e->flags & EDGE_FALLTHRU)
!       break;
!   if (e && e->src != EXIT_BLOCK_PTR->prev_bb)
!     tree_move_block_after (e->src, EXIT_BLOCK_PTR->prev_bb, true);
  
    /* Grow the basic block array if needed.  */
!   if ((size_t) last_basic_block == VARRAY_SIZE (basic_block_info))
!     {
!       l = last_basic_block + (last_basic_block + 3) / 4;
! 
!       if ((size_t) last_basic_block != VARRAY_SIZE (tree_cell_root))
! 	abort ();
! 
!       VARRAY_GROW (basic_block_info, l);
!       VARRAY_GROW (tree_cell_root, l);
!     }
  
    /* Add the newly created block to the array.  */
!   if (VARRAY_GENERIC_PTR (tree_cell_root, last_basic_block))
!     abort ();
!   BASIC_BLOCK (last_basic_block) = bb;
    n_basic_blocks++;
    last_basic_block++;
  
*************** make_edges (void)
*** 538,544 ****
  
    /* Create an edge from entry to the first block with executable
       statements in it.  */
!   make_edge (ENTRY_BLOCK_PTR, BASIC_BLOCK (0), 0);
  
    /* Traverse basic block array placing edges.  */
    FOR_EACH_BB (bb)
--- 492,498 ----
  
    /* Create an edge from entry to the first block with executable
       statements in it.  */
!   make_edge (ENTRY_BLOCK_PTR, ENTRY_BLOCK_PTR->next_bb, EDGE_FALLTHRU);
  
    /* Traverse basic block array placing edges.  */
    FOR_EACH_BB (bb)
*************** make_edges (void)
*** 571,576 ****
--- 525,541 ----
    cleanup_tree_cfg ();
  }
  
+ /* Checks whether STMT is potentially a nonlocal goto.  */
+ static bool
+ nonlocal_goto_p (tree stmt)
+ {
+   return (TREE_CODE (GOTO_DESTINATION (stmt)) == LABEL_DECL
+ 	  && (decl_function_context (GOTO_DESTINATION (stmt))
+ 	       != current_function_decl))
+ 	  || (TREE_CODE (GOTO_DESTINATION (stmt)) != LABEL_DECL
+ 	      && DECL_CONTEXT (current_function_decl));
+ }
+ 
  /* Create edges for control statement at basic block BB.  */
  
  static void
*************** make_ctrl_stmt_edges (basic_block bb)
*** 590,600 ****
  
        /* If this is potentially a nonlocal goto, then this should also
  	 create an edge to the exit block.   */
!       if ((TREE_CODE (GOTO_DESTINATION (last)) == LABEL_DECL
! 	   && (decl_function_context (GOTO_DESTINATION (last))
! 	       != current_function_decl))
! 	  || (TREE_CODE (GOTO_DESTINATION (last)) != LABEL_DECL
! 	      && DECL_CONTEXT (current_function_decl)))
  	make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
        break;
  
--- 555,561 ----
  
        /* If this is potentially a nonlocal goto, then this should also
  	 create an edge to the exit block.   */
!       if (nonlocal_goto_p (last))
  	make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
        break;
  
*************** static void
*** 1343,1351 ****
  remove_bb (basic_block bb)
  {
    block_stmt_iterator i;
-   bsi_list_p stack;
    location_t loc;
-   bool empty = true;
  
    dump_file = dump_begin (TDI_cfg, &dump_flags);
    if (dump_file)
--- 1304,1310 ----
*************** remove_bb (basic_block bb)
*** 1357,1396 ****
        dump_file = NULL;
      }
  
!   /* Remove all the instructions in the block.  Do so in reverse order
!      so that we remove all the containing COMPOUND_EXPRs as well.  */
!   FOR_EACH_BSI_IN_REVERSE (stack, bb, i)
      {
        tree stmt = bsi_stmt (i);
  
!       set_bb_for_stmt (stmt, NULL);
! 
!       if (get_lineno (stmt) != -1
! 	  /* Don't warn for removed gotos.  Gotos are often removed due to jump threading,
! 	     thus resulting into bogus warnings.  Not great, since this way we lose warnings
! 	     for gotos in the original program that are indeed unreachable.  */
! 	  && TREE_CODE (stmt) != GOTO_EXPR)
  	{
  	  loc.file = get_filename (stmt);
  	  loc.line = get_lineno (stmt);
- 	  empty = false;
  	}
        bsi_remove (&i);
      }
  
    /* If requested, give a warning that the first statement in the
       block is unreachable.  We walk statements backwards in the
       loop above, so the last statement we process is the first statement
       in the block.  */
!   if (warn_notreached && !empty)
      warning ("%Hwill never be executed", &loc);
  
-   if (bb->head_tree_p)
-     set_bb_for_stmt (*bb->head_tree_p, NULL);
- 
-   if (bb->end_tree_p)
-     set_bb_for_stmt (*bb->end_tree_p, NULL);
- 
    remove_phi_nodes_and_edges_for_unreachable_block (bb);
  
    /* If we have pdom information, then we must also make sure to
--- 1316,1344 ----
        dump_file = NULL;
      }
  
!   loc.line = -1;
! 
!   /* Remove all the instructions in the block.  */
!   for (i = bsi_last (bb); !bsi_end_p (i); i = bsi_last (bb))
      {
        tree stmt = bsi_stmt (i);
  
!       if (get_lineno (stmt) >= 0)
  	{
  	  loc.file = get_filename (stmt);
  	  loc.line = get_lineno (stmt);
  	}
        bsi_remove (&i);
+       set_bb_for_stmt (stmt, NULL);
      }
  
    /* If requested, give a warning that the first statement in the
       block is unreachable.  We walk statements backwards in the
       loop above, so the last statement we process is the first statement
       in the block.  */
!   if (warn_notreached && loc.line >= 0)
      warning ("%Hwill never be executed", &loc);
  
    remove_phi_nodes_and_edges_for_unreachable_block (bb);
  
    /* If we have pdom information, then we must also make sure to
*************** remove_bb (basic_block bb)
*** 1399,1519 ****
      delete_from_dominance_info (pdom_info, bb);
  
    /* Remove the basic block from the array.  */
    expunge_block (bb);
  }
  
! /* Remove statement pointed by iterator I.
! 
!     Note that this function will wipe out control statements that
!     may span multiple basic blocks.  Make sure that you really
!     want to remove the whole control structure before calling this
!     function.  Remove the annotations if REMOVE_ANNOTATIONS is true.  */
! 
! static void
! remove_bsi_from_block (block_stmt_iterator *i, bool remove_annotations)
! {
!   tree t = *(i->tp);
! 
!   if (is_exec_stmt (t))
!     {
!       if (TREE_CODE (t) == COMPOUND_EXPR)
! 	{
! 	  basic_block op0_bb = bb_for_stmt (TREE_OPERAND (t, 0));
! 	  basic_block op1_bb = bb_for_stmt (TREE_OPERAND (t, 1));
! 
! 	  remove_stmt (&TREE_OPERAND (t, 0), remove_annotations);
! 
! 	  /* If both operands are empty and they are not associated
! 	     with different basic blocks, then delete the whole
! 	     COMPOUND_EXPR.  */
! 	  if (IS_EMPTY_STMT (TREE_OPERAND (t, 1))
! 	      && (op0_bb == NULL
! 		  || op1_bb == NULL
! 		  || op0_bb == op1_bb))
! 	    remove_stmt (i->tp, remove_annotations);
! 	}
!       else
! 	remove_stmt (i->tp, remove_annotations);
!     }
!   
!   bsi_next (i);
! }
! 
! void
! bsi_remove (block_stmt_iterator *i)
! {
!   remove_bsi_from_block (i, true);
! }
! 
! /* Move the statement at FROM so it comes right after the statement at
!    TO.  */
! void 
! bsi_move_after (block_stmt_iterator from, block_stmt_iterator to)
! {
!   tree stmt = bsi_stmt (from);
!   remove_bsi_from_block (&from, false);
!   bsi_insert_after (&to, stmt, BSI_SAME_STMT);
! } 
! 
! /* Move the statement at FROM so it comes right before the statement
!    at TO.  */
! void 
! bsi_move_before (block_stmt_iterator from, block_stmt_iterator to)
! {
!   tree stmt = bsi_stmt (from);
!   remove_bsi_from_block (&from, false);
!   bsi_insert_before (&to, stmt, BSI_SAME_STMT);
! }
! 
! /* Move the statement at FROM to the end of basic block BB, */
! void
! bsi_move_to_bb_end (block_stmt_iterator from, basic_block bb)
! {
!   block_stmt_iterator last = bsi_last (bb);
!   
!   /* Have to check bsi_end_p because it could be an empty block.  */
!   if (!bsi_end_p (last)
!       && is_ctrl_stmt (bsi_stmt (last)))
!     {
!       bsi_move_before (from, last);
!     }
!   else
!     {
!       bsi_move_after (from, last);
!     }
! }
! 
! /* Replace the contents of a stmt with another. The replacement cannot be
!    a COMPOUND_EXPR node, only a gimple stmt.  */
! 
! void
! bsi_replace (block_stmt_iterator bsi, tree stmt)
! {
!   if (TREE_CODE (stmt) == COMPOUND_EXPR)
!     abort ();
! 
!   replace_stmt (bsi.tp, &stmt);
!   modify_stmt (bsi_stmt (bsi));
! }
! 
! /* Remove statement *STMT_P.
! 
!    Update all references associated with it.  Note that this function will
!    wipe out control statements that may span multiple basic blocks.  Make
!    sure that you really want to remove the whole control structure before
!    calling this function.
!    Reset the annotations if REMOVE_ANNOTATIONS is true.  */
  
  static void
! remove_stmt (tree *stmt_p, bool remove_annotations)
  {
    varray_type vdefs;
    size_t i;
    varray_type defs;
!   tree stmt = *stmt_p;
!   basic_block bb = bb_for_stmt (stmt);
!   int update_head = 0;
!   int update_end = 0;
  
    /* If the statement is a LABEL_EXPR, remove the LABEL_DECL from
       the symbol table.  */
--- 1347,1367 ----
      delete_from_dominance_info (pdom_info, bb);
  
    /* Remove the basic block from the array.  */
+   VARRAY_GENERIC_PTR (tree_cell_root, bb->index) = NULL_TREE;
    expunge_block (bb);
  }
  
! /* Remove statement CELL in basic block BB.  Reset the annotations if
!    REMOVE_ANNOTATIONS is true.  */
  
  static void
! remove_stmt (tree_cell cell, basic_block bb, bool remove_annotations)
  {
    varray_type vdefs;
    size_t i;
    varray_type defs;
!   tree stmt = cell->stmt;
!   stmt_ann_t ann = get_stmt_ann (stmt);
  
    /* If the statement is a LABEL_EXPR, remove the LABEL_DECL from
       the symbol table.  */
*************** remove_stmt (tree *stmt_p, bool remove_a
*** 1530,1544 ****
  	 definitions made here, but that is expensive and can easily
  	 be checked by every pass by checking if SSA_NAME_DEF_STMT is
  	 a nop.  */ 
-       stmt_ann_t ann = stmt_ann (stmt);
        defs = def_ops (ann);
        for (i = 0; defs && i < VARRAY_ACTIVE_SIZE (defs); i++)
  	{
! 	  tree *def_p = VARRAY_TREE_PTR (defs, i);
  	  if (TREE_CODE (*def_p) == SSA_NAME)
  	    SSA_NAME_DEF_STMT (*def_p) = build_empty_stmt ();
  	}
!       
        vdefs = vdef_ops (ann);
        for (i = 0; vdefs && i < VARRAY_ACTIVE_SIZE (vdefs); i++)
  	{
--- 1378,1391 ----
  	 definitions made here, but that is expensive and can easily
  	 be checked by every pass by checking if SSA_NAME_DEF_STMT is
  	 a nop.  */ 
        defs = def_ops (ann);
        for (i = 0; defs && i < VARRAY_ACTIVE_SIZE (defs); i++)
  	{
! 	  tree *def_p = VARRAY_GENERIC_PTR (defs, i);
  	  if (TREE_CODE (*def_p) == SSA_NAME)
  	    SSA_NAME_DEF_STMT (*def_p) = build_empty_stmt ();
  	}
! 
        vdefs = vdef_ops (ann);
        for (i = 0; vdefs && i < VARRAY_ACTIVE_SIZE (vdefs); i++)
  	{
*************** remove_stmt (tree *stmt_p, bool remove_a
*** 1546,1552 ****
  	  if (TREE_CODE (vdef) == SSA_NAME)
  	    SSA_NAME_DEF_STMT (vdef) = build_empty_stmt ();
  	}
!       
        stmt->common.ann = NULL;
      }
  
--- 1393,1399 ----
  	  if (TREE_CODE (vdef) == SSA_NAME)
  	    SSA_NAME_DEF_STMT (vdef) = build_empty_stmt ();
  	}
!   
        stmt->common.ann = NULL;
      }
  
*************** remove_stmt (tree *stmt_p, bool remove_a
*** 1563,1606 ****
        && TREE_OPERAND (stmt, 1)->common.ann->common.type == TREE_ANN_COMMON)
      TREE_OPERAND (stmt, 1)->common.ann = NULL;
  
!   /* If we are removing a COMPOUND_EXPR, we may need to update block
!      head/tail pointers which point into operands of the COMPOUND_EXPR.  */
!   if (TREE_CODE (stmt) == COMPOUND_EXPR)
      {
!       basic_block op0_bb = bb_for_stmt (TREE_OPERAND (stmt, 0));
!       basic_block op1_bb = bb_for_stmt (TREE_OPERAND (stmt, 1));
  
! #ifdef ENABLE_CHECKING
!       if (op0_bb && op1_bb && op0_bb != op1_bb)
! 	abort ();
! #endif
  
!       if (op0_bb)
! 	bb = op0_bb;
!       else
! 	bb = op1_bb;
  
!       if (bb
! 	  && (&TREE_OPERAND (stmt, 0) == bb->head_tree_p
! 	      || &TREE_OPERAND (stmt, 1) == bb->head_tree_p))
! 	update_head = 1;
  
!       if (bb
! 	  && (&TREE_OPERAND (stmt, 0) == bb->end_tree_p
! 	      || &TREE_OPERAND (stmt, 1) == bb->end_tree_p))
! 	update_end = 1;
!     }
  
!   /* Replace STMT with an empty statement.  */
!   *stmt_p = build_empty_stmt ();
!   if (bb)
!     set_bb_for_stmt (*stmt_p, bb);
  
!   if (update_head)
!     bb->head_tree_p = stmt_p;
  
!   if (update_end)
!     bb->end_tree_p = stmt_p;
  }
  
  /* Examine BB to determine if it is a forwarding block (a block which only
--- 1410,1501 ----
        && TREE_OPERAND (stmt, 1)->common.ann->common.type == TREE_ANN_COMMON)
      TREE_OPERAND (stmt, 1)->common.ann = NULL;
  
!   if (cell->prev)
!     cell->prev->next = cell->next;
!   else
      {
!       bb->head_tree = cell->next;
!       VARRAY_GENERIC_PTR (tree_cell_root, bb->index) = bb->head_tree;
!     }
  
!   if (cell->next)
!     cell->next->prev = cell->prev;
!   else
!     bb->end_tree = cell->prev;
  
!   cell->prev = cell->next = NULL;
! }
  
! /* Remove statement pointed by iterator I.  */
  
! void
! bsi_remove (block_stmt_iterator *i)
! {
!   tree_cell cell = bsi_cell (*i);
! 
!   bsi_next (i);
! 
!   remove_stmt (cell, i->bb, true);
! }
! 
! /* Remove statement pointed by iterator I, but leave the annotations.  */
! 
! void
! bsi_remove_leave_annot (block_stmt_iterator *i)
! {
!   tree_cell cell = bsi_cell (*i);
! 
!   bsi_next (i);
! 
!   remove_stmt (cell, i->bb, false);
! }
! 
! /* Move the statement at FROM so it comes right after the statement at
!    TO.  */
! void 
! bsi_move_after (block_stmt_iterator from, block_stmt_iterator to)
! {
!   tree stmt = bsi_stmt (from);
!   bsi_remove_leave_annot (&from);
!   bsi_insert_after (&to, stmt, BSI_SAME_STMT);
! } 
! 
! /* Move the statement at FROM so it comes right before the statement
!    at TO.  */
! void 
! bsi_move_before (block_stmt_iterator from, block_stmt_iterator to)
! {
!   tree stmt = bsi_stmt (from);
!   bsi_remove_leave_annot (&from);
!   bsi_insert_before (&to, stmt, BSI_SAME_STMT);
! }
  
! /* Move the statement at FROM to the end of basic block BB, */
! void
! bsi_move_to_bb_end (block_stmt_iterator from, basic_block bb)
! {
!   block_stmt_iterator last = bsi_last (bb);
!   
!   /* Have to check bsi_end_p because it could be an empty block.  */
!   if (!bsi_end_p (last)
!       && is_ctrl_stmt (bsi_stmt (last)))
!     {
!       bsi_move_before (from, last);
!     }
!   else
!     {
!       bsi_move_after (from, last);
!     }
! }
  
! /* Replace the contents of a stmt with another. The replacement cannot be
!    a COMPOUND_EXPR node, only a gimple stmt.  */
  
! void
! bsi_replace (block_stmt_iterator bsi, tree stmt)
! {
!   replace_stmt (bsi_cell (bsi), stmt);
!   modify_stmt (bsi_stmt (bsi));
  }
  
  /* Examine BB to determine if it is a forwarding block (a block which only
*************** cleanup_cond_expr_graph (basic_block bb,
*** 1766,1771 ****
--- 1661,1668 ----
    else
      abort ();
  
+   taken_edge->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+   
    return retval;
  }
  
*************** tree_cfg2dot (FILE *file)
*** 2277,2283 ****
          {
  	  head_code = TREE_CODE (first);
  	  head_name = tree_code_name[head_code];
! 	  head_line = get_lineno (*(bb->head_tree_p));
  	}
        else
          head_name = "no-statement";
--- 2174,2180 ----
          {
  	  head_code = TREE_CODE (first);
  	  head_name = tree_code_name[head_code];
! 	  head_line = get_lineno (bb->head_tree->stmt);
  	}
        else
          head_name = "no-statement";
*************** tree_cfg2dot (FILE *file)
*** 2286,2292 ****
          {
  	  end_code = TREE_CODE (last);
  	  end_name = tree_code_name[end_code];
! 	  end_line = get_lineno (*(bb->end_tree_p));
  	}
        else
          end_name = "no-statement";
--- 2183,2189 ----
          {
  	  end_code = TREE_CODE (last);
  	  end_name = tree_code_name[end_code];
! 	  end_line = get_lineno (bb->end_tree->stmt);
  	}
        else
          end_name = "no-statement";
*************** stmt_ends_bb_p (tree t)
*** 2458,2499 ****
  }
  
  
! /* Remove all the blocks and edges that make up the flowgraph.  */
! 
  void
! delete_tree_cfg (void)
  {
!   if (n_basic_blocks > 0)
!     free_blocks_annotations ();
  
!   free_basic_block_vars (0);
! }
  
  
! /* Return a pointer to the first executable statement starting at ENTRY_P.  */
  
! static tree *
! first_exec_stmt (tree *entry_p)
  {
!   tree_stmt_iterator i;
!   tree stmt;
  
!   for (i = tsi_start (entry_p); !tsi_end_p (i); tsi_next (&i))
      {
!       stmt = tsi_stmt (i);
!       if (!stmt)
!         continue;
  
!       /* Note that we actually return the container for the executable
! 	 statement, not the statement itself.  This is to allow the caller to
! 	 start iterating from this point.  */
!       if (is_exec_stmt (stmt))
! 	return tsi_container (i);
      }
  
!   return NULL;
  }
  
  /* Return the first statement in basic block BB, stripped of any NOP
     containers.  */
  
--- 2355,2411 ----
  }
  
  
! /* Moves basic block BB after block AFTER.  */
  void
! tree_move_block_after (basic_block bb, basic_block after, bool no_false_fallthru)
  {
!   basic_block prev = bb->prev_bb;
  
!   if (bb->prev_bb == after)
!     return;
  
+   unlink_block (bb);
+   link_block (bb, after);
+ 
+   /* Fix up fallthru edges.  */
+   if (prev && prev != ENTRY_BLOCK_PTR)
+     tree_cleanup_block_edges (prev, no_false_fallthru);
+   tree_cleanup_block_edges (bb, no_false_fallthru);
+   tree_cleanup_block_edges (after, no_false_fallthru);
+ }
  
! /* Remove all the blocks and edges that make up the flowgraph.  */
  
! tree_cell
! delete_tree_cfg (void)
  {
!   tree_cell chain = NULL, last = NULL;
!   basic_block bb;
  
!   FOR_EACH_BB (bb)
      {
!       if (!bb->head_tree)
! 	continue;
  
!       if (last)
! 	last->next = bb->head_tree;
!       else
! 	chain = bb->head_tree;
! 
!       bb->head_tree->prev = last;
!       last = bb->end_tree;
      }
  
!   if (n_basic_blocks > 0)
!     free_blocks_annotations ();
! 
!   free_basic_block_vars (0);
!   tree_cell_root = NULL;
! 
!   return chain;
  }
  
+ 
  /* Return the first statement in basic block BB, stripped of any NOP
     containers.  */
  
*************** last_stmt_ptr (basic_block bb)
*** 2534,2650 ****
  }
  
  
! /* Initialize a block stmt iterator with a container that contains stmt's
!    in a specified basic block. If the first real stmt is not in the
!    specified basic block, then return an empty iterator.  */
  
! static block_stmt_iterator
! bsi_init (tree *tp, basic_block bb)
  {
    block_stmt_iterator i;
-   tree stmt;
- 
-   i.tp = tp;
-   i.context = NULL_TREE;
-   /* If the first statement is empty, get the next non-empty one.  */
-   if (i.tp != NULL)
-     {
-       stmt = bsi_stmt (i);
-       if (stmt == NULL_TREE)
- 	bsi_next_in_bb (&i, bb);
-     }
- 
-   /* Now check that its the right basic block.  */
-   if (i.tp != NULL)
-     {
-       stmt = bsi_stmt (i);
-       if (bb_for_stmt (stmt) != bb)
-         i.tp = NULL;
-     }
- 
-   return i;
- }
- 
- /* Similar to tsi_step() but stops at basic block boundaries and ignores
-    empty statement nodes inside a basic block.  */
- 
- void
- bsi_next_in_bb (block_stmt_iterator *i, basic_block bb)
- {
-   tree t, stmt = NULL_TREE;
- 
-   /* Go to the next statement skipping over empty statements we may find.  */
-   do
-     {
-       t = *(i->tp);
-       if (TREE_CODE (t) == COMPOUND_EXPR)
- 	i->tp = &(TREE_OPERAND (t, 1));
-       else
- 	{
- 	  /* We ran out of statements.  Clear the iterator and stop
- 	     searching.  */
- 	  i->tp = NULL;
- 	  break;
- 	}
- 
-       stmt = bsi_stmt (*i);
-     }
-   while (IS_EMPTY_STMT (stmt));
- 
-   if (i->tp && bb_for_stmt (stmt) != bb)
-     i->tp = NULL;
- 
-   if (i->tp == NULL && i->context != NULL_TREE)
-     {
-       /* If we haven't got a statement, and we have context, pop the state and
-          traverse to the next statement.  */
-       i->tp = (tree *)TREE_VALUE (i->context);
-       i->context = TREE_PURPOSE (i->context);
- 
-       /* FIXME.  Hack to recover BB for cases when we are stepping out of a
- 	 removed statement.  If bsi_remove() has been called on the
- 	 last statement of a BIND_EXPR body, the next call to
- 	 bsi_next() will retrieve a NULL basic block from the just deleted
- 	 statement, so that BB will be NULL.  We restore BB using the
- 	 BIND_EXPR node itself.  */
-       bb = bb_for_stmt (*(i->tp));
  
!       bsi_next_in_bb (i, bb);
!     }
! }
! 
! /* Similar to tsi_start() but initializes the iterator at the first
!    statement in basic block BB which isn't an empty statement node.
! 
!    NULL is returned if there are no such statements.  */
! 
! block_stmt_iterator
! bsi_start (basic_block bb)
! {
!   block_stmt_iterator i;
!   tree t;
! 
!   if (bb && bb->index != INVALID_BLOCK)
!     {
!       tree *tp = bb->head_tree_p;
!       i = bsi_init (tp, bb);
!       if (i.tp != NULL)
! 	{
! 	  /* If we get back a statement which is not within this basic
! 	     block, that is wrong!  */
! 	  t = bsi_stmt (i);
! 	  if (t != NULL_TREE && bb_for_stmt (t) != bb)
! 	    abort ();
! 	}
!       }
!     else
!       i.tp = NULL;
! 
!   /* If there are no stmts in the block, set the context to point to the
!      basic block in case we try to insert a stmt with this iterator.  */
! 
!   if (i.tp == NULL)
!     i.context = (tree) bb;
  
    return i;
  }
--- 2446,2463 ----
  }
  
  
! /* Similar to tsi_start() but initializes the iterator at the first
!    statement in basic block BB which isn't an empty statement node.
! 
!    NULL is returned if there are no such statements.  */
  
! block_stmt_iterator
! bsi_start (basic_block bb)
  {
    block_stmt_iterator i;
  
!   i.bb = bb;
!   i.curr_stmt = bb->head_tree;
  
    return i;
  }
*************** bsi_start (basic_block bb)
*** 2655,2751 ****
  block_stmt_iterator
  bsi_last (basic_block bb)
  {
!   block_stmt_iterator b, tmp;
! 
!   if (bb == NULL || bb->index == INVALID_BLOCK)
!     {
!       b.tp = NULL;
!       return b;
!     }
! 
!   b = bsi_init (bb->end_tree_p, bb);
! 
!   /* If the last stmt pointer isn't something a BSI can represent (ie, an
!      empty statement node), then find the last stmt the slow way.  */
!   if (b.tp == NULL)
!     {
!       for (tmp = b = bsi_start (bb); !bsi_end_p (tmp); bsi_next (&tmp))
!         b = tmp;
!     }
! 
!   return b;
! }
! 
! 
! /* Find the previous iterator value.  */
! 
! void
! bsi_prev (block_stmt_iterator *i)
! {
!   block_stmt_iterator bi, next;
! 
!   bi = bsi_start (bb_for_stmt (bsi_stmt (*i)));
!   if (bi.tp != i->tp)
!     {
!       for ( ; !bsi_end_p (bi); bi = next)
! 	{
! 	  next = bi;
! 	  bsi_next (&next);
! 	  if (next.tp == i->tp)
! 	    {
! 	      i->tp = bi.tp;
! 	      i->context = bi.context;
! 	      return;
! 	    }
! 	}
!     }
! 
!   i->tp = NULL;
!   bi.context = NULL_TREE;
!   return;
! }
! 
! 
! /* Initialize a block_stmt_iterator with a statement pointed to by a tree
!    iterator. If this cannot be done, a NULL iterator is returned.  */
! 
! block_stmt_iterator
! bsi_from_tsi (tree_stmt_iterator ti)
! {
!   basic_block bb;
!   tree stmt;
!   block_stmt_iterator bi;
! 
!   stmt = tsi_stmt (ti);
!   if (stmt)
!     {
!       bb = bb_for_stmt (stmt);
!       if (bb)
!         {
! 	  for (bi = bsi_start (bb); !bsi_end_p (bi); bsi_next (&bi))
! 	    if (bi.tp == ti.tp)
! 	      return bi;
! 	}
!     }
! 
!   bi.tp = NULL;
!   bi.context = NULL_TREE;
!   return bi;
! }
! 
  
! /* This is a more efficient version of bsi_from_tsi which can be used when
!    we are changing a bsi in a known way. Specifically, we know that the tsi
!    is located in the same 'context' area (ie, within the same BIND_EXPR),
!    so that the context doesn't have to be re-evaluated. This is primarily for
!    the insert routines which know what they are doing.  */
  
! static inline void
! bsi_update_from_tsi (block_stmt_iterator *bsi, tree_stmt_iterator tsi)
! {
!   /* Pretty simple right now, but its better to have this in an interface
!      rather than exposed right in the insert routine.  */
!   bsi->tp = tsi.tp;
  }
  
  
--- 2468,2479 ----
  block_stmt_iterator
  bsi_last (basic_block bb)
  {
!   block_stmt_iterator i;
  
!   i.bb = bb;
!   i.curr_stmt = bb->end_tree;
  
!   return i;
  }
  
  
*************** set_bb_for_stmt (tree t, basic_block bb)
*** 2756,3008 ****
  {
    stmt_ann_t ann;
  
!   do
      {
!       /* If the statement is a label, add the label to block-to-labels map
! 	 so that we can speed up edge creation for GOTO_EXPRs.  */
!       if (TREE_CODE (t) == LABEL_EXPR)
! 	{
! 	  LABEL_DECL_INDEX (LABEL_EXPR_LABEL (t))
  	      = VARRAY_ACTIVE_SIZE (label_to_block_map);
! 	  VARRAY_PUSH_BB (label_to_block_map, bb);
! 	}
! 
!       ann = get_stmt_ann (t);
!       ann->bb = bb;
!       t = (TREE_CODE (t) == COMPOUND_EXPR) ? TREE_OPERAND (t, 0) : NULL_TREE;
      }
!   while (t);
  }
  
  
  /* Insert routines.  */
  
- /* Because of the way containers and CE nodes are maintained, linking a new
-    stmt in can have significant consequences on the basic block information.
-    The basic block structure maintains the head and tail pointers as
-    containers, or pointers to the pointer to a node.
- 
-    Linking a new stmt after the last stmt in a block changes not only the
-    tail pointer of this block, but the container for the head of the next block
-    is now contained in a new node, so the head pointer must be updated in
-    a that different block. If it is the only statement in that block, then
-    the end pointer needs to be updated too.
- 
-    Linking a stmt after the penultimate (next to last) stmt in a block adds
-    a node which has the container to the end block stmt, so the block end must
-    be updated in this case.
- 
-    And the third case is the simple one when we are adding a new stmt to the
-    end of a chain which also ends a block.  */
- 
- /* This routine returns a tree stmt iterator which points to the original
-    stmt before we did an insert.  The first parameter is a tree stmt iterator
-    which is updated to point to the new stmt.  */
- 
- static tree_stmt_iterator
- bsi_link_after (tree_stmt_iterator *this_tsi, tree t, basic_block curr_bb)
- {
-   enum link_after_cases { NO_UPDATE,
- 			  END_OF_CHAIN,
- 			  PENULTIMATE_STMT,
- 			  AFTER_LAST_STMT,
- 			  JUST_UPDATE };
-   enum link_after_cases update_form = NO_UPDATE;
-   basic_block bb;
-   tree_stmt_iterator same_tsi, next_tsi;
-   tree *this_container;
- 
-   this_container = tsi_container (*this_tsi);
-   same_tsi = next_tsi = *this_tsi;
-   tsi_next (&next_tsi);
-   if (tsi_end_p (next_tsi))
-     update_form = END_OF_CHAIN;
-   /* This is the penultimate case. The next stmt is actually the last stmt
-      in the block, so we need to update the tail pointer to be the new
-      container for that stmt after we link in the new one.  */
-   else if (tsi_container (next_tsi) == curr_bb->end_tree_p)
-     update_form = PENULTIMATE_STMT;
-   /* The ugly case which requires updating pointers in a different
-      basic block.  */
-   else if (this_container == curr_bb->end_tree_p)
-     {
-       /* Double check to make sure the next stmt is indeed the head of
- 	 a different block.  */
-       bb = bb_for_stmt (*tsi_container (next_tsi));
-       if (bb
- 	  && bb != curr_bb
- 	  && bb->head_tree_p == tsi_container (next_tsi))
- 	update_form = AFTER_LAST_STMT;
-       else
- 	/* There are nops between the end of this block and the beginning
- 	   of the next, so we only need to update our end pointer.  */
- 	update_form = JUST_UPDATE;
-     }
- 
-   tsi_link_after (&same_tsi, t, TSI_SAME_STMT);
-   if (update_form == END_OF_CHAIN)
-     {
-       /* If the stmt was added to the end of a chain, the linking routines
- 	 created a new CE node to be a container for what use to be the
- 	 last stmt in the chain.  This container needs to have the BB info
- 	 set for it as well.  */
-       set_bb_for_stmt (*tsi_container (same_tsi), curr_bb);
-     }
-   *this_tsi = same_tsi;
-   tsi_next (this_tsi);
-   set_bb_for_stmt (*tsi_container (*this_tsi), curr_bb);
- 
-   switch (update_form)
-     {
-     case END_OF_CHAIN:
-     case JUST_UPDATE:
-       if (this_container == curr_bb->end_tree_p)
- 	curr_bb->end_tree_p = tsi_container (*this_tsi);
-       break;
- 
-     case PENULTIMATE_STMT:
-       next_tsi = *this_tsi;
-       tsi_next (&next_tsi);
-       curr_bb->end_tree_p = tsi_container (next_tsi);
-       break;
- 
-     case AFTER_LAST_STMT:
-       /* This is now the end of block.  */
-       curr_bb->end_tree_p = tsi_container (*this_tsi);
- 
-       /* And the next basic block's head needs updating too.  */
-       next_tsi = *this_tsi;
-       tsi_next (&next_tsi);
-       bb = bb_for_stmt (tsi_stmt (next_tsi));
-       /* Oh, and we also need to check if this is both the head *and* the
- 	 end of the next block.  */
-       if (bb->end_tree_p == bb->head_tree_p)
- 	bb->end_tree_p = tsi_container (next_tsi);
-       bb->head_tree_p = tsi_container (next_tsi);
-       break;
- 
-     default:
-       break;
-     }
- 
-   return same_tsi;
- }
- 
- 
  /* This routine inserts a stmt after the stmt iterator passed in.
     The final parameter determines whether the statement iterator
     is updated to point to the new stmt, or left pointing to the original
!    statement.  (Which may have a different container, by the way.)  */
  
  void
  bsi_insert_after (block_stmt_iterator *curr_bsi, tree t,
  		  enum bsi_iterator_update mode)
  {
!   tree_stmt_iterator inserted_tsi, same_tsi;
!   basic_block curr_bb;
!   tree *curr_container;
!   tree curr_stmt, inserted_stmt;
  
!   curr_container = bsi_container (*curr_bsi);
!   if (curr_container)
!     {
!       curr_stmt = bsi_stmt (*curr_bsi);
!       curr_bb = bb_for_stmt (curr_stmt);
!     }
!   else
!     {
!       curr_stmt = NULL_TREE;
  
!       /* bsi_start () will initialize the context pointer to the basic block
!          if the the block is completely devoid of instructions, except
! 	 for possibly an empty statement node.  */
!       if (curr_bsi->tp == NULL && curr_bsi->context != NULL)
!         curr_bb = (basic_block)(curr_bsi->context);
!       else
!         abort ();
!     }
! 
!   /* Some blocks are empty. The block iterator points to an empty statement
!      node in those cases only.  */
!   if (curr_stmt == NULL_TREE)
      {
!       inserted_tsi = tsi_start (curr_bb->head_tree_p);
!       tsi_link_before (&inserted_tsi, t, TSI_NEW_STMT);
!       prepend_stmt_to_bb (tsi_container (inserted_tsi), curr_bb);
  
!       /* In this case, we will *always* return the new stmt since BSI_SAME_STMT
!          doesn't really exist.  */
!       *curr_bsi = bsi_from_tsi (inserted_tsi);
      }
-   else
-     {
-       inserted_tsi = tsi_from_bsi (*curr_bsi);
  
!       same_tsi = bsi_link_after (&inserted_tsi, t, curr_bb);
!       bsi_update_from_tsi (curr_bsi, same_tsi);
!       if (mode == BSI_NEW_STMT)
!         bsi_next (curr_bsi);
!     }
  
!   inserted_stmt = tsi_stmt (inserted_tsi);
  
    /* Now update the required SSA bits.  */
!   modify_stmt (inserted_stmt);
! 
!   return;
  }
  
- 
  /* This routine inserts a stmt before the stmt iterator passed in.
     The final parameter determines whether the statement iterator
     is updated to point to the new stmt, or left pointing to the original
!    statement.  (Which will have a different container.)  */
  void
  bsi_insert_before (block_stmt_iterator *curr_bsi, tree t,
  		   enum bsi_iterator_update mode)
  {
!   tree_stmt_iterator inserted_tsi, same_tsi;
!   basic_block curr_bb;
!   tree *curr_container;
!   tree curr_stmt, inserted_stmt;
! 
!   curr_container = bsi_container (*curr_bsi);
! 
!   /* If this block is empty, let bsi_insert_after() handle it.  */
!   if (curr_container == NULL || bsi_stmt (*curr_bsi) == NULL_TREE)
!     bsi_insert_after (curr_bsi, t, mode);
! 
!   curr_stmt = bsi_stmt (*curr_bsi);
!   curr_bb = bb_for_stmt (curr_stmt);
!   inserted_tsi = tsi_from_bsi (*curr_bsi);
! 
!   /* The only case that needs attention is when the insert is before
!      the last stmt in a block. In this case, we have to update the
!      container of the end pointer.  */
!   tsi_link_before (&inserted_tsi, t, TSI_NEW_STMT);
!   set_bb_for_stmt (*tsi_container (inserted_tsi), curr_bb);
! 
!   same_tsi = inserted_tsi;
!   tsi_next (&same_tsi);
! 
!   /* The end block pointer can be modified when we insert before the last stmt
!      in a block.  This occurs because we insert a new container for the last
!      stmt.  */
  
!   if (curr_container == curr_bb->end_tree_p)
!     curr_bb->end_tree_p = tsi_container (same_tsi);
  
!   if (mode == BSI_SAME_STMT)
!     bsi_update_from_tsi (curr_bsi, same_tsi);
    else
!     bsi_update_from_tsi (curr_bsi, inserted_tsi);
  
!   inserted_stmt = tsi_stmt (inserted_tsi);
  
    /* Now update the required SSA bits.  */
!   modify_stmt (inserted_stmt);
! 
!   return;
  }
  
  /* This routine inserts a stmt on an edge. Every attempt is made to place the
--- 2484,2599 ----
  {
    stmt_ann_t ann;
  
!   /* If the statement is a label, add the label to block-to-labels map
!      so that we can speed up edge creation for GOTO_EXPRs.  */
!   if (TREE_CODE (t) == LABEL_EXPR)
      {
!       LABEL_DECL_INDEX (LABEL_EXPR_LABEL (t))
  	      = VARRAY_ACTIVE_SIZE (label_to_block_map);
!       VARRAY_PUSH_BB (label_to_block_map, bb);
      }
! 
!   ann = get_stmt_ann (t);
!   ann->bb = bb;
  }
  
  
  /* Insert routines.  */
  
  /* This routine inserts a stmt after the stmt iterator passed in.
     The final parameter determines whether the statement iterator
     is updated to point to the new stmt, or left pointing to the original
!    statement.  */
  
  void
  bsi_insert_after (block_stmt_iterator *curr_bsi, tree t,
  		  enum bsi_iterator_update mode)
  {
!   basic_block bb = curr_bsi->bb;
!   tree_cell curr, nw = tree_cell_alloc (t);
  
!   set_bb_for_stmt (t, bb);
!   curr = bsi_cell (*curr_bsi);
  
!   if (!curr)
      {
!       /* Inserting after end of bb.  Only valid if the bb is empty.  */
!       if (bb->head_tree)
! 	abort ();
  
!       nw->prev = nw->next = NULL;
!       bb->head_tree = bb->end_tree = nw;
!       VARRAY_GENERIC_PTR (tree_cell_root, bb->index) = nw;
!       *curr_bsi = bsi_start (bb);
!       return;
      }
  
!   nw->next = curr->next;
!   if (!curr->next)
!     bb->end_tree = nw;
!   else
!     nw->next->prev = nw;
!   curr->next = nw;
!   nw->prev = curr;
  
!   if (mode == BSI_NEW_STMT)
!     bsi_next (curr_bsi);
  
    /* Now update the required SSA bits.  */
!   modify_stmt (t);
  }
  
  /* This routine inserts a stmt before the stmt iterator passed in.
     The final parameter determines whether the statement iterator
     is updated to point to the new stmt, or left pointing to the original
!    statement.  */
! 
  void
  bsi_insert_before (block_stmt_iterator *curr_bsi, tree t,
  		   enum bsi_iterator_update mode)
  {
!   basic_block bb = curr_bsi->bb;
!   tree_cell curr, nw = tree_cell_alloc (t);
! 
!   set_bb_for_stmt (t, bb);
!   curr = bsi_cell (*curr_bsi);
  
!   if (!curr)
!     {
!       /* Inserting just after end of the basic block.  */
  
!       nw->prev = bb->end_tree;
!       nw->next = NULL;
!       if (!bb->head_tree)
! 	{
! 	  bb->head_tree = nw;
! 	  VARRAY_GENERIC_PTR (tree_cell_root, bb->index) = bb->head_tree;
! 	}
!       else
! 	nw->prev->next = nw;
!       bb->end_tree = nw;
! 
!       if (mode == BSI_NEW_STMT)
! 	curr_bsi->curr_stmt = nw;
!       return;
!     }
! 
!   nw->prev = curr->prev;
!   if (!nw->prev)
!     {
!       bb->head_tree = nw;
!       VARRAY_GENERIC_PTR (tree_cell_root, bb->index) = bb->head_tree;
!     }
    else
!     nw->prev->next = nw;
!   curr->prev = nw;
!   nw->next = curr;
  
!   if (mode == BSI_NEW_STMT)
!     bsi_prev (curr_bsi);
  
    /* Now update the required SSA bits.  */
!   modify_stmt (t);
  }
  
  /* This routine inserts a stmt on an edge. Every attempt is made to place the
*************** bsi_insert_on_edge_immediate (edge e, tr
*** 3021,3034 ****
  {
    basic_block src, dest, new_bb;
    block_stmt_iterator bsi, tmp;
-   tree_stmt_iterator tsi;
    int num_exit, num_entry;
!   tree last, label, gto, old_gto;
    bb_ann_t ann;
    edge e2;
  
    if (old_bsi)
!     old_bsi->tp = (tree *)NULL;
    if (created_block)
      *created_block = (basic_block)NULL;
  
--- 2612,2624 ----
  {
    basic_block src, dest, new_bb;
    block_stmt_iterator bsi, tmp;
    int num_exit, num_entry;
!   tree last;
    bb_ann_t ann;
    edge e2;
  
    if (old_bsi)
!     old_bsi->curr_stmt = NULL;
    if (created_block)
      *created_block = (basic_block)NULL;
  
*************** bsi_insert_on_edge_immediate (edge e, tr
*** 3057,3109 ****
    if (num_exit == 1 && src != ENTRY_BLOCK_PTR)
      {
        bsi = bsi_last (src);
!       /* If it is an empty block, simply insert after this bsi, and the
! 	 new stmt will become the only stmt in the block.  */
        if (bsi_end_p (bsi))
  	{
  	  bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
  	  return bsi;
  	}
  
!       /* If this is a fallthrough edge, then we can simply append this stmt
! 	 to the basic block.  */
!       if (e->flags & EDGE_FALLTHRU)
! 	{
! #ifdef ENABLE_CHECKING
! 	  /* Control statement edges should not be marked FALLTHRU.  */
! 	  if (is_ctrl_stmt (bsi_stmt (bsi)))
! 	    abort ();
! #endif
  
! 	  if (src->head_tree_p == src->end_tree_p 
! 	      && IS_EMPTY_STMT (*src->head_tree_p))
! 	    {
! 	      bsi_replace (bsi, stmt);
! 	      if (old_bsi)
! 		*old_bsi = bsi;
! 	      return bsi;
! 	    }
! 	  else
! 	    {
! 	      bsi_insert_after (&bsi, stmt, BSI_SAME_STMT);
! 	      if (old_bsi)
! 		*old_bsi = bsi;
! 	      bsi_next (&bsi);
! 	      return bsi;
! 	    }
! 	}
! 
!       /* Otherwise, the last stmt is a control altering stmt, so we need to
! 	 insert before it.  */
!       else
  	{
! #ifdef ENABLE_CHECKING
! 	  /* A block with a normal non-FALLTHRU edge should end with a
! 	     control statement.  */
! 	  if (!is_ctrl_stmt (bsi_stmt (bsi)))
! 	    abort ();
! #endif
  
  	  bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
  	  if (old_bsi)
  	    {
--- 2647,2677 ----
    if (num_exit == 1 && src != ENTRY_BLOCK_PTR)
      {
        bsi = bsi_last (src);
!       /* If it is an empty block, simply insert after this bsi, and the new stmt
! 	 will become the only stmt in the block.  */
        if (bsi_end_p (bsi))
  	{
  	  bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
  	  return bsi;
  	}
+       last = bsi_stmt (bsi);
  
!       /* If the last stmt isn't a control altering stmt, then we can simply
! 	 append this stmt to the basic block. This should mean the edge is
! 	 a fallthrough edge.  */
  
!       if (!is_ctrl_stmt (last) && !is_ctrl_altering_stmt (last))
  	{
! 	  bsi_insert_after (&bsi, stmt, BSI_SAME_STMT);
! 	  if (old_bsi)
! 	    *old_bsi = bsi;
! 	  bsi_next (&bsi);
! 	  return bsi;
!       	}
  
+       /* If the last stmt is a GOTO, the we can simply insert before it.  */
+       if (TREE_CODE (last) == GOTO_EXPR)
+ 	{
  	  bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
  	  if (old_bsi)
  	    {
*************** bsi_insert_on_edge_immediate (edge e, tr
*** 3114,3121 ****
  	}
      }
  
!   /* If dest is a single entry destination, and it isn't the exit block, the
!      new stmt can be inserted at the beginning of the destination block.  */
  
    if (num_entry == 1 && dest != EXIT_BLOCK_PTR)
      {
--- 2682,2689 ----
  	}
      }
  
!   /* If dest is a single entry destination, and it isn't the exit block, the new
!      stmt can be inserted at the beginning of the destination block.  */
  
    if (num_entry == 1 && dest != EXIT_BLOCK_PTR)
      {
*************** bsi_insert_on_edge_immediate (edge e, tr
*** 3160,3273 ****
    if (created_block)
      *created_block = new_bb;
  
!   bsi = bsi_last (src);
!   if (!bsi_end_p (bsi))
!     {
!       bool fixup;
! 
!       last = bsi_stmt (bsi);
!       label = old_gto = NULL;
!       tsi = tsi_start (src->end_tree_p);
! 
!       switch (TREE_CODE (last))
! 	{
! 	case COND_EXPR:
! 	  e = find_edge (src, new_bb);
! 	  if (!e)
! 	    abort ();
! 
! 	  label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
! 	  gto = build_and_jump (&LABEL_EXPR_LABEL (label));
! 	  if (e->flags & EDGE_TRUE_VALUE)
! 	    {
! 	      old_gto = COND_EXPR_THEN (last);
! 	      COND_EXPR_THEN (last) = gto;
! 	    }
! 	  else
! 	    {
! 	      old_gto = COND_EXPR_ELSE (last);
! 	      COND_EXPR_ELSE (last) = gto;
! 	    }
! 	  break;
! 
! 	case SWITCH_EXPR:
! 	  {
! 	    tree vec = SWITCH_LABELS (last);
! 	    size_t i, n = TREE_VEC_LENGTH (vec);
! 	    tree dest_label = NULL;
! 
! 	    label = create_artificial_label ();
! 	    for (i = 0; i < n; ++i)
! 	      {
! 		tree elt = TREE_VEC_ELT (vec, i);
! 		if (label_to_block (CASE_LABEL (elt)) == dest)
! 		  {
! 		    dest_label = CASE_LABEL (elt);
! 		    CASE_LABEL (elt) = label;
! 		  }
! 	      }
! 
! 	    label = build1 (LABEL_EXPR, void_type_node, label);
! 	    old_gto = build_and_jump (&dest_label);
! 	  }
! 	  break;
! 
! 	case CALL_EXPR:
! 	case MODIFY_EXPR:
! 	  /* The block ends in a CALL which has abnormal edges.  In
! 	     that case, we simply create a new block right after this
! 	     one, and then fall through to the destination block.  */
! 	  e = find_edge (new_bb, dest);
! 	  if (!e)
! 	    abort ();
! 	  e->flags |= EDGE_FALLTHRU;
! 	  break;
! 
! 	default:
! 	  /* All cases ought to have been covered by now.  */
! 	  abort ();
! 	}
! 
!       /* When insertting our first statement, we may well create a new
! 	 COMPOUND_EXPR container, and so we'll need to update the end
! 	 of the old src block.  */
!       fixup = false;
! 
!       if (label)
! 	{
! 	  tsi_link_after (&tsi, label, TSI_SAME_STMT);
! 	  src->end_tree_p = tsi_container (tsi);
! 	  fixup = true;
! 	  tsi_next (&tsi);
!           append_stmt_to_bb (tsi_container (tsi), new_bb);
! 	}
! 
!       tsi_link_after (&tsi, stmt, fixup ? TSI_NEW_STMT : TSI_SAME_STMT);
!       if (!fixup)
! 	{
! 	  src->end_tree_p = tsi_container (tsi);
! 	  fixup = true;
! 	  tsi_next (&tsi);
! 	}
!       append_stmt_to_bb (tsi_container (tsi), new_bb);
! 
!       if (old_gto)
! 	{
!           tsi_link_after (&tsi, old_gto, TSI_NEW_STMT);
!           append_stmt_to_bb (tsi_container (tsi), new_bb);
! 	}
! 
!       /* For the same reason of new containers, we have to wait until the
! 	 end to initialize our return bsi value.  Fortunately we don't 
! 	 need to search far to get it pointed to the real statement that
! 	 we added.  */
!       bsi = bsi_start (new_bb);
!       if (label)
! 	bsi_next (&bsi);
!     }
! 
!   /* Now update the required SSA bits.  */
!   modify_stmt (stmt);
  
    return bsi;
  }
--- 2728,2739 ----
    if (created_block)
      *created_block = new_bb;
  
!   bsi = bsi_start (new_bb);
!   if (bsi_stmt (bsi)
!       && TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR)
!     bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
!   else
!     bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
  
    return bsi;
  }
*************** bsi_insert_on_edge (edge e, tree stmt)
*** 3346,3428 ****
  
  }
  
! /* These 2 routines are used to process BSI's in reverse within a block.
!    When there is a decent implementation of bsi_prev, we can get rid of
!    these forever!  */
! 
! /* Push another block_stmt_iterator onto the stack.  */
! void
! push_bsi (bsi_list_p *list, block_stmt_iterator bsi)
! {
!   bsi_list_p tmp;
!   if (*list == NULL)
!     {
!       *list = new_bsi_list ();
!       (*list)->bsi[0] = bsi;
!     }
!   else
!     {
!       if ((*list)->curr_index == (BSI_NUM_ELEMENTS - 1))
!         {
! 	  tmp = new_bsi_list ();
! 	  tmp->bsi[0] = bsi;
! 	  tmp->next = *list;
! 	  *list = tmp;
! 	}
!       else
!         {
! 	  (*list)->bsi[++((*list)->curr_index)] = bsi;
! 	}
!     }
! }
! 
! /* Pop a block_stmt_iterator off the stack.  */
! block_stmt_iterator
! pop_bsi (bsi_list_p *list)
! {
!   block_stmt_iterator bsi;
!   bsi_list_p tmp;
!   if (!list)
!     abort ();
! 
!   tmp = *list;
!   bsi = tmp->bsi[(tmp->curr_index)--];
!   if (tmp->curr_index< 0)
!     {
!       tmp = *list;
!       *list = (*list)->next;
!       free (tmp);
!     }
!   return bsi;
! }
! 
  
! /* Replace the statement pointed by TP1 with the statement pointed by TP2.
!    Note that this function will not replace COMPOUND_EXPR nodes, only
!    individual statements.
! 
!    If TP1 is pointing to a COMPOUND_EXPR node, only its LHS operand will be
!    replaced. TP2 may not point to a COMPOUND_EXPR.  */
! 
! void
! replace_stmt (tree *tp1, tree *tp2)
  {
!   tree t;
! 
!   if (TREE_CODE (*tp2) == COMPOUND_EXPR)
!     abort ();
!       
!   t = *tp2;
  
    /* Relocate annotations for the replacement statement.  */
!   SET_EXPR_LOCUS (t, EXPR_LOCUS (*tp1));
!   set_bb_for_stmt (t, bb_for_stmt (*tp1));
! 
!   /* Don't replace COMPOUND_EXPRs.  Only their operands.  */
!   if (TREE_CODE (*tp1) == COMPOUND_EXPR)
!     TREE_OPERAND (*tp1, 0) = t;
!   else
!     *tp1 = t;
  }
  
  /*---------------------------------------------------------------------------
--- 2812,2829 ----
  
  }
  
! /* Replace the statement TP1 with the statement TP2.  */
  
! static void
! replace_stmt (tree_cell tp1, tree t)
  {
!   basic_block bb;
  
    /* Relocate annotations for the replacement statement.  */
!   SET_EXPR_LOCUS (t, EXPR_LOCUS (tp1->stmt));
!   bb = bb_for_stmt (tp1->stmt);
!   tp1->stmt = t;
!   set_bb_for_stmt (t, bb);
  }
  
  /*---------------------------------------------------------------------------
*************** tree_split_edge (edge edge_in)
*** 3446,3457 ****
  
    dest = edge_in->dest;
    new_bb = create_bb ();
!   create_block_annotation (new_bb);
!   redirect_edge_succ  (edge_in, new_bb);
!   new_edge = make_edge (new_bb, dest, 0);
  
    /* Find all the PHI arguments on the original edge, and change them to
!      the new edge.  */
    for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
      {
        num_elem = PHI_NUM_ARGS (phi);
--- 2847,2859 ----
  
    dest = edge_in->dest;
    new_bb = create_bb ();
! 
!   new_edge = make_edge (new_bb, dest, EDGE_FALLTHRU);
!   tree_cleanup_block_edges (new_bb, false);
  
    /* Find all the PHI arguments on the original edge, and change them to
!      the new edge.  Do it now, since redirect_edge_and_branch would cancel
!      the args otherwise.  */
    for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
      {
        num_elem = PHI_NUM_ARGS (phi);
*************** tree_split_edge (edge edge_in)
*** 3463,3471 ****
--- 2865,2896 ----
  	  }
      }
  
+   if (!redirect_edge_and_branch (edge_in, new_bb))
+     abort ();
+ 
    return new_bb;
  }
  
+ /* Return the label in the head of basic block BLOCK.  Create one if it doesn't
+    exist.  */
+ 
+ static tree
+ tree_block_label (basic_block bb)
+ {
+   tree stmt = first_stmt (bb);
+   /* We need a label at our final destination.  If it does not already exist,
+      create it.  */
+   if (!stmt || TREE_CODE (stmt) != LABEL_EXPR)
+     {
+       block_stmt_iterator iterator = bsi_start (bb);
+       tree label = create_artificial_label ();
+       stmt = build1 (LABEL_EXPR, void_type_node, label);
+       bsi_insert_before (&iterator, stmt, BSI_SAME_STMT);
+       return label;
+     }
+   else
+     return LABEL_EXPR_LABEL (stmt);
+ }
  
  /* Verifies that the flow information is OK.  */
  
*************** tree_verify_flow_info (void)
*** 3476,3485 ****
--- 2901,2942 ----
    basic_block bb;
    block_stmt_iterator bsi;
    tree stmt;
+   bool does_fallthru, should_fallthru;
  
    FOR_EACH_BB (bb)
      {
+       edge e;
        bsi = bsi_last (bb);
+ 
+       if (VARRAY_GENERIC_PTR (tree_cell_root, bb->index) != bb->head_tree)
+ 	{
+ 	  fprintf (stderr, "Head tree root reference lost in bb %d\n",
+ 		   bb->index);
+ 	  err = 1;
+ 	}
+ 
+       if (bb->succ
+ 	  && !bb->succ->succ_next
+ 	  && !(bb->succ->flags & EDGE_ABNORMAL))
+ 	{
+ 	  does_fallthru = (bb->succ->flags & EDGE_FALLTHRU) != 0;
+ 	  should_fallthru = (bsi_end_p (bsi)
+ 			     || !is_ctrl_stmt (bsi_stmt (bsi)));
+ 	  if (does_fallthru ^ should_fallthru)
+ 	    {
+ 	      fprintf (stderr, "Fallthru flag missmatch at the end of bb %d\n",
+ 		       bb->index);
+ 	      err = 1;
+ 	    }
+ 	}
+ 
+       for (e = bb->succ; e; e = e->succ_next)
+ 	if (e->flags & EDGE_FALLTHRU && e->dest != bb->next_bb)
+ 	  {
+ 	    error ("Fallthru edge of bb %d does not point to following block\n", bb->index);
+ 	    err = 1;
+ 	  }
+ 
        if (bsi_end_p (bsi))
  	continue;
  
*************** tree_verify_flow_info (void)
*** 3487,3500 ****
        switch (TREE_CODE (stmt))
  	{
  	case COND_EXPR:
! 	  if (TREE_CODE (COND_EXPR_THEN (stmt)) != GOTO_EXPR
! 	      || TREE_CODE (COND_EXPR_ELSE (stmt)) != GOTO_EXPR)
  	    {
! 	      fprintf (stderr, "Structured COND_EXPR at end of bb %d\n",
! 		       bb->index);
  	      err = 1;
  	    }
  	  break;
  	default: ;
  	}
      }
--- 2944,3003 ----
        switch (TREE_CODE (stmt))
  	{
  	case COND_EXPR:
! 	  {
! 	    edge true_edge;
! 	    edge false_edge;
! 	    if (TREE_CODE (COND_EXPR_THEN (stmt)) != GOTO_EXPR
! 		|| TREE_CODE (COND_EXPR_ELSE (stmt)) != GOTO_EXPR)
! 	      {
! 		error ("Structured COND_EXPR at end of bb %d\n", bb->index);
! 		err = 1;
! 	      }
! 	    if (bb->succ->flags & EDGE_TRUE_VALUE)
! 	      true_edge = bb->succ, false_edge = bb->succ->succ_next;
! 	    else
! 	      false_edge = bb->succ, true_edge = bb->succ->succ_next;
! 	    if (!true_edge || !false_edge
! 		|| !(true_edge->flags & EDGE_TRUE_VALUE)
! 		|| !(false_edge->flags & EDGE_FALSE_VALUE)
! 		|| (true_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
! 		|| (true_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
! 		|| bb->succ->succ_next->succ_next)
! 	      {
! 		error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		err = 1;
! 	      }
! 	    if (label_to_block (GOTO_DESTINATION (COND_EXPR_THEN (stmt)))
! 		!= true_edge->dest
! 		|| (label_to_block (GOTO_DESTINATION (COND_EXPR_ELSE (stmt)))
! 		    != false_edge->dest))
! 	      {
! 		error ("Label does not match edge at end of bb %d\n", bb->index);
! 		err = 1;
! 	      }
! 	  }
! 	  break;
! 
! 	case GOTO_EXPR:
! 	  if (nonlocal_goto_p (stmt)
! 	      || is_computed_goto (stmt))
! 	    break;
! 
! 	  if (!bb->succ
! 	      || bb->succ->succ_next
! 	      || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
! 		  		     | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
!   	    {
! 	      error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 	      err = 1;
! 	    }
! 	  if (label_to_block (GOTO_DESTINATION (stmt)) != bb->succ->dest)
  	    {
! 	      error ("Label does not match edge at end of bb %d\n", bb->index);
  	      err = 1;
  	    }
  	  break;
+ 
  	default: ;
  	}
      }
*************** tree_make_forwarder_block (basic_block b
*** 3522,3529 ****
    dummy->count = bb->count;
    dummy->frequency = bb->frequency;
    dummy->loop_depth = bb->loop_depth;
!   dummy->head_tree_p = NULL;
!   dummy->end_tree_p = NULL;
  
    /* Redirect the incoming edges.  */
    dummy->pred = bb->pred;
--- 3025,3032 ----
    dummy->count = bb->count;
    dummy->frequency = bb->frequency;
    dummy->loop_depth = bb->loop_depth;
!   dummy->head_tree = NULL;
!   dummy->end_tree = NULL;
  
    /* Redirect the incoming edges.  */
    dummy->pred = bb->pred;
*************** thread_jumps (void)
*** 3836,3865 ****
    return retval;
  }
  
- /* Return the label in the head of basic block BLOCK.  Create one if it doesn't
-    exist.  */
- 
- static tree
- tree_block_label (basic_block bb)
- {
-   tree stmt = first_stmt (bb);
-   /* We need a label at our final destination.  If it does not already exist,
-      create it.  */
-   if (!stmt || TREE_CODE (stmt) != LABEL_EXPR)
-     {
-       block_stmt_iterator iterator = bsi_start (bb);
-       tree label;
- 
-       label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-       DECL_CONTEXT (label) = current_function_decl;
-       stmt = build1 (LABEL_EXPR, void_type_node, label);
-       bsi_insert_before (&iterator, stmt, BSI_SAME_STMT);
-       return label;
-     }
-   else
-     return LABEL_EXPR_LABEL (stmt);
- }
- 
  /* Attempt to perform edge redirection by replacing possibly complex jump
     instruction by goto or removing jump completely.  This can apply only
     if all edges now point to the same block.  The parameters and
--- 3339,3344 ----
*************** tree_try_redirect_by_replacing_jump (edg
*** 3882,3905 ****
    if (tmp)
      return NULL;
  
    b = bsi_last (src);
-   if (bsi_end_p (b))
-     return NULL;
-   stmt = bsi_stmt (b);
  
!   if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR
        || (TREE_CODE (stmt) == GOTO_EXPR && target == src->next_bb))
      {
        if (target == src->next_bb)
  	{
  	  flags = EDGE_FALLTHRU;
!           bsi_remove (&b);
  	}
        else
  	{
  	  flags = 0;
            stmt = build1 (GOTO_EXPR, void_type_node, tree_block_label (target));
!           bsi_replace (b, stmt);
  	}
        e = ssa_redirect_edge (e, target);
        e->flags = flags;
--- 3361,3388 ----
    if (tmp)
      return NULL;
  
+   stmt = last_stmt (src);
    b = bsi_last (src);
  
!   if (!stmt
!       || TREE_CODE (stmt) == COND_EXPR
!       || TREE_CODE (stmt) == SWITCH_EXPR
        || (TREE_CODE (stmt) == GOTO_EXPR && target == src->next_bb))
      {
        if (target == src->next_bb)
  	{
  	  flags = EDGE_FALLTHRU;
! 	  if (!bsi_end_p (b))
! 	    bsi_remove (&b);
  	}
        else
  	{
  	  flags = 0;
            stmt = build1 (GOTO_EXPR, void_type_node, tree_block_label (target));
! 	  if (!bsi_end_p (b))
! 	    bsi_replace (b, stmt);
! 	  else
! 	    bsi_insert_after (&b, stmt, BSI_NEW_STMT);
  	}
        e = ssa_redirect_edge (e, target);
        e->flags = flags;
*************** tree_redirect_edge_and_branch_force (edg
*** 3994,3999 ****
--- 3477,3565 ----
    if (!e)
      abort ();
    return e->src == old ? NULL : old;
+ }
+ 
+ /* Cleanup the cfg -- edges correspondence for a single block BB.  If
+    NO_FALSE_FALLTHRU, just remove false fallthru edges.  */
+ void
+ tree_cleanup_block_edges (basic_block bb, bool no_false_fallthru)
+ {
+   edge e, e_true;
+   block_stmt_iterator bsi;
+   tree stmt;
+ 
+   if (bb == ENTRY_BLOCK_PTR)
+     return;
+ 
+ redo:
+   stmt = last_stmt (bb);
+   bsi = bsi_last (bb);
+ 
+   if (!stmt
+       || !stmt_ends_bb_p (stmt)
+       || no_false_fallthru)
+     {
+       for (e = bb->succ; e; e = e->succ_next)
+ 	if (e->flags & EDGE_FALLTHRU)
+ 	  break;
+ 
+       if (e && e->dest != bb->next_bb && e->dest != EXIT_BLOCK_PTR)
+ 	{
+ 	  tree label = tree_block_label (e->dest);
+ 
+ 	  bsi_insert_after (&bsi,
+ 			    build1 (GOTO_EXPR, void_type_node, label),
+ 			    BSI_NEW_STMT);
+ 	  e->flags &= ~EDGE_FALLTHRU;
+ 	  goto redo;
+ 	}
+     }
+ 
+   if (!stmt
+       || no_false_fallthru)
+     return;
+ 
+   switch (TREE_CODE (stmt))
+     {
+     case GOTO_EXPR:
+       if (is_computed_goto (stmt)
+ 	  || nonlocal_goto_p (stmt))
+ 	break;
+ 
+       e_true = NULL;
+       for (e = bb->succ; e; e = e->succ_next)
+ 	{
+ 	  if (e->flags & EDGE_ABNORMAL)
+ 	    continue;
+ 
+ 	  if (e_true)
+ 	    abort ();
+ 
+ 	  e_true = e;
+ 	}
+ 	    
+       if (!e_true)
+ 	break;
+ 
+       if (e_true->dest == bb->next_bb)
+ 	{
+      	  bsi_remove (&bsi);
+ 	  e_true->flags |= EDGE_FALLTHRU;
+ 	}
+       break;
+ 
+     case COND_EXPR:
+       if (cleanup_cond_expr_graph (bb, bsi))
+ 	goto redo;
+       break;
+ 
+     case SWITCH_EXPR:
+       if (cleanup_switch_expr_graph (bb, bsi))
+ 	goto redo;
+       break;
+ 
+     default: ;
+     }
  }
  
  /* FIXME These need to be filled in with appropriate pointers.  But this
Index: tree-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dump.c,v
retrieving revision 1.6.2.47
diff -c -3 -p -r1.6.2.47 tree-dump.c
*** tree-dump.c	5 Nov 2003 13:39:23 -0000	1.6.2.47
--- tree-dump.c	5 Nov 2003 15:43:44 -0000
*************** static const struct dump_option_value_in
*** 699,705 ****
    {"blocks", TDF_BLOCKS},
    {"vops", TDF_VOPS},
    {"lineno", TDF_LINENO},
!   {"all", ~(TDF_RAW | TDF_SLIM)},
    {NULL, 0}
  };
  
--- 699,705 ----
    {"blocks", TDF_BLOCKS},
    {"vops", TDF_VOPS},
    {"lineno", TDF_LINENO},
!   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO)},
    {NULL, 0}
  };
  
Index: tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow-inline.h,v
retrieving revision 1.1.2.56
diff -c -3 -p -r1.1.2.56 tree-flow-inline.h
*** tree-flow-inline.h	1 Nov 2003 20:27:15 -0000	1.1.2.56
--- tree-flow-inline.h	5 Nov 2003 15:43:44 -0000
*************** dom_children (basic_block bb)
*** 349,355 ****
  static inline bool
  bsi_end_p (block_stmt_iterator i)
  {
!   return (i.tp == NULL || bsi_stmt (i) == NULL_TREE);
  }
  
  /* Similar to tsi_next() but stops at basic block boundaries.  Assumes stmt
--- 349,355 ----
  static inline bool
  bsi_end_p (block_stmt_iterator i)
  {
!   return i.curr_stmt == NULL;
  }
  
  /* Similar to tsi_next() but stops at basic block boundaries.  Assumes stmt
*************** bsi_end_p (block_stmt_iterator i)
*** 358,393 ****
  static inline void
  bsi_next (block_stmt_iterator *i)
  {
!   extern void bsi_next_in_bb (block_stmt_iterator *, basic_block);
  
!   basic_block bb = bb_for_stmt (*(i->tp));
!   bsi_next_in_bb (i, bb);
  }
  
  static inline tree *
  bsi_stmt_ptr (block_stmt_iterator i)
  {
! #if defined ENABLE_CHECKING
!   if (i.tp == NULL || *i.tp == NULL_TREE)
!     abort ();
! #endif
! 
!   if (TREE_CODE ((*i.tp)) == COMPOUND_EXPR)
!     return &TREE_OPERAND ((*i.tp), 0);
!   else
!     return i.tp;
  }
  
  static inline tree
  bsi_stmt (block_stmt_iterator i)
  {
!   return *(bsi_stmt_ptr (i));
  }
  
! static inline tree *
! bsi_container (block_stmt_iterator i)
  {
!   return i.tp;
  }
  
  /* Return a tree_stmt_iterator for the stmt a block iterator refers to.  */
--- 358,390 ----
  static inline void
  bsi_next (block_stmt_iterator *i)
  {
!   i->curr_stmt = i->curr_stmt->next;
! }
! 
! /* Find the previous iterator value.  */
  
! static inline void
! bsi_prev (block_stmt_iterator *i)
! {
!   i->curr_stmt = i->curr_stmt->prev;
  }
  
  static inline tree *
  bsi_stmt_ptr (block_stmt_iterator i)
  {
!   return &i.curr_stmt->stmt;
  }
  
  static inline tree
  bsi_stmt (block_stmt_iterator i)
  {
!   return i.curr_stmt->stmt;
  }
  
! static inline tree_cell
! bsi_cell (block_stmt_iterator i)
  {
!   return i.curr_stmt;
  }
  
  /* Return a tree_stmt_iterator for the stmt a block iterator refers to.  */
*************** bsi_container (block_stmt_iterator i)
*** 395,401 ****
  static inline tree_stmt_iterator
  tsi_from_bsi (block_stmt_iterator bi)
  {
!   return tsi_start (bi.tp);
  }
  
  static inline bool
--- 392,398 ----
  static inline tree_stmt_iterator
  tsi_from_bsi (block_stmt_iterator bi)
  {
!   return tsi_start (&bi.curr_stmt->stmt);
  }
  
  static inline bool
*************** is_label_stmt (tree t)
*** 422,526 ****
        }
    return false;
  }
- 
- /* Routines to allow a block to be walked backwards reasonably efficiently.
-    Once a decent implementation of bsi_prev() is implemented, this can
-    be removed.  */
- 
- #define BSI_NUM_ELEMENTS	50
- 
- typedef struct bsi_list_d {
-   block_stmt_iterator bsi[BSI_NUM_ELEMENTS];
-   int curr_index;
-   struct bsi_list_d *next;
- } *bsi_list_p;
- 
- 
- static inline bsi_list_p new_bsi_list (void);
- static inline int empty_bsi_stack (bsi_list_p);
- extern void push_bsi (bsi_list_p *, block_stmt_iterator);
- extern block_stmt_iterator pop_bsi (bsi_list_p *);
- 
- 
- /* Allocate a bsi_list structure.  */
- static inline bsi_list_p
- new_bsi_list (void)
- {
-   bsi_list_p b;
-   b = (bsi_list_p) xmalloc (sizeof (struct bsi_list_d));
-   b->curr_index = 0;
-   b->next = NULL;
- 
-   return b;
- }
- 
- /* Is the iterator stack empty?  */
- static inline int
- empty_bsi_stack (bsi_list_p list)
- {
-   if (!list || (list->curr_index < 0 && list->next == NULL))
-     return 1;
-   return 0;
- }
- 
- 
- /* Process an entire block of bsi's in reverse by pushing them on a stack
-    as they are encountered, and then popping them off as they are needed.
-    There are a couple of odd things. Since the last loop is a for loop,
-    a dummy entry is pushed on the beginning of the stack, this allows the first
-    item pushed on the stack to be processed in the final for loop, as well
-    as guaranteeing there will be at least one to pop off.
- 
-    usage:
-      bsi_list_p  stack;
-      block_stmt_iterator bsi;
-      basic_block bb;
- 
-      FOR_EACH_BSI_IN_REVERSE (stack, bb, bsi)
-        {
-          ...
-        }
- */
- #define FOR_EACH_BSI_IN_REVERSE(bsi_stack, bb, bsi)		\
-   bsi_stack = new_bsi_list ();					\
-   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))	\
-     push_bsi (&bsi_stack, bsi);					\
-   bsi = pop_bsi (&bsi_stack);					\
-   for ( ; !empty_bsi_stack (bsi_stack); bsi = pop_bsi (&bsi_stack))
- 
- 
- 
- /* This macro can be used if all that is ever examined is the stmt nodes
-    of bsi. Ie, if the usage is
-       FOR_EACH_BSI_IN_REVERSE (stack, bb, bsi)
-         {
- 	  tree stmt = bsi_stmt (bsi);
- 	  ...
-   Then less overhead exists to simply use this macro.
- 
-   usage:
-     varray_type stmt_stack;
-     basic_block bb;
-     tree stmt;
- 
-     FOR_EACH_STMT_IN_REVERSE (stmt_stack, bb, stmt)
-       {
-         ...
-       }
- */
- #define FOR_EACH_STMT_IN_REVERSE(stmt_stack, bb, stmt)		\
-   VARRAY_TREE_INIT (stmt_stack, 50, "stmt_stack");		\
-   VARRAY_PUSH_TREE (stmt_stack, NULL_TREE);			\
-   {								\
-     block_stmt_iterator bsi;					\
-     for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))	\
-       VARRAY_PUSH_TREE (stmt_stack, bsi_stmt (bsi));		\
-   }								\
-   stmt = VARRAY_TOP_TREE (stmt_stack);				\
-   VARRAY_POP (stmt_stack);					\
-   for ( ; VARRAY_ACTIVE_SIZE (stmt_stack) > 0 ;		\
- 	      stmt = VARRAY_TOP_TREE (stmt_stack), VARRAY_POP (stmt_stack))
- 
  
  static inline bool
  may_propagate_copy (tree dest, tree orig)
--- 419,424 ----
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.141
diff -c -3 -p -r1.1.4.141 tree-flow.h
*** tree-flow.h	5 Nov 2003 13:39:23 -0000	1.1.4.141
--- tree-flow.h	5 Nov 2003 15:43:44 -0000
*************** struct basic_block_def;
*** 36,41 ****
--- 36,52 ----
  typedef struct basic_block_def *basic_block;
  #endif
  
+ /* A container for statements.  */
+ 
+ struct tree_container GTY (())
+ {
+   struct tree_container *prev;
+   struct tree_container *next;
+   tree stmt;
+ };
+ 
+ typedef struct tree_container *tree_cell;
+ 
  /*---------------------------------------------------------------------------
  		   Tree annotations stored in tree_common.ann
  ---------------------------------------------------------------------------*/
*************** static inline bitmap dom_children (basic
*** 347,370 ****
  
  /* Iterator object for traversing over BASIC BLOCKs.  */
  
! typedef struct {
!   tree *tp;
!   tree context;		/* Stack for descending into BIND_EXPR's.  */
  } block_stmt_iterator;
  
  extern block_stmt_iterator bsi_start (basic_block);
  extern block_stmt_iterator bsi_last (basic_block);
  static inline bool bsi_end_p (block_stmt_iterator);
  static inline void bsi_next (block_stmt_iterator *);
! extern void bsi_prev (block_stmt_iterator *);
  static inline tree bsi_stmt (block_stmt_iterator);
  static inline tree *bsi_stmt_ptr (block_stmt_iterator);
! static inline tree *bsi_container (block_stmt_iterator);
  
- extern block_stmt_iterator bsi_from_tsi (tree_stmt_iterator);
  static inline tree_stmt_iterator tsi_from_bsi (block_stmt_iterator);
  
  extern void bsi_remove (block_stmt_iterator *);
  
  enum bsi_iterator_update
  {
--- 358,382 ----
  
  /* Iterator object for traversing over BASIC BLOCKs.  */
  
! typedef struct
! {
!   tree_cell curr_stmt;
!   basic_block bb;
  } block_stmt_iterator;
  
  extern block_stmt_iterator bsi_start (basic_block);
  extern block_stmt_iterator bsi_last (basic_block);
  static inline bool bsi_end_p (block_stmt_iterator);
  static inline void bsi_next (block_stmt_iterator *);
! static inline void bsi_prev (block_stmt_iterator *);
  static inline tree bsi_stmt (block_stmt_iterator);
  static inline tree *bsi_stmt_ptr (block_stmt_iterator);
! static inline tree_cell bsi_cell (block_stmt_iterator);
  
  static inline tree_stmt_iterator tsi_from_bsi (block_stmt_iterator);
  
  extern void bsi_remove (block_stmt_iterator *);
+ extern void bsi_remove_leave_annot (block_stmt_iterator *);
  
  enum bsi_iterator_update
  {
*************** enum bsi_iterator_update
*** 376,381 ****
--- 388,394 ----
  
  extern void bsi_insert_before (block_stmt_iterator *, tree, enum bsi_iterator_update);
  extern void bsi_insert_after (block_stmt_iterator *, tree, enum bsi_iterator_update);
+ extern void tree_move_block_after (basic_block, basic_block, bool);
  extern void bsi_insert_on_edge (edge, tree);
  extern int bsi_commit_edge_inserts (int, int *);
  extern block_stmt_iterator bsi_insert_on_edge_immediate
*************** extern void bsi_insert_list_before (bloc
*** 389,396 ****
  extern void bsi_insert_list_after (block_stmt_iterator *, tree_stmt_anchor);
  extern block_stmt_iterator bsi_insert_list_on_edge (edge, tree_stmt_anchor);
  
- void bsi_next_in_bb (block_stmt_iterator *, basic_block);
- 
  /*---------------------------------------------------------------------------
  			      Global declarations
  ---------------------------------------------------------------------------*/
--- 402,407 ----
*************** extern GTY(()) varray_type call_clobbere
*** 426,433 ****
  			      Function prototypes
  ---------------------------------------------------------------------------*/
  /* In tree-cfg.c  */
! extern void build_tree_cfg (tree *);
! extern void delete_tree_cfg (void);
  extern bool is_ctrl_stmt (tree);
  extern bool is_ctrl_altering_stmt (tree);
  extern bool is_computed_goto (tree);
--- 437,444 ----
  			      Function prototypes
  ---------------------------------------------------------------------------*/
  /* In tree-cfg.c  */
! extern void build_tree_cfg (tree_cell);
! extern tree_cell delete_tree_cfg (void);
  extern bool is_ctrl_stmt (tree);
  extern bool is_ctrl_altering_stmt (tree);
  extern bool is_computed_goto (tree);
*************** extern bool cleanup_switch_expr_graph (b
*** 460,465 ****
--- 471,477 ----
  extern void tree_optimize_tail_calls (void);
  extern basic_block tree_block_forwards_to (basic_block bb);
  extern void dump_cfg_function_to_file (tree, FILE *, int);
+ void tree_cleanup_block_edges (basic_block, bool);
  
  /* In tree-dfa.c  */
  void find_referenced_vars (tree);
*************** extern void mark_new_vars_to_rename (tre
*** 503,511 ****
  #define TDFA_USE_VOPS		1 << 1
  
  /* In gimple-low.c  */
! void lower_function_body (tree *);
  void expand_used_vars (void);
  void record_vars (tree);
  
  /* In tree-ssa.c  */
  extern void init_tree_ssa (void);
--- 515,526 ----
  #define TDFA_USE_VOPS		1 << 1
  
  /* In gimple-low.c  */
! tree_cell lower_function_body (tree *);
  void expand_used_vars (void);
  void record_vars (tree);
+ tree_cell tree_cell_alloc (tree);
+ tree unchain (tree_cell);
+ void dump_chain (FILE *, tree, tree_cell, int);
  
  /* In tree-ssa.c  */
  extern void init_tree_ssa (void);
*************** extern bool tree_could_trap_p (tree);
*** 562,570 ****
  extern bool tree_could_throw_p (tree);
  extern bool tree_can_throw_internal (tree);
  extern bool tree_can_throw_external (tree);
- 
- /* In gimple-low.c  */
- void lower_function_body (tree *);
  
  #include "tree-flow-inline.h"
  
--- 577,582 ----
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.68
diff -c -3 -p -r1.1.4.68 tree-optimize.c
*** tree-optimize.c	5 Nov 2003 13:39:23 -0000	1.1.4.68
--- tree-optimize.c	5 Nov 2003 15:43:44 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 51,58 ****
  /* Main entry point to the tree SSA transformation routines.  FNDECL is the
     FUNCTION_DECL node for the function to optimize.  */
  
! void
! optimize_function_tree (tree fndecl, tree *chain)
  {
    /* Don't bother doing anything if the program has errors.  */
    if (errorcount || sorrycount)
--- 51,58 ----
  /* Main entry point to the tree SSA transformation routines.  FNDECL is the
     FUNCTION_DECL node for the function to optimize.  */
  
! static void
! optimize_function_tree (tree fndecl, tree_cell *chain)
  {
    /* Don't bother doing anything if the program has errors.  */
    if (errorcount || sorrycount)
*************** optimize_function_tree (tree fndecl, tre
*** 61,67 ****
    /* Build the flowgraph.  */
    init_flow ();
  
!   build_tree_cfg (chain);
  
    /* Begin analysis and optimization passes.  After the function is
       initially renamed into SSA form, passes are responsible from keeping
--- 61,67 ----
    /* Build the flowgraph.  */
    init_flow ();
  
!   build_tree_cfg (*chain);
  
    /* Begin analysis and optimization passes.  After the function is
       initially renamed into SSA form, passes are responsible from keeping
*************** optimize_function_tree (tree fndecl, tre
*** 80,89 ****
--- 80,95 ----
  
        /* Eliminate tail recursion calls.  */
        tree_optimize_tail_calls ();
+ #ifdef ENABLE_CHECKING
+       verify_flow_info ();
+ #endif
  
        /* Compute aliasing information for all the variables referenced in
  	 the function.  */
        compute_may_aliases (fndecl);
+ #ifdef ENABLE_CHECKING
+       verify_flow_info ();
+ #endif
  
        /*			BEGIN SSA PASSES
  
*************** optimize_function_tree (tree fndecl, tre
*** 96,105 ****
--- 102,117 ----
        /* Rewrite the function into SSA form.  Initially, request all
  	 variables to be renamed.  */
        rewrite_into_ssa (fndecl, NULL, TDI_ssa_1);
+ #ifdef ENABLE_CHECKING
+       verify_flow_info ();
+ #endif
  
        /* Set up VARS_TO_RENAME to allow passes to inform which variables
  	 need to be renamed.  */
        vars_to_rename = sbitmap_alloc (num_referenced_vars);
+ #ifdef ENABLE_CHECKING
+       verify_flow_info ();
+ #endif
  
        /* Perform dominator optimizations.  */
        if (flag_tree_dom)
*************** optimize_function_tree (tree fndecl, tre
*** 119,124 ****
--- 131,139 ----
  	 dead pointer assignments taking the address of local variables.  */
        if (flag_tree_dce)
  	tree_ssa_dce (fndecl, TDI_dce_1);
+ #ifdef ENABLE_CHECKING
+       verify_flow_info ();
+ #endif
  
        /* The must-alias pass removes the aliasing and addressability bits
  	 from variables that used to have their address taken.  */
*************** optimize_function_tree (tree fndecl, tre
*** 131,136 ****
--- 146,154 ----
  	  if (sbitmap_first_set_bit (vars_to_rename) >= 0)
  	    rewrite_into_ssa (fndecl, vars_to_rename, TDI_ssa_3);
  	}
+ #ifdef ENABLE_CHECKING
+       verify_flow_info ();
+ #endif
  
        /* Run SCCP (Sparse Conditional Constant Propagation).  */
        if (flag_tree_ccp)
*************** optimize_function_tree (tree fndecl, tre
*** 142,151 ****
--- 160,175 ----
  	  if (sbitmap_first_set_bit (vars_to_rename) >= 0)
  	    rewrite_into_ssa (fndecl, vars_to_rename, TDI_ssa_4);
  	}
+ #ifdef ENABLE_CHECKING
+       verify_flow_info ();
+ #endif
  
        /* Run SSA-PRE (Partial Redundancy Elimination).  */
        if (flag_tree_pre)
  	tree_perform_ssapre (fndecl, TDI_pre);
+ #ifdef ENABLE_CHECKING
+       verify_flow_info ();
+ #endif
  
        /* Perform a second pass of dominator optimizations.  */
        if (flag_tree_dom)
*************** optimize_function_tree (tree fndecl, tre
*** 172,178 ****
        sbitmap_free (vars_to_rename);
      }
  
!   delete_tree_cfg ();
  }
  
  
--- 196,202 ----
        sbitmap_free (vars_to_rename);
      }
  
!   *chain = delete_tree_cfg ();
  }
  
  
*************** void
*** 239,245 ****
  tree_rest_of_compilation (tree fndecl, bool nested_p)
  {
    location_t saved_loc;
!   tree saved_tree = NULL, chain;
  
    timevar_push (TV_EXPAND);
  
--- 263,272 ----
  tree_rest_of_compilation (tree fndecl, bool nested_p)
  {
    location_t saved_loc;
!   tree saved_tree = NULL;
!   tree_cell chain;
!   FILE *dump_file;
!   int dump_flags;
  
    timevar_push (TV_EXPAND);
  
*************** tree_rest_of_compilation (tree fndecl, b
*** 289,309 ****
    lower_eh_constructs (&DECL_SAVED_TREE (fndecl));
  
    /* Lower the structured statements.  */
!   lower_function_body (&DECL_SAVED_TREE (fndecl));
!   chain = DECL_SAVED_TREE (fndecl);
  
    /* Avoid producing notes for blocks.  */
    cfun->dont_emit_block_notes = 1;
    reset_block_changes ();
  
!   dump_function (TDI_lower, fndecl);
  
    /* Invoke the SSA tree optimizer.  */
    if (optimize >= 1 && !flag_disable_tree_ssa)
      optimize_function_tree (fndecl, &chain);
  
!   DECL_SAVED_TREE (fndecl) = build (BIND_EXPR, void_type_node,
! 				    NULL_TREE, chain, NULL_TREE);
  
    /* If the function has a variably modified type, there may be
       SAVE_EXPRs in the parameter types.  Their context must be set to
--- 316,339 ----
    lower_eh_constructs (&DECL_SAVED_TREE (fndecl));
  
    /* Lower the structured statements.  */
!   chain = lower_function_body (&DECL_SAVED_TREE (fndecl));
  
    /* Avoid producing notes for blocks.  */
    cfun->dont_emit_block_notes = 1;
    reset_block_changes ();
  
!   dump_file = dump_begin (TDI_lower, &dump_flags);
!   if (dump_file)
!     {
!       dump_chain (dump_file, fndecl, chain, dump_flags);
!       dump_end (TDI_lower, dump_file);
!     }
  
    /* Invoke the SSA tree optimizer.  */
    if (optimize >= 1 && !flag_disable_tree_ssa)
      optimize_function_tree (fndecl, &chain);
  
!   BIND_EXPR_BODY (DECL_SAVED_TREE (fndecl)) = unchain (chain);
  
    /* If the function has a variably modified type, there may be
       SAVE_EXPRs in the parameter types.  Their context must be set to
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-pretty-print.c,v
retrieving revision 1.1.2.55
diff -c -3 -p -r1.1.2.55 tree-pretty-print.c
*** tree-pretty-print.c	3 Nov 2003 17:54:04 -0000	1.1.2.55
--- tree-pretty-print.c	5 Nov 2003 15:43:44 -0000
*************** dump_block_info (pretty_printer *buffer,
*** 1979,1997 ****
    if (bb)
      {
        edge e;
!       tree *stmt_p = bb->head_tree_p;
        int lineno;
  
        newline_and_indent (buffer, spc);
        pp_scalar (buffer, "# block %d", bb->index);
  
!       if (stmt_p
! 	  && is_exec_stmt (*stmt_p)
! 	  && (lineno = get_lineno (*stmt_p)) > 0
  	  && (flags & TDF_LINENO))
  	{
  	  pp_string (buffer, " (");
! 	  pp_string (buffer, get_filename (*stmt_p));
  	  pp_scalar (buffer, ":%d", lineno);
  	  pp_string (buffer, ")");
  	}
--- 1979,1997 ----
    if (bb)
      {
        edge e;
!       tree_cell cell = bb->head_tree;
        int lineno;
  
        newline_and_indent (buffer, spc);
        pp_scalar (buffer, "# block %d", bb->index);
  
!       if (cell
! 	  && is_exec_stmt (cell->stmt)
! 	  && (lineno = get_lineno (cell->stmt)) > 0
  	  && (flags & TDF_LINENO))
  	{
  	  pp_string (buffer, " (");
! 	  pp_string (buffer, get_filename (cell->stmt));
  	  pp_scalar (buffer, ":%d", lineno);
  	  pp_string (buffer, ")");
  	}
Index: tree-ssa-dce.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dce.c,v
retrieving revision 1.1.2.64
diff -c -3 -p -r1.1.2.64 tree-ssa-dce.c
*** tree-ssa-dce.c	5 Nov 2003 13:39:23 -0000	1.1.2.64
--- tree-ssa-dce.c	5 Nov 2003 15:43:44 -0000
*************** remove_dead_stmts (void)
*** 395,408 ****
    tree t;
    block_stmt_iterator i;
  
!   FOR_EACH_BB_REVERSE (bb)
      {
-       bsi_list_p stack;
        /* Remove dead PHI nodes.  */
        remove_dead_phis (bb);
  
        /* Remove dead statements.  */
!       FOR_EACH_BSI_IN_REVERSE (stack, bb, i)
  	{
  	  t = bsi_stmt (i);
  	  stats.total++;
--- 395,407 ----
    tree t;
    block_stmt_iterator i;
  
!   FOR_EACH_BB (bb)
      {
        /* Remove dead PHI nodes.  */
        remove_dead_phis (bb);
  
        /* Remove dead statements.  */
!       for (i = bsi_start (bb); !bsi_end_p (i); )
  	{
  	  t = bsi_stmt (i);
  	  stats.total++;
*************** remove_dead_stmts (void)
*** 410,415 ****
--- 409,416 ----
  	  /* If `i' is not in `necessary' then remove from B.  */
  	  if (!necessary_p (t))
  	    remove_dead_stmt (&i);
+ 	  else
+ 	    bsi_next (&i);
  	}
      }
  }
Index: tree-ssa-live.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-live.c,v
retrieving revision 1.1.2.23
diff -c -3 -p -r1.1.2.23 tree-ssa-live.c
*** tree-ssa-live.c	22 Oct 2003 20:28:25 -0000	1.1.2.23
--- tree-ssa-live.c	5 Nov 2003 15:43:44 -0000
*************** build_tree_conflict_graph (tree_live_inf
*** 1301,1309 ****
    bitmap live;
    int num, x, y, i;
    basic_block bb;
!   varray_type stmt_stack, ops, partition_link, tpa_to_clear, tpa_nodes;
    stmt_ann_t ann;
    tree stmt, *var_p;
    unsigned l;
  
    map = live_var_map (liveinfo);
--- 1301,1310 ----
    bitmap live;
    int num, x, y, i;
    basic_block bb;
!   varray_type ops, partition_link, tpa_to_clear, tpa_nodes;
    stmt_ann_t ann;
    tree stmt, *var_p;
+   block_stmt_iterator bsi;
    unsigned l;
  
    map = live_var_map (liveinfo);
*************** build_tree_conflict_graph (tree_live_inf
*** 1323,1331 ****
        /* Start with live on exit temporaries.  */
        bitmap_copy (live, live_on_exit (liveinfo, bb));
  
!       FOR_EACH_STMT_IN_REVERSE (stmt_stack, bb, stmt)
          {
  	  tree important_copy_rhs_partition = NULL_TREE;
  
  	  get_stmt_operands (stmt);
  	  ann = stmt_ann (stmt);
--- 1324,1333 ----
        /* Start with live on exit temporaries.  */
        bitmap_copy (live, live_on_exit (liveinfo, bb));
  
!       for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
          {
  	  tree important_copy_rhs_partition = NULL_TREE;
+ 	  stmt = bsi_stmt (bsi);
  
  	  get_stmt_operands (stmt);
  	  ann = stmt_ann (stmt);
Index: tree-ssa-pre.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-pre.c,v
retrieving revision 1.1.4.97
diff -c -3 -p -r1.1.4.97 tree-ssa-pre.c
*** tree-ssa-pre.c	5 Nov 2003 13:39:23 -0000	1.1.4.97
--- tree-ssa-pre.c	5 Nov 2003 15:43:44 -0000
*************** static inline bool injured_real_occ_phi_
*** 247,253 ****
  static void compute_du_info (struct expr_info *);
  static void add_ephi_use (tree, tree, int);
  static void insert_one_operand (struct expr_info *, tree, int, tree, edge);
! static bool split_critical_edges (void);
  static void collect_expressions (basic_block, varray_type *);
  static int build_dfn_array (basic_block, int);
  static int eref_compare (const void *, const void *);
--- 247,253 ----
  static void compute_du_info (struct expr_info *);
  static void add_ephi_use (tree, tree, int);
  static void insert_one_operand (struct expr_info *, tree, int, tree, edge);
! static void split_critical_edges (void);
  static void collect_expressions (basic_block, varray_type *);
  static int build_dfn_array (basic_block, int);
  static int eref_compare (const void *, const void *);
*************** pre_expression (struct expr_info *slot, 
*** 3126,3156 ****
    return 0;
  }
  
! static bool
  split_critical_edges (void)
  {
    struct edge_list *el = create_edge_list ();
-   bool did_something = false;
-   tree tempvar = create_tmp_var (integer_type_node, "critedgetmp");
    int i;
    edge e;
!   add_referenced_tmp_var (tempvar);
    for (i = 0; i < NUM_EDGES (el); i++)
!   {
!     e = INDEX_EDGE (el, i);
!     if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL))
!       {
!         tree newexpr = build (MODIFY_EXPR, TREE_TYPE (tempvar), tempvar, 
! 			      integer_zero_node);
! 	tree newtemp = make_ssa_name (tempvar, newexpr);
! 	TREE_OPERAND (newexpr, 0) = newtemp;
! 	bsi_insert_on_edge (e, newexpr);
! 	did_something = true;
!       }
!   }
!   bsi_commit_edge_inserts (0, 0);
    free_edge_list (el);
-   return did_something;
  }
  
  /* Step 1 - Collect the expressions to perform PRE on.  */
--- 3126,3145 ----
    return 0;
  }
  
! static void
  split_critical_edges (void)
  {
    struct edge_list *el = create_edge_list ();
    int i;
    edge e;
! 
    for (i = 0; i < NUM_EDGES (el); i++)
!     {
!       e = INDEX_EDGE (el, i);
!       if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL))
! 	split_edge (e);
!     }
    free_edge_list (el);
  }
  
  /* Step 1 - Collect the expressions to perform PRE on.  */
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.263.2.65
diff -c -3 -p -r1.263.2.65 tree.c
*** tree.c	28 Oct 2003 14:56:21 -0000	1.263.2.65
--- tree.c	5 Nov 2003 15:43:45 -0000
*************** tsi_link_after (tree_stmt_iterator *i, t
*** 5345,5365 ****
        /* Create a new node with the same 'next' link as the current one.  */
        ce = build (COMPOUND_EXPR, void_type_node, t, next);
  
-       /* If the 'next' statement is a COMPOUND_EXPR and was the first
- 	 statement of a basic block, we need to adjust the 'head_tree_p'
- 	 field of that block because we are about to move the statement one
- 	 position down in the CE chain.  */
-       {
- 	basic_block bb = bb_for_stmt (next);
- 	if (bb && bb->head_tree_p == &TREE_OPERAND (cur, 1))
- 	  {
- 	    /* We may also need to update end_tree_p.  */
- 	    if (bb->head_tree_p == bb->end_tree_p)
- 	      bb->end_tree_p = &TREE_OPERAND (ce, 1);
- 	    bb->head_tree_p = &TREE_OPERAND (ce, 1);
- 	  }
-       }
- 
        /* Make the current one's 'next' link point to our new stmt.  */
        TREE_OPERAND (cur, 1) = ce;
  
--- 5345,5350 ----
*************** tsi_link_chain_after (tree_stmt_iterator
*** 5473,5493 ****
  
        /* Create a new node with the same 'next' link as the current one.  */
        ce = build (COMPOUND_EXPR, void_type_node, *last, next);
- 
-       /* If the 'next' statement is a COMPOUND_EXPR and was the first
- 	 statement of a basic block, we need to adjust the 'head_tree_p'
- 	 field of that block because we are about to move the statement one
- 	 position down in the CE chain.  */
-       {
- 	basic_block bb = bb_for_stmt (next);
- 	if (bb && bb->head_tree_p == nextp)
- 	  {
- 	    /* We may also need to update end_tree_p.  */
- 	    if (bb->head_tree_p == bb->end_tree_p)
- 	      bb->end_tree_p = &TREE_OPERAND (ce, 1);
- 	    bb->head_tree_p = &TREE_OPERAND (ce, 1);
- 	  }
-       }
  
        *last = ce;
        TREE_OPERAND (cur, 1) = t;
--- 5458,5463 ----
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.122
diff -c -3 -p -r1.342.2.122 tree.h
*** tree.h	5 Nov 2003 13:39:24 -0000	1.342.2.122
--- tree.h	5 Nov 2003 15:43:45 -0000
*************** extern void expand_start_case_dummy (voi
*** 3439,3447 ****
  extern void declare_nonlocal_label (tree);
  extern int containing_blocks_have_cleanups_or_stack_level (void);
  
- /* In tree-optimize.c.  */
- void optimize_function_tree (tree, tree *);
- 
  /* In gimplify.c.  */
  extern void gimplify_function_tree (tree);
  extern const char *get_name (tree);
--- 3439,3444 ----


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