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]

[ast-optimizer-branch] Fixes for -Wuninitialized and SSA form [patch]


This patch fixes several bugs in the SSA form that popped up
while implementing support for -Wuninitialized.  It also merges
part of Jan's CFG changes to simplify a future merge with the
trunk.

- When adding PHI terms, they were being added at the end of the
  list of references for the block.  This caused uses of the same
  variable to miss the PHI definition.

- Some header blocks were being created out of order w.r.t. the
  body of the control structure.  For instance, the block for
  DO_COND was created before the body.  This caused the following
  problem:

  do
    a = ...;
  while (a);

  The use of A was being found before the definition of A.

- SWITCH_STMT blocks had an edge to the first block outside the
  switch even if the default label was present.

- References to arrays and structures were not being classified
  correctly as definitions when used on the lhs.


New features:

- Calls to non-returning functions end a basic block and get an
  edge to EXIT_BLOCK_PTR.

- We now model infinite loops, one-iteration DO loops,
  zero-iteration FOR and WHILE loops, and always-true/always-false
  conditionals.  This reduced the number of false positives for
  -Wuninitialized quite a bit.


Bootstrapped and regression tested on x86.  Committed to the
AST branch.


Diego.

	* Merge from mainline:

	Tue Sep 11 11:37:52 CEST 2001  Jan Hubicka  <jh@suse.cz>

		* basic-block.h (cached_make_edge): New.
		(make_edge): Remove first parameter.
		* flow.c (cached_make_edge): Rename from make_edge; return
		newly created edge; use obstack allocation.
		(make_edge): New.
		(flow_call_edges_add): Updaet make_edge call.
		(add_noreturn_fake_exit_edges): Likewise.
		(connect_infinite_loops_to_exit): Liekwise.
		(make_label_edge, make_edges, find_sub_basic_blocks): Use
		cached_make_edge.
		* profile.c (branch_prob): Update make_edge call.
		* ssa-dce.c (ssa_eliminate_dead_code): Likewise.

	* Makefile.in (tree-ssa.o): Remove dependency on flags.h.
	(tree-optimize.o): Add dependency on flags.h.
	* bb-reorder.c (fixup_reorder_chain): Update call to make_edge.
	* c-lang.c (c_post_options): Set flag_tree_ssa if -Wuninitialized
	is given.
	* ifcvt.c (find_if_case_1): Update call to make_edge.
	* toplev.c (toplev_main): Do not warn about -Wuninitialized without
	-O if -ftree-ssa is used.
	* tree-cfg.c (dot_dump_file): Remove.
	(dot_dump_flags): Remove.
	(cfg_dump_file): Rename to dump_file.
	(cfg_dump_flags): Rename to dump_flags.
	(remove_bb_ann): New function.
	(tree_find_basic_blocks): Do not open dump files at the beginning
	of the function.
	Do not call delete_cfg.
	Create annotations for ENTRY_BLOCK_PTR and EXIT_BLOCK_PTR.
	(make_for_stmt_blocks): Update FOR_INIT_STMT_BB and FOR_COND_BB
	when creating the header blocks.
	Create the blocks for the loop body before the expression block.
	(make_while_stmt_blocks): Update END_WHILE_BB when creating the
	header blocks.
	Create the blocks for the loop body before the end-while block.
	(make_do_stmt_blocks): Update DO_COND_BB when creating header
	blocks.
	Create the blocks for the loop body before the block for DO_COND.
	(create_bb): When creating loop header blocks, allocate space for
	the header_blocks union.
	Call create_bb_ann to create a new annotation.
	(remove_bb_ann): New function.
	(tree_split_bb): New function.
	(make_edges): Remove first argument from call to make_edge,
	make_ctrl_stmt_edges, make_exit_edges, make_for_stmt_edges,
	make_while_stmt_edges, make_do_stmt_edges, make_if_stmt_edges,
	make_goto_stmt_edges, make_break_stmt_edges and
	make_continue_stmt_edges.
	When creating edges for the default label, remove the fallthru edge
	that was created for the associated SWITCH_STMT entry block.
	Do not call delete_unreachable_blocks.
	Call tree_cleanup_cfg.
	(make_ctrl_stmt_edges): Remove first argument.
	(make_exit_edges): Remove first argument.
	If the last element of the block is an EXPR_STMT, assume that it is
	the call to a non-returning function and make an edge to the exit
	block.
	Do not call make_return_stmt_edges.  Call make_edge directly.
	(make_for_stmt_edges): Remove first argument.
	Simplify the graph for infinite and zero-iteration loops.
	(make_while_stmt_edges): Remove first argument.
	Simplify the graph for infinite and zero-iteration loops.
	(make_do_stmt_edges): Remove first argument.
	Simplify the graph for infinite and one-iteration loops.
	(make_if_stmt_edges): Remove first argument.
	Simplify the graph for always-true and always-false conditionals.
	(make_goto_stmt_edges): Remove first argument.
	(make_break_stmt_edges): Remove first argument.
	(make_continue_stmt_edges): Remove first argument.
	(make_return_stmt_edges): Remove.
	(tree_cleanup_cfg): New function.
	(delete_unreachable_blocks): Do not react to -Wunreachable-code.
	Write to dump file blocks that have been removed.
	Call remove_edge.
	(is_ctrl_altering_stmt): If the statement contains a call to a
	non-returning function, return 1.
	(delete_cfg): Call remove_bb_ann.  Also remove annotations for
	ENTRY_BLOCK_PTR and EXIT_BLOCK_PTR.
	(latch_block): Use WHILE_COND_BB instead of END_WHILE_BB.
	(insert_stmt_tree_before): Use cfg_dump_file instead of dump_file.
	(insert_before_ctrl_stmt): Ditto.
	(insert_before_normal_stmt): Ditto.
	(insert_stmt_tree_after): Ditto.
	(insert_after_ctrl_stmt): Ditto.
	(insert_after_normal_stmt): Ditto.
	(replace_expr_in_tree): Ditto.
	(insert_bb_before): Ditto.
	* tree-dfa.c (tree_find_varrefs): Call find_refs_in_expr when the
	tree is not a statement.
	(find_refs_in_stmt): Update comments.
	Do not deal with FOR_STMT and DO_STMT trees separately.
	When processing VAR_DECLs, call find_refs_in_expr with the
	declaration, not its initial value.
	(find_refs_in_expr): When processing COMPONENT_REFs and ARRAY_REFs,
	recurse using the same reference type that was given by the
	original caller.
	(create_varref): Insert new PHI terms at the beginning of the
	BB_REFS array, not the end.
	* tree-flow.h (struct for_header_blocks): Declare.
	(union header_blocks): Declare.
	(struct bb_ann_def): Add new field 'loop_hdr'.
	(BB_ANN): Re-define so that it can be used as an lvalue.
	(BB_PARENT): Ditto.
	(BB_REFS): Ditto.
	(BB_PREV_CHAIN): Ditto.
	(BB_BINDING_SCOPE): Ditto.
	(BB_LOOP_HDR): Define.
	(FOR_INIT_STMT_BB): Redefine using BB_LOOP_HDR.
	(FOR_COND_BB): Ditto.
	(FOR_EXPR_BB): Ditto.
	(DO_COND_BB): Ditto.
	(END_WHILE_BB): New name for WHILE_COND_BB.
	(tree_warn_uninitialized): Declare.
	(tree_cleanup_cfg): Declare.
	(tree_split_bb): Declare.
	* tree-optimize.c: Include flags.h.
	(init_tree_flow): New function.
	(optimize_tree): Call build_tree_ssa instead of building SSA
	in-place.
	(build_tree_ssa): New function.
	* tree-optimize.h (build_tree_ssa): Declare.
	* tree-ssa.c: Don't include toplev.h
	(tree_warn_uninitialized): Define.
	(tree_compute_rdefs): Do not call is_upward_exposed.  Instead
	traverse all the uses of each variable and warn if the use is
	reached by the ghost definition.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.701.2.5
diff -d -p -d -u -p -r1.701.2.5 Makefile.in
--- Makefile.in	2001/09/30 06:24:05	1.701.2.5
+++ Makefile.in	2001/10/14 23:28:36
@@ -1335,7 +1335,7 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) 
 
 tree-ssa.o : tree-ssa.c tree-optimize.h tree-flow.h $(CONFIG_H) $(SYSTEM_H) \
    $(RTL_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) $(EXPR_H) $(C_COMMON_H) \
-   $(GGC_H) flags.h output.h diagnostic.h ssa.h errors.h toplev.h
+   $(GGC_H) output.h diagnostic.h ssa.h errors.h toplev.h
 tree-cfg.o : tree-cfg.c tree-optimize.h tree-flow.h $(CONFIG_H) $(SYSTEM_H) \
    $(RTL_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) $(EXPR_H) $(C_COMMON_H) \
    $(GGC_H) flags.h output.h diagnostic.h errors.h
@@ -1344,7 +1344,7 @@ tree-dfa.o : tree-dfa.c tree-optimize.h 
    $(GGC_H) output.h diagnostic.h errors.h
 tree-optimize.o : tree-optimize.c tree-optimize.h tree-flow.h $(CONFIG_H) \
    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) $(EXPR_H) \
-   $(C_COMMON_H) $(GGC_H) output.h diagnostic.h ssa.h errors.h
+   $(C_COMMON_H) $(GGC_H) output.h diagnostic.h ssa.h errors.h flags.h
 
 print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(GGC_H)
 stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.102.2.3
diff -d -p -d -u -p -r1.102.2.3 basic-block.h
--- basic-block.h	2001/09/30 06:24:06	1.102.2.3
+++ basic-block.h	2001/10/14 23:28:36
@@ -309,7 +309,9 @@ extern void connect_infinite_loops_to_ex
 extern int flow_call_edges_add 		PARAMS ((sbitmap));
 extern rtx flow_delete_insn		PARAMS ((rtx));
 extern void flow_delete_insn_chain	PARAMS ((rtx, rtx));
-extern void make_edge			PARAMS ((sbitmap *, basic_block,
+extern edge make_edge			PARAMS ((basic_block, basic_block,
+						 int));
+extern edge cached_make_edge		PARAMS ((sbitmap *, basic_block,
 						 basic_block, int));
 extern void remove_edge			PARAMS ((edge));
 extern void redirect_edge_succ		PARAMS ((edge, basic_block));
Index: bb-reorder.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/bb-reorder.c,v
retrieving revision 1.30
diff -d -p -d -u -p -r1.30 bb-reorder.c
--- bb-reorder.c	2001/07/14 01:06:41	1.30
+++ bb-reorder.c	2001/10/14 23:28:36
@@ -712,7 +712,7 @@ fixup_reorder_chain ()
       RBI (bb)->next = nb;
 
       /* Link to new block.  */
-      make_edge (NULL, nb, e_fall->dest, 0);
+      make_edge (nb, e_fall->dest, 0);
       redirect_edge_succ (e_fall, nb);
 
       /* Don't process this new block.  */
Index: c-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-lang.c,v
retrieving revision 1.53
diff -d -p -d -u -p -r1.53 c-lang.c
--- c-lang.c	2001/07/09 18:36:15	1.53
+++ c-lang.c	2001/10/14 23:28:36
@@ -54,6 +54,10 @@ static void
 c_post_options ()
 {
   cpp_post_options (parse_in);
+
+  /* Enable tree SSA analysis if -Wuninitialized is used.  */
+  if (warn_uninitialized == 1)
+    flag_tree_ssa = 1;
 }
 
 static void
Index: flow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.431.2.3
diff -d -p -d -u -p -r1.431.2.3 flow.c
--- flow.c	2001/08/27 15:52:11	1.431.2.3
+++ flow.c	2001/10/14 23:28:37
@@ -760,7 +760,7 @@ find_sub_basic_blocks (bb)
 	  jump_insn = 0;
 	  created = 1;
 	  if (LABEL_ALTERNATE_NAME (insn))
-	    make_edge (NULL, ENTRY_BLOCK_PTR, bb, 0);
+	    make_edge (ENTRY_BLOCK_PTR, bb, 0);
 	  break;
 	case INSN:
 	  /* In case we've previously split insn on the JUMP_INSN, move the
@@ -1205,7 +1205,7 @@ make_edges (label_value_list)
     }
 
   /* By nature of the way these get numbered, block 0 is always the entry.  */
-  make_edge (edge_cache, ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU);
+  cached_make_edge (edge_cache, ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU);
 
   for (i = 0; i < n_basic_blocks; ++i)
     {
@@ -1216,7 +1216,7 @@ make_edges (label_value_list)
 
       if (GET_CODE (bb->head) == CODE_LABEL
 	  && LABEL_ALTERNATE_NAME (bb->head))
-	make_edge (NULL, ENTRY_BLOCK_PTR, bb, 0);
+	make_edge (ENTRY_BLOCK_PTR, bb, 0);
 
       /* Examine the last instruction of the block, and discover the
 	 ways we can leave the block.  */
@@ -1289,7 +1289,7 @@ make_edges (label_value_list)
 
 	  /* Returns create an exit out.  */
 	  else if (returnjump_p (insn))
-	    make_edge (edge_cache, bb, EXIT_BLOCK_PTR, 0);
+	    cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR, 0);
 
 	  /* Otherwise, we have a plain conditional or unconditional jump.  */
 	  else
@@ -1306,7 +1306,7 @@ make_edges (label_value_list)
 	 wouldn't have created the sibling call in the first place.  */
 
       if (code == CALL_INSN && SIBLING_CALL_P (insn))
-	make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
+	cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
 		   EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
 
       /* If this is a CALL_INSN, then mark it as reaching the active EH
@@ -1342,14 +1342,14 @@ make_edges (label_value_list)
       /* Find out if we can drop through to the next block.  */
       insn = next_nonnote_insn (insn);
       if (!insn || (i + 1 == n_basic_blocks && force_fallthru))
-	make_edge (edge_cache, bb, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
+	cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
       else if (i + 1 < n_basic_blocks)
 	{
 	  rtx tmp = BLOCK_HEAD (i + 1);
 	  if (GET_CODE (tmp) == NOTE)
 	    tmp = next_nonnote_insn (tmp);
 	  if (force_fallthru || insn == tmp)
-	    make_edge (edge_cache, bb, BASIC_BLOCK (i + 1), EDGE_FALLTHRU);
+	    cached_make_edge (edge_cache, bb, BASIC_BLOCK (i + 1), EDGE_FALLTHRU);
 	}
     }
 
@@ -1357,11 +1357,22 @@ make_edges (label_value_list)
     sbitmap_vector_free (edge_cache);
 }
 
-/* Create an edge between two basic blocks.  FLAGS are auxiliary information
-   about the edge that is accumulated between calls.  */
+/* Create an edge connecting SRC and DEST with flags FLAGS.  Return newly
+   created edge or NULL if already exist.  */
 
-void
-make_edge (edge_cache, src, dst, flags)
+edge
+make_edge (src, dest, flags)
+     basic_block src, dest;
+     int flags;
+{
+  return cached_make_edge (NULL, src, dest, flags);
+}
+
+/* Create an edge connecting SRC and DST with FLAGS optionally using
+   edge cache CACHE.  Return the new edge, NULL if already exist.  */
+
+edge
+cached_make_edge (edge_cache, src, dst, flags)
      sbitmap *edge_cache;
      basic_block src, dst;
      int flags;
@@ -1385,7 +1396,7 @@ make_edge (edge_cache, src, dst, flags)
 
       /* The edge exists; early exit if no work to do.  */
       if (flags == 0)
-	return;
+	return NULL;
 
       /* FALLTHRU */
     case 0:
@@ -1393,7 +1404,7 @@ make_edge (edge_cache, src, dst, flags)
 	if (e->dest == dst)
 	  {
 	    e->flags |= flags;
-	    return;
+	    return NULL;
 	  }
       break;
     }
@@ -1412,6 +1423,8 @@ make_edge (edge_cache, src, dst, flags)
 
   if (use_edge_cache)
     SET_BIT (edge_cache[src->index], dst->index);
+
+  return e;
 }
 
 /* Create an edge from a basic block to a label.  */
@@ -1434,7 +1447,7 @@ make_label_edge (edge_cache, src, label,
   if (INSN_UID (label) == 0)
     return;
 
-  make_edge (edge_cache, src, BLOCK_FOR_INSN (label), flags);
+  cached_make_edge (edge_cache, src, BLOCK_FOR_INSN (label), flags);
 }
 
 /* Create the edges generated by INSN in REGION.  */
@@ -2390,7 +2403,7 @@ flow_call_edges_add (blocks)
 	      if (e)
 		blocks_split++;
 
-	      make_edge (NULL, bb, EXIT_BLOCK_PTR, EDGE_FAKE);
+	      make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
 	    }
 	  if (insn == bb->head)
 	    break;
@@ -8488,7 +8501,7 @@ add_noreturn_fake_exit_edges ()
 
   for (x = 0; x < n_basic_blocks; x++)
     if (BASIC_BLOCK (x)->succ == NULL)
-      make_edge (NULL, BASIC_BLOCK (x), EXIT_BLOCK_PTR, EDGE_FAKE);
+      make_edge (BASIC_BLOCK (x), EXIT_BLOCK_PTR, EDGE_FAKE);
 }
 
 /* This function adds a fake edge between any infinite loops to the
@@ -8520,7 +8533,7 @@ connect_infinite_loops_to_exit ()
       unvisited_block = flow_dfs_compute_reverse_execute (&dfs_ds);
       if (!unvisited_block)
 	break;
-      make_edge (NULL, unvisited_block, EXIT_BLOCK_PTR, EDGE_FAKE);
+      make_edge (unvisited_block, EXIT_BLOCK_PTR, EDGE_FAKE);
       flow_dfs_compute_reverse_add_bb (&dfs_ds, unvisited_block);
     }
 
Index: ifcvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.57
diff -d -p -d -u -p -r1.57 ifcvt.c
--- ifcvt.c	2001/07/20 03:59:19	1.57
+++ ifcvt.c	2001/10/14 23:28:37
@@ -2235,7 +2235,7 @@ find_if_case_1 (test_bb, then_edge, else
 		    else_bb->global_live_at_start,
 		    then_bb->global_live_at_end, BITMAP_IOR);
   
-  make_edge (NULL, test_bb, then_succ->dest, 0);
+  make_edge (test_bb, then_succ->dest, 0);
   flow_delete_block (then_bb);
   tidy_fallthru_edge (else_edge, test_bb, else_bb);
 
@@ -2326,7 +2326,7 @@ find_if_case_2 (test_bb, then_edge, else
 		    else_bb->global_live_at_end, BITMAP_IOR);
   
   remove_edge (else_edge);
-  make_edge (NULL, test_bb, else_succ->dest, 0);
+  make_edge (test_bb, else_succ->dest, 0);
   flow_delete_block (else_bb);
 
   num_removed_blocks++;
Index: profile.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.c,v
retrieving revision 1.58
diff -d -p -d -u -p -r1.58 profile.c
--- profile.c	2001/07/11 17:36:50	1.58
+++ profile.c	2001/10/14 23:28:37
@@ -611,14 +611,14 @@ branch_prob ()
 	  if (rtl_dump_file)
 	    fprintf (rtl_dump_file, "Adding fake exit edge to bb %i\n",
 		     bb->index);
-          make_edge (NULL, bb, EXIT_BLOCK_PTR, EDGE_FAKE);
+          make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
 	}
       if (need_entry_edge && !have_entry_edge)
 	{
 	  if (rtl_dump_file)
 	    fprintf (rtl_dump_file, "Adding fake entry edge to bb %i\n",
 		     bb->index);
-          make_edge (NULL, ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
+          make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
 	}
     }
 
Index: ssa-dce.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ssa-dce.c,v
retrieving revision 1.7
diff -d -p -d -u -p -r1.7 ssa-dce.c
--- ssa-dce.c	2001/07/06 18:19:47	1.7
+++ ssa-dce.c	2001/10/14 23:28:37
@@ -707,7 +707,7 @@ ssa_eliminate_dead_code ()
 
 	/* Create an edge from this block to the post dominator.  
 	   What about the PHI nodes at the target?  */
-	make_edge (NULL, bb, pdom_bb, 0);
+	make_edge (bb, pdom_bb, 0);
 
 	/* Third, transform this insn into an unconditional
 	   jump to the label for the immediate postdominator.  */
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.494.2.1
diff -d -p -d -u -p -r1.494.2.1 toplev.c
--- toplev.c	2001/07/24 17:38:10	1.494.2.1
+++ toplev.c	2001/10/14 23:28:37
@@ -4804,8 +4804,11 @@ toplev_main (argc, argv)
 
       /* The c_decode_option function and decode_option hook set
 	 this to `2' if -Wall is used, so we can avoid giving out
-	 lots of errors for people who don't realize what -Wall does.  */
-      if (warn_uninitialized == 1)
+	 lots of errors for people who don't realize what -Wall does.
+ 	 lots of errors for people who don't realize what -Wall does.
+ 	 However, when -ftree-ssa is used, -O is not necessary for finding
+ 	 uses of uninitialized variables.  */
+      if (warn_uninitialized == 1 && !flag_tree_ssa)
 	warning ("-Wuninitialized is not supported without -O");
     }
 
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.2.9
diff -d -p -d -u -p -r1.1.2.9 tree-cfg.c
--- tree-cfg.c	2001/09/30 23:10:08	1.1.2.9
+++ tree-cfg.c	2001/10/14 23:28:37
@@ -46,10 +46,8 @@ static const int initial_cfg_capacity = 
 static varray_type binding_stack;
 
 /* Dump files and flags.  */
-static FILE *cfg_dump_file;
-static FILE *dot_dump_file;
-static int cfg_dump_flags;
-static int dot_dump_flags;
+static FILE *dump_file;
+static int dump_flags;
 
 /* Basic blocks and flowgraphs.  */
 static void make_blocks PARAMS ((tree, basic_block, tree, tree *));
@@ -66,21 +64,21 @@ static void delete_bb PARAMS ((basic_blo
 
 /* Edges.  */
 static void make_edges PARAMS ((void));
-static void make_ctrl_stmt_edges PARAMS ((sbitmap *, basic_block));
-static void make_exit_edges PARAMS ((sbitmap *, basic_block));
-static void make_for_stmt_edges PARAMS ((sbitmap *, basic_block));
-static void make_while_stmt_edges PARAMS ((sbitmap *, basic_block));
-static void make_do_stmt_edges PARAMS ((sbitmap *, basic_block));
-static void make_if_stmt_edges PARAMS ((sbitmap *, basic_block));
-static void make_goto_stmt_edges PARAMS ((sbitmap *, basic_block));
-static void make_break_stmt_edges PARAMS ((sbitmap *, basic_block));
-static void make_continue_stmt_edges PARAMS ((sbitmap *, basic_block));
-static void make_return_stmt_edges PARAMS ((sbitmap *, basic_block));
+static void make_ctrl_stmt_edges PARAMS ((basic_block));
+static void make_exit_edges PARAMS ((basic_block));
+static void make_for_stmt_edges PARAMS ((basic_block));
+static void make_while_stmt_edges PARAMS ((basic_block));
+static void make_do_stmt_edges PARAMS ((basic_block));
+static void make_if_stmt_edges PARAMS ((basic_block));
+static void make_goto_stmt_edges PARAMS ((basic_block));
+static void make_break_stmt_edges PARAMS ((basic_block));
+static void make_continue_stmt_edges PARAMS ((basic_block));
 
 /* Various helpers.  */
 static basic_block successor_block PARAMS ((basic_block));
 static int block_invalidates_loop PARAMS ((basic_block, struct loop *));
 static void create_bb_ann PARAMS ((basic_block));
+static void remove_bb_ann PARAMS ((basic_block));
 
 static void insert_before_ctrl_stmt PARAMS ((tree, tree, basic_block));
 static void insert_before_normal_stmt PARAMS ((tree, tree, basic_block));
@@ -99,16 +97,14 @@ void
 tree_find_basic_blocks (t)
      tree t;
 {
-  cfg_dump_file = dump_begin (TDI_cfg, &cfg_dump_flags);
-  dot_dump_file = dump_begin (TDI_dot, &dot_dump_flags);
-
-  /* Flush out existing data.  */
-  delete_cfg ();
-
   /* Initialize the basic block array.  */
   n_basic_blocks = 0;
   VARRAY_BB_INIT (basic_block_info, initial_cfg_capacity, "basic_block_info");
 
+  /* Create annotations for ENTRY_BLOCK_PTR and EXIT_BLOCK_PTR.  */
+  create_bb_ann (ENTRY_BLOCK_PTR);
+  create_bb_ann (EXIT_BLOCK_PTR);
+
   /* Initialize the stack of binding scopes.  */
   VARRAY_BB_INIT (binding_stack, 5, "binding_stack");
 
@@ -124,19 +120,21 @@ tree_find_basic_blocks (t)
       make_edges ();
 
       /* Write the flowgraph to a GraphViz file.  */
-      if (dot_dump_file)
-	tree_cfg2dot (dot_dump_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.  */
-      if (cfg_dump_file)
-	tree_dump_cfg (cfg_dump_file);
+      dump_file = dump_begin (TDI_cfg, &dump_flags);
+      if (dump_file)
+	{
+	  tree_dump_cfg (dump_file);
+	  dump_end (TDI_cfg, dump_file);
+	}
     }
-
-  if (dot_dump_file)
-    dump_end (TDI_dot, dot_dump_file);
-
-  if (cfg_dump_file)
-    dump_end (TDI_cfg, cfg_dump_file);
 }
 
 /* }}} */
@@ -270,14 +268,17 @@ make_for_stmt_blocks (t, control_parent,
   bb = create_maximal_bb (FOR_INIT_STMT (t), entry, compound_stmt,
                           &(FOR_INIT_STMT (t)));
   bb->flags |= BB_CONTROL_EXPR;
+  FOR_INIT_STMT_BB (entry) = bb;
 
   bb = create_maximal_bb (cond, entry, compound_stmt, &(FOR_COND (t)));
   bb->flags |= BB_CONTROL_EXPR;
+  FOR_COND_BB (entry) = bb;
 
+  make_blocks (FOR_BODY (t), entry, compound_stmt, &(FOR_BODY (t)));
+
   bb = create_maximal_bb (expr, entry, compound_stmt, &(FOR_EXPR (t)));
   bb->flags |= BB_CONTROL_EXPR;
-
-  make_blocks (FOR_BODY (t), entry, compound_stmt, &(FOR_BODY (t)));
+  FOR_EXPR_BB (entry) = bb;
 }
 
 /* }}} */
@@ -293,15 +294,18 @@ make_while_stmt_blocks (t, control_paren
      tree compound_stmt;
      tree *prev_chain_p;
 {
-  basic_block bb = create_bb (t, t, control_parent, prev_chain_p);
-  bb->flags |= BB_CONTROL_ENTRY | BB_CONTROL_EXPR;
+  basic_block bb, entry;
   
+  entry = create_bb (t, t, control_parent, prev_chain_p);
+  entry->flags |= BB_CONTROL_ENTRY | BB_CONTROL_EXPR;
+  
+  make_blocks (WHILE_BODY (t), entry, compound_stmt, &(WHILE_BODY (t)));
+
   /* END_WHILE block.  Needed to avoid multiple back edges that would
      result in multiple natural loops instead of just one.  */
-  bb = create_maximal_bb (build_int_2 (1, 0), bb, compound_stmt, NULL);
+  bb = create_maximal_bb (build_int_2 (1, 0), entry, compound_stmt, NULL);
   bb->flags |= BB_CONTROL_ENTRY;
-
-  make_blocks (WHILE_BODY (t), bb, compound_stmt, &(WHILE_BODY (t)));
+  END_WHILE_BB (entry) = bb;
 }
 
 /* }}} */
@@ -317,13 +321,16 @@ make_do_stmt_blocks (t, control_parent, 
      tree compound_stmt;
      tree *prev_chain_p;
 {
-  basic_block bb = create_bb (t, t, control_parent, prev_chain_p);
-  bb->flags |= BB_CONTROL_ENTRY;
+  basic_block bb, entry;
+  
+  entry = create_bb (t, t, control_parent, prev_chain_p);
+  entry->flags |= BB_CONTROL_ENTRY;
 
-  bb = create_maximal_bb (DO_COND (t), bb, compound_stmt, &(DO_COND (t)));
-  bb->flags |= BB_CONTROL_EXPR;
+  make_blocks (DO_BODY (t), entry, compound_stmt, &(DO_BODY (t)));
 
-  make_blocks (DO_BODY (t), bb, compound_stmt, &(DO_BODY (t)));
+  bb = create_maximal_bb (DO_COND (t), entry, compound_stmt, &(DO_COND (t)));
+  bb->flags |= BB_CONTROL_EXPR;
+  DO_COND_BB (entry) = bb;
 }
 
 /* }}} */
@@ -458,10 +465,23 @@ create_bb (head, end, control_parent, pr
   bb->head_tree = head;
   bb->end_tree = end;
   bb->index = n_basic_blocks;
-  get_bb_ann (bb)->parent = control_parent;
-  get_bb_ann (bb)->prev_chain_p = prev_chain_p;
-  get_bb_ann (bb)->binding_scope = VARRAY_TOP_BB (binding_stack);
 
+  /* Create annotations for the block.  */
+  create_bb_ann (bb);
+  BB_PARENT (bb) = control_parent;
+  BB_PREV_CHAIN_P (bb) = prev_chain_p;
+  BB_BINDING_SCOPE (bb) = VARRAY_TOP_BB (binding_stack);
+
+  if (is_loop_stmt (head))
+    {
+      union header_blocks *hdr;
+      hdr = (union header_blocks *) ggc_alloc (sizeof (union header_blocks));
+      memset (hdr, 0, sizeof (union header_blocks));
+      BB_LOOP_HDR (bb) = hdr;
+    }
+  else
+    BB_LOOP_HDR (bb) = NULL;
+
   /* 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);
@@ -535,6 +555,56 @@ create_bb_ann (bb)
 
 /* }}} */
 
+/* {{{ remove_bb_ann()
+
+   Remove the annotation from block BB.  */
+
+static void
+remove_bb_ann (bb)
+     basic_block bb;
+{
+  bb_ann ann = BB_ANN (bb);
+  if (ann)
+    {
+      ann->parent = NULL;
+      /* There is no need to delete the arrays in each of the reference.
+	 That is done by delete_ssa().  */
+      VARRAY_FREE (ann->refs);
+    }
+  bb->aux = NULL;
+}
+
+/* }}} */
+
+/* {{{ tree_split_bb()
+
+   Splits basic block BB at statement T.  A new basic block is created
+   starting with the statement following T.  If T is already the last
+   statement in the block, nothing is done.
+
+   Returns the newly created basic block or NULL if no splitting is
+   necessary.  */
+
+basic_block
+tree_split_bb (bb, t)
+     basic_block bb;
+     tree t;
+{
+  basic_block new_bb;
+
+  /* If T is already BB's last statement, nothing needs to be done.  */
+  if (t == bb->end_tree)
+    return NULL;
+  
+  new_bb = create_maximal_bb (TREE_CHAIN (t), BB_PARENT (bb),
+                              TREE_COMPOUND_STMT (t), &(TREE_CHAIN (t)));
+  bb->end_tree = t;
+
+  return new_bb;
+}
+
+/* }}} */
+
 
 /* Create edges.  */
 
@@ -546,12 +616,8 @@ static void
 make_edges ()
 {
   int i;
-  sbitmap *edge_cache;
-
-  edge_cache = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
-  sbitmap_vector_zero (edge_cache, n_basic_blocks);
 
-  make_edge (edge_cache, ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU);
+  make_edge (ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU);
 
   /* Traverse basic block array placing edges.  */
   for (i = 0; i < n_basic_blocks; i++)
@@ -560,17 +626,17 @@ make_edges ()
 
       /* Edges for control statements.  */
       if (is_ctrl_stmt (bb->head_tree))
-	make_ctrl_stmt_edges (edge_cache, bb);
+	make_ctrl_stmt_edges (bb);
 
       /* Edges for statement expressions.  */
       if (is_statement_expression (bb->head_tree))
-	make_edge (edge_cache, bb, BASIC_BLOCK (i + 1), 0);
+	make_edge (bb, BASIC_BLOCK (i + 1), 0);
 
       /* Edges for control flow altering statements (goto, break,
          continue, return) need an edge to the corresponding target
          block.  */
       if (is_ctrl_altering_stmt (bb->end_tree))
-	make_exit_edges (edge_cache, bb);
+	make_exit_edges (bb);
 
       /* Incoming edges for label blocks in switch statements.  It's easier
          to deal with these bottom-up than top-down.  */
@@ -585,26 +651,35 @@ make_edges ()
 	      return;
 	    }
 
-	  /* If the preceding block begins a new scope, make the edge to
-	     that block instead.  */
-	  if (bb->pred && bb->pred->src && bb->pred->src->head_tree
-	      && TREE_CODE (bb->pred->src->head_tree) == SCOPE_STMT)
-	    make_edge (edge_cache, switch_bb, bb->pred->src, 0);
-	  else
-	    make_edge (edge_cache, switch_bb, bb, 0);
+	  make_edge (switch_bb, bb, 0);
+
+	  /* If this label is the default label, we need to remove the
+	     fallthru edge that was created when we processed the entry
+	     block for the switch() statement.  */
+	  if (CASE_LOW (bb->head_tree) == NULL)
+	    {
+	      edge e;
+	      basic_block entry_bb, chain_bb;
+
+	      entry_bb = BB_PARENT (bb);
+	      chain_bb = successor_block (entry_bb);
+	      for (e = entry_bb->succ; e; e = e->succ_next)
+		if (e->dest == chain_bb)
+		  {
+		    remove_edge (e);
+		    break;
+		  }
+	    }
 	}
 
       /* Finally, if no edges were created above, this is a regular
          basic block that only needs a fallthru edge.  */
       if (bb->succ == NULL)
-	make_edge (edge_cache, bb, successor_block (bb), EDGE_FALLTHRU);
+	make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
     }
 
   /* Clean up the graph and warn for unreachable code.  */
-  delete_unreachable_blocks ();
-
-  if (edge_cache)
-    sbitmap_vector_free (edge_cache);
+  tree_cleanup_cfg ();
 }
 
 /* }}} */
@@ -614,26 +689,25 @@ make_edges ()
    Create edges for control statement at basic block BB.  */
 
 static void
-make_ctrl_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_ctrl_stmt_edges (bb)
      basic_block bb;
 {
   switch (TREE_CODE (bb->head_tree))
     {
     case FOR_STMT:
-      make_for_stmt_edges (edge_cache, bb);
+      make_for_stmt_edges (bb);
       break;
 
     case WHILE_STMT:
-      make_while_stmt_edges (edge_cache, bb);
+      make_while_stmt_edges (bb);
       break;
 
     case DO_STMT:
-      make_do_stmt_edges (edge_cache, bb);
+      make_do_stmt_edges (bb);
       break;
 
     case IF_STMT:
-      make_if_stmt_edges (edge_cache, bb);
+      make_if_stmt_edges (bb);
       break;
 
     case SWITCH_STMT:
@@ -651,29 +725,29 @@ make_ctrl_stmt_edges (edge_cache, bb)
 /* {{{ make_exit_edges()
 
    Create exit edges for statements that alter the flow of control
-   (BREAK, CONTINUE, GOTO, RETURN).  */
+   (BREAK, CONTINUE, GOTO, RETURN and calls to non-returning functions).  */
 
 static void
-make_exit_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_exit_edges (bb)
      basic_block bb;
 {
   switch (TREE_CODE (bb->end_tree))
     {
     case BREAK_STMT:
-      make_break_stmt_edges (edge_cache, bb);
+      make_break_stmt_edges (bb);
       break;
 
     case CONTINUE_STMT:
-      make_continue_stmt_edges (edge_cache, bb);
+      make_continue_stmt_edges (bb);
       break;
 
     case GOTO_STMT:
-      make_goto_stmt_edges (edge_cache, bb);
+      make_goto_stmt_edges (bb);
       break;
 
+    case EXPR_STMT:
     case RETURN_STMT:
-      make_return_stmt_edges (edge_cache, bb);
+      make_edge (bb, EXIT_BLOCK_PTR, 0);
       break;
 
     default:
@@ -688,12 +762,12 @@ make_exit_edges (edge_cache, bb)
    Create edges for a FOR_STMT structure that starts at basic block BB.  */
 
 static void
-make_for_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_for_stmt_edges (bb)
      basic_block bb;
 {
   tree body_t, entry = bb->head_tree;
   basic_block init_bb, cond_bb, expr_bb, body_bb;
+  int infinite_loop, zero_iter_loop;
 
   if (TREE_CODE (entry) != FOR_STMT)
     abort ();
@@ -733,11 +807,31 @@ make_for_stmt_edges (edge_cache, bb)
   body_t = first_exec_stmt (FOR_BODY (entry));
   body_bb = (body_t) ? BB_FOR_STMT (body_t) : expr_bb;
 
-  make_edge (edge_cache, bb, init_bb, 0);
-  make_edge (edge_cache, init_bb, cond_bb, 0);
-  make_edge (edge_cache, cond_bb, body_bb, 0);
-  make_edge (edge_cache, expr_bb, cond_bb, 0);
-  make_edge (edge_cache, cond_bb, successor_block (bb), 0);
+  make_edge (bb, init_bb, 0);
+  make_edge (init_bb, cond_bb, 0);
+
+  /* Simplify the loop if the condition can be statically computed:
+
+     - For infinite loops, do not make an edge between the condition node
+       and the first block outside the loop.
+
+     - For zero-iteration loops, do not make an edge into the first block
+       of the body nor make a back edge from the latch block.  */
+
+  infinite_loop = (FOR_COND (entry) == NULL
+                   || (TREE_CODE (FOR_COND (entry)) == INTEGER_CST
+		       && FOR_COND (entry) != integer_zero_node));
+
+  zero_iter_loop = (FOR_COND (entry) == integer_zero_node);
+
+  if (!zero_iter_loop)
+    {
+      make_edge (cond_bb, body_bb, 0);
+      make_edge (expr_bb, cond_bb, 0);
+    }
+
+  if (!infinite_loop)
+    make_edge (cond_bb, successor_block (bb), 0);
 }
 
 /* }}} */
@@ -747,12 +841,12 @@ make_for_stmt_edges (edge_cache, bb)
    Create the edges for a WHILE_STMT structure starting with bb.  */
 
 static void
-make_while_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_while_stmt_edges (bb)
      basic_block bb;
 {
   tree body_t, entry = bb->head_tree;
-  basic_block end_bb, body_bb, exit_bb;
+  basic_block end_bb, body_bb;
+  int infinite_loop, zero_iter_loop;
 
   if (TREE_CODE (entry) != WHILE_STMT)
     abort ();
@@ -773,16 +867,32 @@ make_while_stmt_edges (edge_cache, bb)
           
      If the body doesn't exist, we use the header instead.  */
 
-  /* Basic blocks for each component.  Note that the block numbers are
-     determined by make_while_stmt_blocks().  */
-  exit_bb = successor_block (bb);
+  /* Basic blocks for each component.  */
   end_bb = latch_block (bb);
   body_t = first_exec_stmt (WHILE_BODY (entry));
   body_bb = (body_t) ? BB_FOR_STMT (body_t) : end_bb;
 
-  make_edge (edge_cache, bb, body_bb, 0);
-  make_edge (edge_cache, end_bb, bb, 0);
-  make_edge (edge_cache, bb, exit_bb, 0);
+  /* Simplify the loop if the condition can be statically computed:
+
+     - For infinite loops, do not make an edge between the entry node and
+       the first block outside the loop.
+
+     - For zero-iteration loops, do not make an edge into the first block
+       of the body nor make a back edge from the latch block.  */
+
+  infinite_loop = (TREE_CODE (WHILE_COND (entry)) == INTEGER_CST
+                   && WHILE_COND (entry) != integer_zero_node);
+
+  zero_iter_loop = (WHILE_COND (entry) == integer_zero_node);
+
+  if (!zero_iter_loop)
+    {
+      make_edge (bb, body_bb, 0);
+      make_edge (end_bb, bb, 0);
+    }
+
+  if (!infinite_loop)
+    make_edge (bb, successor_block (bb), 0);
 }
 
 /* }}} */
@@ -792,12 +902,12 @@ make_while_stmt_edges (edge_cache, bb)
    Create the edges for a DO_STMT structure starting with bb.  */
 
 static void
-make_do_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_do_stmt_edges (bb)
      basic_block bb;
 {
   tree body_t, entry = bb->head_tree;
   basic_block cond_bb, body_bb;
+  int infinite_loop, one_iter_loop;
 
   if (TREE_CODE (entry) != DO_STMT)
     abort ();
@@ -818,15 +928,31 @@ make_do_stmt_edges (edge_cache, bb)
 
      If the body doesn't exist, we use the condition instead.  */
 
-  /* Basic blocks for each component. Note that the block numbers are
-     determined by make_do_stmt_blocks().  */
+  /* Basic blocks for each component.  */
   cond_bb = latch_block (bb);
   body_t = first_exec_stmt (DO_BODY (entry));
   body_bb = (body_t) ? BB_FOR_STMT (body_t) : cond_bb;
 
-  make_edge (edge_cache, bb, body_bb, 0);
-  make_edge (edge_cache, cond_bb, body_bb, 0);
-  make_edge (edge_cache, cond_bb, successor_block (bb), 0);
+  make_edge (bb, body_bb, 0);
+
+  /* Simplify the loop if the condition can be statically computed:
+
+     - For infinite loops, do not make an edge between the conditional
+       block and the first block outside the loop.
+
+     - For one-iteration loops (i.e., 'do {} while (0);'), do not make a
+       back edge to the beginning of the loop.  */
+
+  infinite_loop = (TREE_CODE (DO_COND (entry)) == INTEGER_CST
+                   && DO_COND (entry) != integer_zero_node);
+
+  one_iter_loop = (DO_COND (entry) == integer_zero_node);
+
+  if (!one_iter_loop)
+    make_edge (cond_bb, body_bb, 0);
+
+  if (!infinite_loop)
+    make_edge (cond_bb, successor_block (bb), 0);
 }
 
 /* }}} */
@@ -836,13 +962,13 @@ make_do_stmt_edges (edge_cache, bb)
    Create the edges for an IF_STMT structure starting with BB.  */
 
 static void
-make_if_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_if_stmt_edges (bb)
      basic_block bb;
 {
   tree entry = bb->head_tree;
-  basic_block then_bb, else_bb;
+  basic_block successor_bb, then_bb, else_bb;
   tree then_t, else_t;
+  int always_true, always_false;
 
   if (TREE_CODE (entry) != IF_STMT)
     abort ();
@@ -854,6 +980,8 @@ make_if_stmt_edges (edge_cache, bb)
   else_t = first_exec_stmt (ELSE_CLAUSE (entry));
   else_bb = (else_t) ? BB_FOR_STMT (else_t) : NULL;
 
+  successor_bb = successor_block (bb);
+
   /* Create the following edges.
 
 	      IF_STMT
@@ -861,18 +989,31 @@ make_if_stmt_edges (edge_cache, bb)
 	       /   \
 	    THEN   ELSE
 
-     Either clause may be empty.  */
+     Either clause may be empty.  Linearize the IF statement if the
+     conditional can be statically computed.  */
 
+  always_true = (TREE_CODE (IF_COND (entry)) == INTEGER_CST
+                 && IF_COND (entry) != integer_zero_node);
+
+  always_false = (IF_COND (entry) == integer_zero_node);
+
+  if (always_true)
+    else_bb = NULL;
+
+  if (always_false)
+    then_bb = NULL;
+
   if (then_bb)
-    make_edge (edge_cache, bb, then_bb, 0);
+    make_edge (bb, then_bb, 0);
 
   if (else_bb)
-    make_edge (edge_cache, bb, else_bb, 0);
+    make_edge (bb, else_bb, 0);
 
-  /* We only need an edge to BB's successor block if one of the clauses is
-     missing.  */
-  if (then_bb == NULL || else_bb == NULL)
-    make_edge (edge_cache, bb, successor_block (bb), 0);
+  /* If the conditional cannot be statically computed and the IF is missing
+     one of the clauses, make an edge between the entry block and the
+     first block outside the IF.  */
+  if (!always_true && !always_false && (!then_bb || !else_bb))
+    make_edge (bb, successor_bb, 0);
 }
 
 /* }}} */
@@ -882,8 +1023,7 @@ make_if_stmt_edges (edge_cache, bb)
    Create edges for a goto statement.  */
 
 static void
-make_goto_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_goto_stmt_edges (bb)
      basic_block bb;
 {
   tree goto_t, dest;
@@ -909,14 +1049,14 @@ make_goto_stmt_edges (edge_cache, bb)
 	  && TREE_CODE (target) == LABEL_STMT
 	  && LABEL_STMT_LABEL (target) == dest)
 	{
-	  make_edge (edge_cache, bb, target_bb, 0);
+	  make_edge (bb, target_bb, 0);
 	  break;
 	}
 
       /* Computed GOTOs.  Make an edge to every label block.  */
       else if (TREE_CODE (dest) != LABEL_DECL
 	       && TREE_CODE (target) == LABEL_STMT)
-	make_edge (edge_cache, bb, target_bb, 0);
+	make_edge (bb, target_bb, 0);
     }
 }
 
@@ -928,8 +1068,7 @@ make_goto_stmt_edges (edge_cache, bb)
    block for the break statement's control parent.  */
 
 static void
-make_break_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_break_stmt_edges (bb)
      basic_block bb;
 {
   tree break_t;
@@ -951,7 +1090,7 @@ make_break_stmt_edges (edge_cache, bb)
       return;
     }
 
-  make_edge (edge_cache, bb, successor_block (control_parent), 0);
+  make_edge (bb, successor_block (control_parent), 0);
 }
 
 /* }}} */
@@ -962,8 +1101,7 @@ make_break_stmt_edges (edge_cache, bb)
    control parent's expression block.  */
 
 static void
-make_continue_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
+make_continue_stmt_edges (bb)
      basic_block bb;
 {
   tree continue_t;
@@ -983,33 +1121,26 @@ make_continue_stmt_edges (edge_cache, bb
       return;
     }
 
-  make_edge (edge_cache, bb, latch_block (loop_bb), 0);
+  make_edge (bb, latch_block (loop_bb), 0);
 }
 
 /* }}} */
 
-/* {{{ make_return_stmt_edges()
 
-   Create an edge from the RETURN block to EXIT_BLOCK_PTR.  */
+/* Flowgraph analysis.  */
 
-static void
-make_return_stmt_edges (edge_cache, bb)
-     sbitmap *edge_cache;
-     basic_block bb;
-{
-  tree return_t = bb->end_tree;
+/* {{{ tree_cleanup_cfg()
 
-  if (return_t == NULL || TREE_CODE (return_t) != RETURN_STMT)
-    abort ();
+   Remove unreachable blocks and other miscellaneous clean up work.  */
 
-  make_edge (edge_cache, bb, EXIT_BLOCK_PTR, 0);
+void
+tree_cleanup_cfg ()
+{
+  delete_unreachable_blocks ();
 }
 
 /* }}} */
 
-
-/* Flowgraph analysis.  */
-
 /* {{{ delete_unreachable_blocks()
    
    Delete all unreachable basic blocks.   */
@@ -1037,27 +1168,21 @@ delete_unreachable_blocks ()
 
 /* {{{ delete_bb()
 
-   Remove a block from the flowgraph.  Emit a warning if -Wunreachable-code
-   is set.  */
+   Remove a block from the flowgraph.  */
 
 static void
 delete_bb (bb)
      basic_block bb;
 {
-  edge e, next, *q;
   tree t;
 
-  if (warn_notreached)
+  dump_file = dump_begin (TDI_cfg, &dump_flags);
+  if (dump_file)
     {
-      tree stmt;
-
-      if (statement_code_p (TREE_CODE (bb->head_tree)))
-	stmt = bb->head_tree;
-      else
-	stmt = BB_PARENT (bb)->head_tree;
-
-      prep_stmt (stmt);
-      warning ("unreachable statement");
+      fprintf (dump_file, "Removed unreachable basic block %d\n", bb->index);
+      tree_dump_bb (dump_file, "", bb, 0);
+      fprintf (dump_file, "\n");
+      dump_end (TDI_cfg, dump_file);
     }
 
   /* Unmap all the instructions in the block.  */
@@ -1070,27 +1195,12 @@ delete_bb (bb)
       t = TREE_CHAIN (t);
     }
 
-  /* Remove the edges into and out of this block.  Note that there
-     may indeed be edges in, if we are removing an unreachable loop.  */
-  for (e = bb->pred; e; e = next)
-    {
-      for (q = &e->src->succ; *q != e; q = &(*q)->succ_next)
-	continue;
-      *q = e->succ_next;
-      next = e->pred_next;
-      n_edges--;
-      free (e);
-    }
+  /* Remove the edges into and out of this block.  */
+  while (bb->pred != NULL)
+    remove_edge (bb->pred);
 
-  for (e = bb->succ; e; e = next)
-    {
-      for (q = &e->dest->pred; *q != e; q = &(*q)->pred_next)
-	continue;
-      *q = e->pred_next;
-      next = e->succ_next;
-      n_edges--;
-      free (e);
-    }
+  while (bb->succ != NULL)
+    remove_edge (bb->succ);
 
   bb->pred = NULL;
   bb->succ = NULL;
@@ -1262,9 +1372,25 @@ is_ctrl_altering_stmt (t)
   if (t == NULL)
     abort ();
 
-  return (TREE_CODE (t) == GOTO_STMT
-	  || TREE_CODE (t) == CONTINUE_STMT
-	  || TREE_CODE (t) == BREAK_STMT || TREE_CODE (t) == RETURN_STMT);
+  if (TREE_CODE (t) == GOTO_STMT || TREE_CODE (t) == CONTINUE_STMT
+      || TREE_CODE (t) == BREAK_STMT || TREE_CODE (t) == RETURN_STMT)
+    return 1;
+
+  /* Calls to non-returning functions also alter the flow of control.  */
+  if (TREE_CODE (t) == EXPR_STMT
+      && EXPR_STMT_EXPR (t)
+      && TREE_CODE (EXPR_STMT_EXPR (t)) == CALL_EXPR)
+    {
+      tree call_expr = EXPR_STMT_EXPR (t);
+      tree addr = TREE_OPERAND (call_expr, 0);
+      tree decl = (TREE_CODE (addr) == ADDR_EXPR) 
+	          ? TREE_OPERAND (addr, 0) 
+		  : addr;
+      if (TREE_THIS_VOLATILE (decl))
+	return 1;
+    }
+
+  return 0;
 }
 
 /* }}} */
@@ -1399,18 +1525,13 @@ delete_cfg ()
   if (basic_block_info == NULL)
     return;
 
-  clear_edges ();
-
   for (i = 0; i < n_basic_blocks; i++)
-    {
-      bb_ann ann = BB_ANN (BASIC_BLOCK (i));
-      ann->parent = NULL;
-      /* There is no need to delete the arrays in each of the reference.
-	 That is done by delete_ssa().  */
-      VARRAY_FREE (ann->refs);
-      BASIC_BLOCK (i)->aux = NULL;
-    }
+    remove_bb_ann (BASIC_BLOCK (i));
 
+  remove_bb_ann (ENTRY_BLOCK_PTR);
+  remove_bb_ann (EXIT_BLOCK_PTR);
+
+  clear_edges ();
   VARRAY_FREE (basic_block_info);
 }
 
@@ -1449,7 +1570,7 @@ latch_block (loop_bb)
   if (code == FOR_STMT)
     return FOR_EXPR_BB (loop_bb);
   else if (code == WHILE_STMT)
-    return WHILE_COND_BB (loop_bb);
+    return END_WHILE_BB (loop_bb);
   else if (code == DO_STMT)
     return DO_COND_BB (loop_bb);
   else
@@ -1660,7 +1781,7 @@ insert_stmt_tree_before (stmt, where, bb
   if (! statement_code_p (TREE_CODE (stmt)) || TREE_CHAIN (stmt))
     abort ();
 
-  cfg_dump_file = dump_begin (TDI_cfg, &cfg_dump_flags);
+  dump_file = dump_begin (TDI_cfg, &dump_flags);
 
   /* If the basic block contains a control flow expression, we may need
      to do other insertions.  */
@@ -1669,8 +1790,8 @@ insert_stmt_tree_before (stmt, where, bb
   else
     insert_before_normal_stmt (stmt, where, bb);
 
-  if (cfg_dump_file)
-    dump_end (TDI_cfg, cfg_dump_file);
+  if (dump_file)
+    dump_end (TDI_cfg, dump_file);
 }
 
 /* }}} */
@@ -1694,14 +1815,14 @@ insert_before_ctrl_stmt (stmt, where, bb
   parent_bb = (bb->flags & BB_CONTROL_ENTRY) ? bb : BB_PARENT (bb);
   parent = parent_bb->head_tree;
 
-  if (cfg_dump_file)
+  if (dump_file)
     {
-      fprintf (cfg_dump_file, "\nAbout to insert statement: ");
-      print_node_brief (cfg_dump_file, "", stmt, 0);
-      fprintf (cfg_dump_file, "\nBefore statement: ");
-      print_node_brief (cfg_dump_file, "", parent, 0);
-      fprintf (cfg_dump_file, " (line %d)\n", STMT_LINENO (parent));
-      fprintf (cfg_dump_file, "At basic block %d\n", bb->index);
+      fprintf (dump_file, "\nAbout to insert statement: ");
+      print_node_brief (dump_file, "", stmt, 0);
+      fprintf (dump_file, "\nBefore statement: ");
+      print_node_brief (dump_file, "", parent, 0);
+      fprintf (dump_file, " (line %d)\n", STMT_LINENO (parent));
+      fprintf (dump_file, "At basic block %d\n", bb->index);
     }
 
   /* If this is not a loop, do a normal insertion before the control
@@ -1813,14 +1934,14 @@ insert_before_normal_stmt (stmt, where, 
       TREE_CHAIN (stmt) = where;
       map_stmt_to_bb (stmt, bb);
 
-      if (cfg_dump_file)
+      if (dump_file)
 	{
-	  fprintf (cfg_dump_file, "\nInserted statement: ");
-	  print_node_brief (cfg_dump_file, "", stmt, 0);
-	  fprintf (cfg_dump_file, "\nBefore statement  : ");
-	  print_node_brief (cfg_dump_file, "", where, 0);
-	  fprintf (cfg_dump_file, " (line %d)\n", STMT_LINENO (where));
-	  fprintf (cfg_dump_file, "At basic block %d\n", bb->index);
+	  fprintf (dump_file, "\nInserted statement: ");
+	  print_node_brief (dump_file, "", stmt, 0);
+	  fprintf (dump_file, "\nBefore statement  : ");
+	  print_node_brief (dump_file, "", where, 0);
+	  fprintf (dump_file, " (line %d)\n", STMT_LINENO (where));
+	  fprintf (dump_file, "At basic block %d\n", bb->index);
 	}
     }
 
@@ -1845,18 +1966,18 @@ insert_before_normal_stmt (stmt, where, 
 	  bb->head_tree = stmt;
 	}
 
-      if (cfg_dump_file)
+      if (dump_file)
 	{
-	  fprintf (cfg_dump_file, "\nInserted statement: ");
-	  print_node_brief (cfg_dump_file, "", stmt, 0);
-	  fprintf (cfg_dump_file, "\nBefore statement  : ");
-	  print_node_brief (cfg_dump_file, "", where, 0);
-	  fprintf (cfg_dump_file, " (line %d)\n", STMT_LINENO (where));
+	  fprintf (dump_file, "\nInserted statement: ");
+	  print_node_brief (dump_file, "", stmt, 0);
+	  fprintf (dump_file, "\nBefore statement  : ");
+	  print_node_brief (dump_file, "", where, 0);
+	  fprintf (dump_file, " (line %d)\n", STMT_LINENO (where));
 	  if (new_bb)
-	    fprintf (cfg_dump_file, "Created new basic block %d\n",
+	    fprintf (dump_file, "Created new basic block %d\n",
 		     new_bb->index);
 	  else
-	    fprintf (cfg_dump_file, "At basic block %d\n", bb->index);
+	    fprintf (dump_file, "At basic block %d\n", bb->index);
 	}
     }
 }
@@ -1887,15 +2008,15 @@ insert_stmt_tree_after (stmt, where, bb)
   if (! statement_code_p (TREE_CODE (stmt)))
     abort ();
 
-  cfg_dump_file = dump_begin (TDI_cfg, &cfg_dump_flags);
+  dump_file = dump_begin (TDI_cfg, &dump_flags);
 
   if (bb->flags & BB_CONTROL_EXPR)
     insert_after_ctrl_stmt (stmt, bb);
   else
     insert_after_normal_stmt (stmt, where, bb);
 
-  if (cfg_dump_file)
-    dump_end (TDI_cfg, cfg_dump_file);
+  if (dump_file)
+    dump_end (TDI_cfg, dump_file);
 }
 
 /* }}} */
@@ -1919,14 +2040,14 @@ insert_after_ctrl_stmt (stmt, bb)
   parent_bb = (bb->flags & BB_CONTROL_ENTRY) ? bb : BB_PARENT (bb);
   parent = parent_bb->head_tree;
 
-  if (cfg_dump_file)
+  if (dump_file)
     {
-      fprintf (cfg_dump_file, "\nAbout to insert statement: ");
-      print_node_brief (cfg_dump_file, "", stmt, 0);
-      fprintf (cfg_dump_file, "\nAfter statement: ");
-      print_node_brief (cfg_dump_file, "", parent, 0);
-      fprintf (cfg_dump_file, " (line %d)\n", STMT_LINENO (parent));
-      fprintf (cfg_dump_file, "At basic block %d\n", bb->index);
+      fprintf (dump_file, "\nAbout to insert statement: ");
+      print_node_brief (dump_file, "", stmt, 0);
+      fprintf (dump_file, "\nAfter statement: ");
+      print_node_brief (dump_file, "", parent, 0);
+      fprintf (dump_file, " (line %d)\n", STMT_LINENO (parent));
+      fprintf (dump_file, "At basic block %d\n", bb->index);
     }
 
   /* IF_STMT block.  Insert before THEN_CLAUSE and ELSE_CLAUSE.  */
@@ -2061,14 +2182,14 @@ insert_after_normal_stmt (stmt, where, b
   if (where == bb->end_tree)
     bb->end_tree = stmt;
 
-  if (cfg_dump_file)
+  if (dump_file)
     {
-      fprintf (cfg_dump_file, "\nInserted statement: ");
-      print_node_brief (cfg_dump_file, "", stmt, 0);
-      fprintf (cfg_dump_file, "\nAfter statement  : ");
-      print_node_brief (cfg_dump_file, "", where, 0);
-      fprintf (cfg_dump_file, " (line %d)\n", STMT_LINENO (where));
-      fprintf (cfg_dump_file, "At basic block %d\n", bb->index);
+      fprintf (dump_file, "\nInserted statement: ");
+      print_node_brief (dump_file, "", stmt, 0);
+      fprintf (dump_file, "\nAfter statement  : ");
+      print_node_brief (dump_file, "", where, 0);
+      fprintf (dump_file, " (line %d)\n", STMT_LINENO (where));
+      fprintf (dump_file, "At basic block %d\n", bb->index);
     }
 }
 
@@ -2139,44 +2260,44 @@ replace_expr_in_tree (stmt, old_expr, ne
 {
   tree *old_expr_p = find_expr_in_tree (stmt, old_expr);
 
-  cfg_dump_file = dump_begin (TDI_cfg, &cfg_dump_flags);
-  if (cfg_dump_file)
+  dump_file = dump_begin (TDI_cfg, &dump_flags);
+  if (dump_file)
     {
       if (old_expr_p)
 	{
-	  fprintf (cfg_dump_file, "\nRequested expression: ");
-	  print_node_brief (cfg_dump_file, "", old_expr, 0);
+	  fprintf (dump_file, "\nRequested expression: ");
+	  print_node_brief (dump_file, "", old_expr, 0);
 
-	  fprintf (cfg_dump_file, "\nReplaced expression:  ");
-	  print_node_brief (cfg_dump_file, "", *old_expr_p, 0);
+	  fprintf (dump_file, "\nReplaced expression:  ");
+	  print_node_brief (dump_file, "", *old_expr_p, 0);
 
-	  fprintf (cfg_dump_file, "\nWith expression:      ");
-	  print_node_brief (cfg_dump_file, "", new_expr, 0);
+	  fprintf (dump_file, "\nWith expression:      ");
+	  print_node_brief (dump_file, "", new_expr, 0);
 	}
       else
 	{
-	  fprintf (cfg_dump_file, "\nCould not find expression: ");
-	  print_node_brief (cfg_dump_file, "", old_expr, 0);
+	  fprintf (dump_file, "\nCould not find expression: ");
+	  print_node_brief (dump_file, "", old_expr, 0);
 	}
 
-      fprintf (cfg_dump_file, "\nIn statement:        ");
-      print_node_brief (cfg_dump_file, "", stmt, 0);
+      fprintf (dump_file, "\nIn statement:        ");
+      print_node_brief (dump_file, "", stmt, 0);
 
-      fprintf (cfg_dump_file, "\nBasic block:         ");
+      fprintf (dump_file, "\nBasic block:         ");
       if (statement_code_p (TREE_CODE (stmt)))
-	fprintf (cfg_dump_file, "%d", BB_FOR_STMT (stmt)->index);
+	fprintf (dump_file, "%d", BB_FOR_STMT (stmt)->index);
       else
-	fprintf (cfg_dump_file, "-1");
+	fprintf (dump_file, "-1");
 
-      fprintf (cfg_dump_file, "\nLine:                ");
+      fprintf (dump_file, "\nLine:                ");
       if (statement_code_p (TREE_CODE (stmt)))
-	fprintf (cfg_dump_file, "%d", STMT_LINENO (stmt));
+	fprintf (dump_file, "%d", STMT_LINENO (stmt));
       else
-	fprintf (cfg_dump_file, "-1");
+	fprintf (dump_file, "-1");
 
-      fprintf (cfg_dump_file, "\n");
+      fprintf (dump_file, "\n");
 
-      dump_end (TDI_cfg, cfg_dump_file);
+      dump_end (TDI_cfg, dump_file);
     }
 
   if (old_expr_p)
@@ -2281,7 +2402,7 @@ insert_bb_before (new_bb, bb)
     redirect_edge_succ (e, new_bb);
 
   /* Create the edge NEW_BB -> BB.  */
-  make_edge (NULL, new_bb, bb, 0);
+  make_edge (new_bb, bb, 0);
 }
 
 /* }}} */
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.2.8
diff -d -p -d -u -p -r1.1.2.8 tree-dfa.c
--- tree-dfa.c	2001/09/30 06:24:06	1.1.2.8
+++ tree-dfa.c	2001/10/14 23:28:37
@@ -55,7 +55,6 @@ static void add_ref_symbol PARAMS ((tree
 varray_type referenced_symbols;
 
 
-
 /* Find variable references in the code.  */
 
 /* {{{ tree_find_varrefs()
@@ -74,16 +73,17 @@ tree_find_varrefs ()
 
       while (t)
 	{
-	  /* The only non-statements that we can have in a block are the
-	     expressions in control header blocks (FOR_COND, DO_COND, etc).
-	     Those are handled when we process the associated control
-	     statement.  */
 	  if (statement_code_p (TREE_CODE (t)))
 	    {
 	      find_refs_in_stmt (t, bb);
 	      if (t == bb->end_tree || is_ctrl_stmt (t))
 		break;
 	    }
+	  else
+	    {
+	      tree parent = BB_PARENT (bb)->head_tree;
+	      find_refs_in_expr (t, VARUSE, bb, parent, t);
+	    }
 
 	  t = TREE_CHAIN (t);
 	}
@@ -136,24 +136,24 @@ find_refs_in_stmt (t, bb)
   if (code == EXPR_STMT)
     find_refs_in_expr (EXPR_STMT_EXPR (t), VARUSE, bb, t, t);
 
+  /* The condition nodes for IF_STMT, SWITCH_STMT and WHILE_STMT are not
+     modeled in the flowgraph, so they need to be looked at separately.  */
   else if (code == IF_STMT)
     find_refs_in_expr (IF_COND (t), VARUSE, bb, t, t);
 
   else if (code == SWITCH_STMT)
     find_refs_in_expr (SWITCH_COND (t), VARUSE, bb, t, t);
 
-  else if (code == FOR_STMT)
-    {
-      find_refs_in_stmt (FOR_INIT_STMT (t), bb);
-      find_refs_in_expr (FOR_COND (t), VARUSE, bb, t, t);
-      find_refs_in_expr (FOR_EXPR (t), VARUSE, bb, t, t);
-    }
-
   else if (code == WHILE_STMT)
     find_refs_in_expr (WHILE_COND (t), VARUSE, bb, t, t);
 
+  /* There is no need to check the children nodes for DO_STMTs and
+     FOR_STMTs, because they're in separate basic blocks.  */
+  else if (code == FOR_STMT)
+    ;				/* Nothing to do.  */
+
   else if (code == DO_STMT)
-    find_refs_in_expr (DO_COND (t), VARUSE, bb, t, t);
+    ;				/* Nothing to do.  */
 
   else if (code == ASM_STMT)
     {
@@ -171,7 +171,11 @@ find_refs_in_stmt (t, bb)
   else if (code == DECL_STMT)
     {
       if (TREE_CODE (DECL_STMT_DECL (t)) == VAR_DECL)
-	find_refs_in_expr (DECL_INITIAL (DECL_STMT_DECL (t)), VARDEF, bb, t, t);
+	{
+	  tree decl = DECL_STMT_DECL (t);
+	  if (DECL_INITIAL (decl))
+	    find_refs_in_expr (decl, VARDEF, bb, t, t);
+	}
     }
 
   else if (code == LABEL_STMT)
@@ -215,7 +219,7 @@ find_refs_in_stmt (t, bb)
    Recursively scan the expression tree EXPR looking for variable
    references.
    
-   REF_TYPE indicates what type of reference should be created,
+   REF_TYPE indicates what type of reference should be created.
 
    BB, PARENT_STMT and PARENT_EXPR are the block, statement and expression
       trees containing EXPR.  */
@@ -246,6 +250,24 @@ find_refs_in_expr (expr, ref_type, bb, p
 
   switch (code)
     {
+      /* Structure and union references.  Use the same reference type that
+	 was given by our caller.  */
+    case COMPONENT_REF:
+      find_refs_in_expr (TREE_OPERAND (expr, 0), ref_type, bb, parent_stmt,
+			 expr);
+      find_refs_in_expr (TREE_OPERAND (expr, 1), ref_type, bb, parent_stmt,
+			 expr);
+      break;
+
+      /* Array references.  Use the same reference type for the array, but
+	 default to VARUSE for the index expression.  */
+    case ARRAY_REF:
+      find_refs_in_expr (TREE_OPERAND (expr, 0), ref_type, bb, parent_stmt,
+			 expr);
+      find_refs_in_expr (TREE_OPERAND (expr, 1), VARUSE, bb, parent_stmt,
+			 expr);
+      break;
+
       /* Unary expressions.  */
     case COMPLEX_CST:
     case INTEGER_CST:
@@ -297,7 +319,6 @@ find_refs_in_expr (expr, ref_type, bb, p
 
 
       /* Binary expressions.  */
-    case ARRAY_REF:
     case BIT_AND_EXPR:
     case BIT_ANDTC_EXPR:
     case BIT_IOR_EXPR:
@@ -305,7 +326,6 @@ find_refs_in_expr (expr, ref_type, bb, p
     case CEIL_DIV_EXPR:
     case CEIL_MOD_EXPR:
     case COMPLEX_EXPR:
-    case COMPONENT_REF:
     case COMPOUND_EXPR:
     case COND_EXPR:
     case CONSTRUCTOR:
@@ -362,7 +382,7 @@ find_refs_in_expr (expr, ref_type, bb, p
       /* Ternary operations.  */
     case BIT_FIELD_REF:
     case SAVE_EXPR:
-      find_refs_in_expr (TREE_OPERAND (expr, 0), VARUSE, bb, parent_stmt,
+      find_refs_in_expr (TREE_OPERAND (expr, 0), ref_type, bb, parent_stmt,
 			 expr);
       find_refs_in_expr (TREE_OPERAND (expr, 1), VARUSE, bb, parent_stmt,
 			 expr);
@@ -474,6 +494,20 @@ create_varref (sym, ref_type, bb, parent
 
   /* Add this reference to the list of references for the basic block.  */
   VARRAY_PUSH_GENERIC_PTR (get_bb_ann (bb)->refs, ref);
+
+  /* Make sure that PHI terms are added at the beginning of the list,
+     otherwise FUD chaining will fail to link local uses to the PHI
+     term in this basic block.  */
+  if (ref_type == VARPHI)
+    {
+      varray_type refs = BB_REFS (bb);
+      char *src = refs->data.c;
+      char *dest = refs->data.c + refs->element_size;
+      size_t n = (refs->elements_used - 1) * refs->element_size;
+
+      memmove (dest, src, n);
+      VARRAY_GENERIC_PTR (refs, 0) = ref;
+    }
 
   return ref;
 }
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.2.9
diff -d -p -d -u -p -r1.1.2.9 tree-flow.h
--- tree-flow.h	2001/09/30 06:24:07	1.1.2.9
+++ tree-flow.h	2001/10/14 23:28:37
@@ -167,6 +167,20 @@ typedef struct tree_ann_def *tree_ann;
 
 /* {{{ Block annotations stored in basic_block.aux.  */
 
+struct for_header_blocks
+{
+  basic_block for_init_stmt_bb;
+  basic_block for_cond_bb;
+  basic_block for_expr_bb;
+};
+
+union header_blocks
+{
+  struct for_header_blocks for_hdr;
+  basic_block end_while_bb;
+  basic_block do_cond_bb;
+};
+
 struct bb_ann_def
 {
   /* Control flow parent.  */
@@ -182,40 +196,37 @@ struct bb_ann_def
 
   /* Block that starts the enclosing binding scope for this block.  */
   basic_block binding_scope;
+
+  /* For the entry block of a control structure, header_blocks is a
+     structure containing all the associated header blocks.  */
+  union header_blocks *loop_hdr;
 };
 
 typedef struct bb_ann_def *bb_ann;
-
-#define BB_ANN(BLOCK)			\
-    ((bb_ann)((BLOCK)->aux))
-
-#define BB_PARENT(BLOCK)		\
-    ((BB_ANN (BLOCK)) ? BB_ANN (BLOCK)->parent : NULL)
 
-#define BB_REFS(BLOCK)			\
-    ((BB_ANN (BLOCK)) ? BB_ANN (BLOCK)->refs : NULL)
-
-#define BB_PREV_CHAIN_P(BLOCK)		\
-    ((BB_ANN (BLOCK)) ? BB_ANN (BLOCK)->prev_chain_p : NULL)
-
-#define BB_BINDING_SCOPE(BLOCK)		\
-    ((BB_ANN (BLOCK)) ? BB_ANN (BLOCK)->binding_scope : NULL)
+/* Accessors for basic block annotations.  */
+#define BB_ANN(BLOCK)		((bb_ann)((BLOCK)->aux))
+#define BB_PARENT(BLOCK)	BB_ANN (BLOCK)->parent
+#define BB_REFS(BLOCK)		BB_ANN (BLOCK)->refs
+#define BB_PREV_CHAIN_P(BLOCK)	BB_ANN (BLOCK)->prev_chain_p
+#define BB_BINDING_SCOPE(BLOCK)	BB_ANN (BLOCK)->binding_scope
+#define BB_LOOP_HDR(BLOCK)	BB_ANN (BLOCK)->loop_hdr
 
+/* Accessors for obtaining header blocks of loop statements.  */
+#define FOR_INIT_STMT_BB(BLOCK)	BB_LOOP_HDR (BLOCK)->for_hdr.for_init_stmt_bb
+#define FOR_COND_BB(BLOCK)	BB_LOOP_HDR (BLOCK)->for_hdr.for_cond_bb
+#define FOR_EXPR_BB(BLOCK)	BB_LOOP_HDR (BLOCK)->for_hdr.for_expr_bb
+#define END_WHILE_BB(BLOCK)	BB_LOOP_HDR (BLOCK)->end_while_bb
+#define DO_COND_BB(BLOCK)	BB_LOOP_HDR (BLOCK)->do_cond_bb
 
-/* Accessors for obtaining header blocks of a control statement.  */
-#define FOR_INIT_STMT_BB(BLOCK)		(BASIC_BLOCK ((BLOCK)->index + 1))
-#define FOR_COND_BB(BLOCK)		(BASIC_BLOCK ((BLOCK)->index + 2))
-#define FOR_EXPR_BB(BLOCK)		(BASIC_BLOCK ((BLOCK)->index + 3))
+/* }}} */
 
-#define WHILE_COND_BB(BLOCK)		(BASIC_BLOCK ((BLOCK)->index + 1))
-#define DO_COND_BB(BLOCK)		(BASIC_BLOCK ((BLOCK)->index + 1))
+/* {{{ Global declarations.  */
 
-#define IF_COND_BB(BLOCK)		(BASIC_BLOCK ((BLOCK)->index + 1))
+/* Nonzero to warn about variables used before they are initialized.  */
 
-#define CASE_COND_BB(BLOCK)		(BASIC_BLOCK ((BLOCK)->index + 1))
-/* }}} */
+extern int tree_warn_uninitialized;
 
-/* {{{ Global declarations.  */
 
 /* Array of all symbols referenced in the function.  */
 
@@ -268,6 +279,8 @@ extern void insert_stmt_tree_after PARAM
 extern void replace_expr_in_tree PARAMS ((tree, tree, tree));
 extern tree *find_expr_in_tree PARAMS ((tree, tree));
 extern void insert_bb_before PARAMS ((basic_block, basic_block));
+extern void tree_cleanup_cfg PARAMS ((void));
+extern basic_block tree_split_bb PARAMS ((basic_block, tree));
 
 /* }}} */
 
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-optimize.c,v
retrieving revision 1.1.2.5
diff -d -p -d -u -p -r1.1.2.5 tree-optimize.c
--- tree-optimize.c	2001/10/01 14:40:06	1.1.2.5
+++ tree-optimize.c	2001/10/14 23:28:37
@@ -31,12 +31,16 @@ Boston, MA 02111-1307, USA.  */
 #include "c-common.h"
 #include "diagnostic.h"
 #include "basic-block.h"
+#include "flags.h"
 #include "tree-optimize.h"
 #include "tree-flow.h"
 
+/* Local functions.  */
+static void init_tree_flow PARAMS ((void));
+
 /* {{{ optimize_tree()
 
-   Main entry point to the tree-based optimizer.  */
+   Main entry point to the tree SSA transformation routines.  */
 
 void
 optimize_tree (t)
@@ -46,9 +50,29 @@ optimize_tree (t)
   if (errorcount || sorrycount)
     return;
 
-  /* Flush out existing data.  */
-  VARRAY_TREE_INIT (referenced_symbols, 20, "referenced_symbols");
+  /* Build the SSA representation for the function.  */
+  build_tree_ssa (t);
 
+  /* Flush out flow graph and SSA data.  */
+  delete_cfg ();
+  delete_ssa ();
+  VARRAY_FREE (referenced_symbols);
+}
+
+/* }}} */
+
+/* {{{ build_tree_ssa()
+
+   Main entry point to the tree SSA analysis routines.  */
+
+void
+build_tree_ssa (t)
+     tree t;
+{
+  /* Initialize flow data.  */
+  init_flow ();
+  init_tree_flow ();
+
   tree_find_basic_blocks (t);
 
   if (n_basic_blocks > 0 && ! (errorcount || sorrycount))
@@ -57,11 +81,26 @@ optimize_tree (t)
       tree_build_ssa ();
       tree_compute_rdefs ();
     }
+}
 
-  /* Flush out DFA and SSA data.  */
-  delete_cfg ();
-  delete_ssa ();
-  VARRAY_FREE (referenced_symbols);
+/* }}} */
+
+/* {{{ init_tree_flow()
+
+   Initialize internal data structures and flags for the tree SSA pass.  */
+
+static void
+init_tree_flow ()
+{
+  VARRAY_TREE_INIT (referenced_symbols, 20, "referenced_symbols");
+
+  /* If -Wuninitialized was used, set tree_warn_uninitialized and clear
+     warn_uninitialized to avoid duplicate warnings.  */
+  if (warn_uninitialized == 1)
+    {
+      tree_warn_uninitialized = 1;
+      warn_uninitialized = 0;
+    }
 }
 
 /* }}} */
Index: tree-optimize.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-optimize.h,v
retrieving revision 1.1.2.1
diff -d -p -d -u -p -r1.1.2.1 tree-optimize.h
--- tree-optimize.h	2001/08/27 15:52:13	1.1.2.1
+++ tree-optimize.h	2001/10/14 23:28:37
@@ -25,6 +25,7 @@ Boston, MA 02111-1307, USA.  */
 /* {{{ Function prototypes.  */
 
 void optimize_tree PARAMS ((tree));
+void build_tree_ssa PARAMS ((tree));
 
 /* }}} */
 
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.2.7
diff -d -p -d -u -p -r1.1.2.7 tree-ssa.c
--- tree-ssa.c	2001/09/30 06:24:07	1.1.2.7
+++ tree-ssa.c	2001/10/14 23:28:41
@@ -32,17 +32,24 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "c-common.h"
 #include "diagnostic.h"
-#include "toplev.h"
 #include "tree-optimize.h"
 #include "tree-flow.h"
 #include "ssa.h"
 
+/* Nonzero to warn about variables used before they are initialized.  Used
+   by analyze_rdefs().  */
+
+int tree_warn_uninitialized = 0;
+
 
 /* Dump file and flags.  */
+
 static FILE *dump_file;
 static int dump_flags;
 
+
 /* Local functions.  */
+
 static void insert_phi_terms PARAMS ((sbitmap *));
 static void build_fud_chains PARAMS ((int *));
 static void search_fud_chains PARAMS ((basic_block, int *));
@@ -508,35 +515,69 @@ tree_compute_rdefs ()
 /* {{{ analyze_rdefs()
 
   Analyze reaching definition information and warn about uses of potentially
-  uninitialized variables.  */
+  uninitialized variables if -Wuninitialized was given.  */
 
 void
 analyze_rdefs ()
 {
   size_t i;
-  sbitmap blocks;
 
-  if (warn_uninitialized == 0)
+  if (tree_warn_uninitialized == 0)
     return;
 
-  blocks = sbitmap_alloc (n_basic_blocks);
-  sbitmap_ones (blocks);
-
   for (i = 0; i < NREF_SYMBOLS; i++)
     {
+      size_t j;
       tree sym = REF_SYMBOL (i);
+      varray_type refs = TREE_REFS (sym);
 
-      if (TREE_CODE (sym) == VAR_DECL
-	  && DECL_CONTEXT (sym) != NULL
-	  && ! TREE_STATIC (sym)
-	  && is_upward_exposed (sym, blocks, 0))
+      /* Uninitialized warning messages are only given for local variables
+	 with auto declarations.  */
+      if (TREE_CODE (sym) != VAR_DECL
+	  || DECL_CONTEXT (sym) == NULL
+	  || TREE_STATIC (sym)
+	  || TREE_ADDRESSABLE (sym))
+	continue;
+
+      /* For each use of SYM, if the use is reached by SYM's ghost
+	 definition, then the symbol may have been used uninitialized in
+	 the function.  */
+      for (j = 0; j < VARRAY_ACTIVE_SIZE (refs); j++)
 	{
-	  if (! TREE_ADDRESSABLE (sym))
-	    warning_with_decl (sym,
-		  "`%s' is used uninitialized in this function");
-	  else
-	    warning_with_decl (sym,
-		  "`%s' may be used uninitialized in this function");
+	  size_t k;
+	  int found_ghost;
+	  varray_type rdefs;
+	  varref use = VARRAY_GENERIC_PTR (refs, j);
+
+	  if (VARREF_TYPE (use) != VARUSE)
+	    continue;
+
+	  /* Check all the reaching definitions looking for the ghost
+	     definition.  */
+	  found_ghost = 0;
+	  rdefs = VARUSE_RDEFS (use);
+	  for (k = 0; k < VARRAY_ACTIVE_SIZE (rdefs); k++)
+	    {
+	      varref def = VARRAY_GENERIC_PTR (rdefs, k);
+
+	      if (IS_GHOST_DEF (def))
+		found_ghost = 1;
+	    }
+
+	  /* If we found a ghost definition for SYM, then the reference may
+	     be accessing an uninitialized symbol.  If the ghost def is the
+	     only reaching definition, then the symbol _is_ used
+	     uninitialized.  Otherwise it _may_ be used uninitialized.  */
+	  if (found_ghost)
+	    {
+	      prep_stmt (VARREF_STMT (use));
+	      if (VARRAY_ACTIVE_SIZE (rdefs) == 1)
+		warning ("`%s' is used uninitialized at this point",
+		         IDENTIFIER_POINTER (DECL_NAME (sym)));
+	      else
+		warning ("`%s' may be used uninitialized at this point",
+		         IDENTIFIER_POINTER (DECL_NAME (sym)));
+	    }
 	}
     }
 }


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