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]

Structural CFG analysis code


Hi,
this patch implements structural analysis as sometimes used for
dataflow.  The code just implements algorithm to reduce the CFG, not to
compute the dataflow.  I think for dataflow the DJ-graph based algorithm
would work better (it promises easier updating of the information), but
it implements dumping of the structure :).  So function like:

static void
do_SUBST_INT (int *into, int newval)
{
  struct undo *buf;
  int oldval = *into;

  if (oldval == newval)
    return;

  if (undobuf.frees)
    buf = undobuf.frees, undobuf.frees = buf->next;
  else
    buf = (struct undo *) xmalloc (sizeof (struct undo));

  buf->is_int = 1;
  buf->where.i = into;
  buf->old_contents.i = oldval;
  *into = newval;

  buf->next = undobuf.undos, undobuf.undos = buf;
}

Is dumped as:
{
  if BB #0	 ../../gcc/combine.c:477-481
    {
      if BB #1	 ../../gcc/combine.c:484
        BB #2	 ../../gcc/combine.c:485
      else
        BB #3	 ../../gcc/combine.c:487
      BB #4	 ../../gcc/combine.c:489-494
    }
  BB #5
  return
}

Instead of:

Basic block 0: first insn 64, last 14, prev -1, next 1, loop_depth 0, count 0, freq 0.
Predecessors:  ENTRY (fallthru)
Successors:  1 (fallthru) 5
Registers live at start: (nil)
Registers live at end: (nil)
Invalid sum of outgoing probabilities 0.0%

Basic block 1: first insn 66, last 23, prev 0, next 2, loop_depth 0, count 0, freq 0.
Predecessors:  0 (fallthru)
Successors:  2 (fallthru) 3
Registers live at start: (nil)
Registers live at end: (nil)
Invalid sum of outgoing probabilities 0.0%

Basic block 2: first insn 67, last 30, prev 1, next 3, loop_depth 0, count 0, freq 0.
Predecessors:  1 (fallthru)
Successors:  4
Registers live at start: (nil)
Registers live at end: (nil)
Invalid sum of outgoing probabilities 0.0%

Basic block 3: first insn 32, last 42, prev 2, next 4, loop_depth 0, count 0, freq 0.
Predecessors:  1
Successors:  4 (fallthru)
Registers live at start: (nil)
Registers live at end: (nil)
Invalid sum of outgoing probabilities 0.0%

Basic block 4: first insn 45, last 59, prev 3, next 5, loop_depth 0, count 0, freq 0.
Predecessors:  3 (fallthru) 2
Successors:  5 (fallthru)
Registers live at start: (nil)
Registers live at end: (nil)
Invalid sum of outgoing probabilities 0.0%

Basic block 5: first insn 63, last 70, prev 4, next -2, loop_depth 0, count 0, freq 0.
Predecessors:  4 (fallthru) 0
Successors:  EXIT (fallthru)
Registers live at start: (nil)
Registers live at end: (nil)
Invalid sum of outgoing probabilities 0.0%

That I think is helpfull by itself.  I also home that the code will find
some use later (it can, for instance be used for propagating profile
information that should not run into quadratic side cases when large
loop nest happens, similarly it can do a bit of competition to our
current loop tree code we have).

The code has some internal consistency checks and is able to reduce all
CFGs during GCC bootstrap that I hope is good test.  Pretty printing
needs probably some extra work to be really pretty but even now it is
quite fun :)

Regtested/bootstrapped i386, OK for mainline?

Honza

Sun Jun 15 20:06:28 CEST 2003  Jan Hubicka  <jh@suse.cz>

	* Makefile.in (sa.o): New.
	* toplev.c (rest_of_handle_cfg): Dump flow structure
	* sa.c: New.
	* sa.h: New.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1077
diff -c -3 -p -r1.1077 Makefile.in
*** Makefile.in	10 Jun 2003 00:52:11 -0000	1.1077
--- Makefile.in	15 Jun 2003 18:13:37 -0000
*************** OBJS = alias.o bb-reorder.o bitmap.o bui
*** 817,823 ****
   profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o	   \
   real.o recog.o reg-stack.o regclass.o regmove.o regrename.o		   \
   reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o	   \
!  sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o	   \
   sibcall.o simplify-rtx.o sreal.o ssa.o ssa-ccp.o ssa-dce.o stmt.o	   \
   stor-layout.o stringpool.o timevar.o toplev.o tracer.o tree.o tree-dump.o \
   tree-inline.o unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \
--- 817,823 ----
   profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o	   \
   real.o recog.o reg-stack.o regclass.o regmove.o regrename.o		   \
   reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o	   \
!  sa.o sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o  \
   sibcall.o simplify-rtx.o sreal.o ssa.o ssa-ccp.o ssa-dce.o stmt.o	   \
   stor-layout.o stringpool.o timevar.o toplev.o tracer.o tree.o tree-dump.o \
   tree-inline.o unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \
*************** toplev.o : toplev.c $(CONFIG_H) $(SYSTEM
*** 1489,1495 ****
     graph.h $(LOOP_H) except.h $(REGS_H) $(TIMEVAR_H) $(lang_options_files) \
     ssa.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \
     langhooks.h insn-flags.h options_.h cfglayout.h real.h cfgloop.h \
!    hosthooks.h $(LANGHOOKS_DEF_H) cgraph.h
  	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
  	  -DTARGET_NAME=\"$(target_alias)\" \
  	  -c $(srcdir)/toplev.c $(OUTPUT_OPTION)
--- 1489,1495 ----
     graph.h $(LOOP_H) except.h $(REGS_H) $(TIMEVAR_H) $(lang_options_files) \
     ssa.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \
     langhooks.h insn-flags.h options_.h cfglayout.h real.h cfgloop.h \
!    hosthooks.h $(LANGHOOKS_DEF_H) cgraph.h sa.h
  	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
  	  -DTARGET_NAME=\"$(target_alias)\" \
  	  -c $(srcdir)/toplev.c $(OUTPUT_OPTION)
*************** regmove.o : regmove.c $(CONFIG_H) $(SYST
*** 1738,1743 ****
--- 1738,1745 ----
  haifa-sched.o : haifa-sched.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     sched-int.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
     $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H) $(TARGET_H)
+ sa.o : sa.c sa.h $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
+    $(BASIC_BLOCK_H) hard-reg-set.h coretypes.h $(TM_H)
  sched-deps.o : sched-deps.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     sched-int.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
     $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h cselib.h $(PARAMS_H) $(TM_P_H)
Index: sa.c
===================================================================
RCS file: sa.c
diff -N sa.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- sa.c	15 Jun 2003 18:13:37 -0000
***************
*** 0 ****
--- 1,1133 ----
+ /* The structural control flow graph analysis.
+    Contributed by Jan Hubicka, SuSE Labs.
+    Copyright (C) 2003 Free Software Foundation, Inc.
+ 
+    This file is part of GCC.
+ 
+    GCC is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    GCC is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with GCC; see the file COPYING.  If not, write to the Free
+    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+    02111-1307, USA.  */
+ 
+ /* This pass performs the structural analysis and produces the reduced
+    flowgraph containing single entry-multiple exit nodes. 
+    It is almost identical to the algorithm described by Munick's
+    Advanced Compiler Design and Implementation book.  */
+ 
+ #include "config.h"
+ #include "system.h"
+ #include "coretypes.h"
+ #include "tm.h"
+ #include "alloc-pool.h"
+ #include "basic-block.h"
+ #include "sa.h"
+ #include "toplev.h"
+ #include "rtl.h"	/* We need abort() macro.  */
+ 
+ /* Pool used to allocate lists of improper regions.  */
+ alloc_pool list_pool;
+ /* Dominance info is used to minimize improper regions
+    and is computed lazilly when such region appears.  */
+ static dominance_info dom;
+ 
+ /* Create structural node.  */
+ static struct struct_node *
+ create_node (struct flow_structure *st, enum node_type type)
+ {
+   struct struct_node *n = pool_alloc (st->node_pool);
+   memset (n, 0, sizeof (*n));
+   n->index = st->nnodes++;
+   n->type = type;
+   n->improper_head = NULL;
+   n->improper_nodes = NULL;
+   return n;
+ }
+ 
+ /* Create edge and avoid duplicates.  */
+ 
+ static struct struct_edge *
+ struct_create_edge (struct flow_structure *st, struct struct_node *n1,
+ 		    struct struct_node *n2)
+ {
+   struct struct_edge *e = n1->succ;
+   /* Look if the edge does already exist.  */
+   while (e)
+     {
+       if (e->src == n1 && e->dest == n2)
+ 	return e;
+       e = e->succ_next;
+     }
+   e = pool_alloc (st->edge_pool);
+ 
+   e->src = n1;
+   e->dest = n2;
+   e->pred_prev = NULL;
+   e->succ_prev = NULL;
+   e->pred_next = e->dest->pred;
+   e->succ_next = e->src->succ;
+ 
+   if (n1->succ)
+     n1->succ->succ_prev = e;
+   if (n2->pred)
+     n2->pred->pred_prev = e;
+ 
+   n1->succ = e;
+   n2->pred = e;
+ 
+   return e;
+ }
+ 
+ /* Remove edge.  */
+ static void
+ struct_remove_edge (struct flow_structure *st,
+ 		    struct struct_edge *e)
+ {
+   if (e->pred_prev)
+     e->pred_prev->pred_next = e->pred_next;
+   else if (e->dest->pred != e)
+     abort ();
+   else
+     e->dest->pred = e->pred_next;
+ 
+   if (e->succ_prev)
+     e->succ_prev->succ_next = e->succ_next;
+   else if (e->src->succ != e)
+     abort ();
+   else
+     e->src->succ = e->succ_next;
+ 
+   if (e->pred_next)
+     e->pred_next->pred_prev = e->pred_prev;
+   if (e->succ_next)
+     e->succ_next->succ_prev = e->succ_prev;
+   pool_free (st->edge_pool, e);
+ }
+ 
+ /* Create structural node representing basic block B.
+    b->aux filed is set to point back to the node to simplify manipulation.  */
+ static struct struct_node *
+ create_basic_block_node (struct flow_structure *st, basic_block b)
+ {
+   struct struct_node *n = create_node (st, STRUCT_BASIC_BLOCK);
+   n->data.basic_block.basic_block = b;
+   b->aux = n;
+   return n;
+ }
+ 
+ /* Create structural node representing exit block.  */
+ static struct struct_node *
+ create_exit_node (struct flow_structure *st)
+ {
+   struct struct_node *n = create_node (st, STRUCT_EXIT);
+   n->data.basic_block.basic_block = EXIT_BLOCK_PTR;
+   EXIT_BLOCK_PTR->aux = n;
+   return n;
+ }
+ 
+ /* Create structural node representing entry block.  */
+ static struct struct_node *
+ create_entry_node (struct flow_structure *st)
+ {
+   struct struct_node *n = create_node (st, STRUCT_ENTRY);
+   n->data.basic_block.basic_block = ENTRY_BLOCK_PTR;
+   ENTRY_BLOCK_PTR->aux = n;
+   return n;
+ }
+ 
+ /* Print INDENT spaces.  */
+ static void
+ print_indent (FILE * out, int indent)
+ {
+   int i;
+ 
+   for (i = 0; i < indent; i++)
+     fputc (' ', out);
+ }
+ 
+ /* Print goto used by proper, improper and reduced_loop blocks.  */
+ static void
+ struct_pretty_print_goto (FILE * out, struct struct_node *node, int indent,
+ 			  bool indented)
+ {
+   bool first = true;
+   struct struct_edge *e = node->succ;
+ 
+   if (!node->succ)
+     return;
+   if (!indented)
+     print_indent (out, indent);
+   else
+     fputc (' ', out);
+   fputs ("goto ", out);
+   for (e = node->succ; e; e = e->succ_next)
+     {
+       struct struct_node *n = e->dest;
+ 
+       while (n->son)
+ 	n = n->son;
+       if (!first)
+ 	fputs (" or ", out);
+       if (n->type == STRUCT_EXIT)
+ 	fputs ("return", out);
+       else if (n->type == STRUCT_BASIC_BLOCK)
+ 	fprintf (out, "bb%i", n->data.basic_block.basic_block->index);
+       first = false;
+     }
+   if (node->exits)
+     {
+       if (!first)
+ 	fputs (" or ", out);
+       fputs ("upper", out);
+     }
+   fputc ('\n', out);
+ }
+ 
+ /* Print node in pretty way indented by INDENT spaces.
+    when INDENTED is true expect the current line being partly output
+    and use it only when the whole thing fits in single line.  */
+ static void
+ struct_pretty_print_node (FILE * out, struct struct_node *node, int indent,
+ 			  bool indented)
+ {
+   struct struct_node *n = node->son;
+   switch (node->type)
+     {
+     case STRUCT_NONE:
+       abort ();
+     case STRUCT_ENTRY:
+       break;
+     case STRUCT_EXIT:
+       if (!indented)
+ 	print_indent (out, indent);
+       else
+ 	fputc (' ', out);
+       fputs ("return\n", out);
+       break;
+     case STRUCT_BLOCK:
+       if (indented)
+ 	fputc ('\n', out);
+       print_indent (out, indent);
+       fputs ("{\n", out);
+       while (n)
+ 	{
+ 	  struct_pretty_print_node (out, n, indent + 2, false);
+ 	  if (n->son_next && (!n->succ || n->succ->succ_next
+ 			      || n->succ->dest != n->son_next))
+ 	    abort ();
+ 
+ 	  n = n->son_next;
+ 	}
+       print_indent (out, indent);
+       fputs ("}\n", out);
+       break;
+     case STRUCT_IF_THEN_ELSE:
+       if (indented)
+ 	fputc ('\n', out);
+       print_indent (out, indent);
+       fputs ("if", out);
+     again:
+       struct_pretty_print_node (out, n, indent + 2, true);
+       n = n->son_next;
+       struct_pretty_print_node (out, n, indent + 2, false);
+       n = n->son_next;
+       print_indent (out, indent);
+       if (n->type == STRUCT_IF_THEN_ELSE)
+ 	{
+ 	  fputs ("else if", out);
+ 	  node = n;
+ 	  n = n->son;
+ 	  goto again;
+ 	}
+       if (n->type == STRUCT_IF_THEN)
+ 	{
+ 	  fputs ("else if", out);
+ 	  node = n;
+ 	  n = n->son;
+ 	  goto again2;
+ 	}
+       fputs ("else\n", out);
+       struct_pretty_print_node (out, n, indent + 2, false);
+       n = n->son_next;
+       if (n)
+ 	abort ();
+       break;
+     case STRUCT_IF_THEN:
+       if (indented)
+ 	fputc ('\n', out);
+       print_indent (out, indent);
+       fputs ("if", out);
+     again2:
+       struct_pretty_print_node (out, n, indent + 2, true);
+       n = n->son_next;
+       struct_pretty_print_node (out, n, indent + 2, false);
+       n = n->son_next;
+       if (n)
+ 	abort ();
+       break;
+     case STRUCT_BASIC_BLOCK:
+       if (!indented)
+ 	print_indent (out, indent);
+       else
+ 	fputc (' ', out);
+       {
+ 	basic_block bb = node->data.basic_block.basic_block;
+ 
+ 	fprintf (out, "BB #%i", bb->index);
+ 	if (bb->frequency)
+ 	  fprintf (out, "      	freq:%i", bb->frequency);
+ 	if (bb->count)
+ 	  fprintf (out, " count:" HOST_WIDEST_INT_PRINT_DEC,
+ 		   (HOST_WIDEST_INT) bb->count);
+ 	fputc ('\n', out);
+       }
+       if (n)
+ 	abort ();
+       break;
+     case STRUCT_LOOP:
+       if (indented)
+ 	fputc ('\n', out);
+       print_indent (out, indent);
+       fputs ("loop", out);
+       struct_pretty_print_node (out, n, indent + 2, true);
+       if (n->son_next)
+ 	abort ();
+       break;
+     case STRUCT_REPEAT:
+       if (indented)
+ 	fputc ('\n', out);
+       print_indent (out, indent);
+       fputs ("do\n", out);
+       struct_pretty_print_node (out, n, indent + 2, false);
+       n = n->son_next;
+       print_indent (out, indent);
+       fputs ("while", out);
+       struct_pretty_print_node (out, n, indent + 2, true);
+       if (n->son_next)
+ 	abort ();
+       break;
+     case STRUCT_WHILE:
+       if (indented)
+ 	fputc ('\n', out);
+       print_indent (out, indent);
+       fputs ("while", out);
+       struct_pretty_print_node (out, n, indent + 2, true);
+       n = n->son_next;
+       print_indent (out, indent);
+       fputs ("do\n", out);
+       struct_pretty_print_node (out, n, indent + 2, false);
+       if (n->son_next)
+ 	abort ();
+       break;
+     case STRUCT_REDUCED_LOOP:
+       if (indented)
+ 	fputc ('\n', out);
+       print_indent (out, indent);
+       fputs ("while forever\n", out);
+       print_indent (out, indent + 2);
+       fputs ("{\n", out);
+       while (n)
+ 	{
+ 	  struct struct_node *next = n->son_next;
+ 
+ 	  if (!next)
+ 	    next = node->son;
+ 	  if (!n->succ->succ_next && n->succ->dest == next && !n->exits)
+ 	    {
+ 	      struct_pretty_print_node (out, n, indent + 4, false);
+ 	    }
+ 	  else if (!n->succ->succ_next && n->succ->dest == next && n->exits)
+ 	    {
+ 	      print_indent (out, indent + 4);
+ 	      fputs ("if", out);
+ 	      struct_pretty_print_node (out, n, indent + 6, true);
+ 	      print_indent (out, indent + 6);
+ 	      fputs ("break\n", out);
+ 	    }
+ 	  else
+ 	    {
+ 	      struct_pretty_print_node (out, n, indent + 4, false);
+ 	      struct_pretty_print_goto (out, n, indent + 4, false);
+ 	    }
+ 	  n = n->son_next;
+ 	}
+       print_indent (out, indent + 2);
+       fputs ("}\n", out);
+       break;
+     case STRUCT_PROPER:
+     case STRUCT_IMPROPER:
+       if (indented)
+ 	fputc ('\n', out);
+       if (node->type == STRUCT_IMPROPER)
+ 	{
+ 	  print_indent (out, indent);
+ 	  fputs ("improper:\n", out);
+ 	}
+       print_indent (out, indent);
+       fputs ("{\n", out);
+       while (n)
+ 	{
+ 	  struct struct_node *next = n->son_next;
+ 
+ 	  if (n->succ && !n->succ->succ_next && n->succ->dest == next
+ 	      && !n->exits)
+ 	    {
+ 	      struct_pretty_print_node (out, n, indent + 2, false);
+ 	    }
+ 	  else if (n->succ && !n->succ->succ_next && n->succ->dest == next
+ 		   && n->exits)
+ 	    {
+ 	      print_indent (out, indent + 2);
+ 	      fputs ("if", out);
+ 	      struct_pretty_print_node (out, n, indent + 4, true);
+ 	      print_indent (out, indent + 4);
+ 	      fputs ("break\n", out);
+ 	    }
+ 	  else
+ 	    {
+ 	      struct_pretty_print_node (out, n, indent + 2, false);
+ 	      struct_pretty_print_goto (out, n, indent + 2, false);
+ 	    }
+ 	  n = n->son_next;
+ 	}
+       print_indent (out, indent);
+       fputs ("}\n", out);
+       break;
+     default:
+       abort ();
+     }
+ }
+ 
+ /* Print node in verbose way.  Usefull for debugging the structural
+    analysis themselves.  */
+ static void
+ struct_print_node (FILE * out, struct struct_node *node, int indent)
+ {
+   static const char *const node_names[] = {
+     "none",
+     "basic_block",
+     "entry",
+     "exit",
+     "block",
+     "if_then",
+     "if_then_else",
+     "proper",
+     "loop",
+     "repeat",
+     "while",
+     "reduced_loop",
+     "improper"
+   };
+   struct struct_node *n = node->son;
+ 
+   print_indent (out, indent);
+   fprintf (out, "%s #%i pre: %i post: %i", node_names[node->type], node->index,
+ 	   node->pre_dfs_index, node->post_dfs_index);
+   if (node->type == STRUCT_BASIC_BLOCK)
+     fprintf (out, " %i", node->data.basic_block.basic_block->index);
+   if (node->succ)
+     {
+       struct struct_edge *e = node->succ;
+       fprintf (out, " succ [");
+       while (e)
+ 	{
+ 	  if (e->src != node)
+ 	    abort ();
+ 	  fprintf (out, " %i", e->dest->index);
+ 	  e = e->succ_next;
+ 	}
+       fprintf (out, " ]");
+     }
+   if (node->pred)
+     {
+       struct struct_edge *e = node->pred;
+       fprintf (out, " pred [");
+       while (e)
+ 	{
+ 	  if (e->dest != node)
+ 	    abort ();
+ 	  fprintf (out, " %i", e->src->index);
+ 	  e = e->pred_next;
+ 	}
+       fprintf (out, " ]");
+     }
+   fprintf (out, "\n");
+   while (n)
+     {
+       struct_print_node (out, n, indent + 2);
+       n = n->son_next;
+     }
+ }
+ 
+ /* We need to mirror the CFG into our own representation.  
+    Return entry node.  */
+ static struct struct_node *
+ mirror_cfg (struct flow_structure *st)
+ {
+   basic_block bb;
+   edge edge;
+ 
+   FOR_EACH_BB (bb)
+     create_basic_block_node (st, bb);
+   FOR_EACH_BB (bb)
+     {
+       edge = bb->succ;
+       while (edge)
+ 	{
+           struct_create_edge (st, edge->src->aux, edge->dest->aux);
+ 	  edge = edge->succ_next;
+ 	}
+       /* Structural analysis produce ugly results with presence of
+ 	 basic block with no outgoing edges.  Alternatively we can
+ 	 accept noreturn block for STRUCT_IF_THEN/STRUCT_IF_THEN_ELSE
+ 	 or invent new names for conditionals terminating program.  */
+       if (!bb->succ)
+         struct_create_edge (st, bb->aux, st->exit);
+     }
+   edge = ENTRY_BLOCK_PTR->succ;
+   while (edge)
+     {
+       struct_create_edge (st, st->entry, edge->dest->aux);
+       edge = edge->succ_next;
+     }
+   return (st->entry);
+ }
+ 
+ /* Perform depth first search, intialize dfs_order structure
+    and set pre_dfs_index and post_dfs_index.  */
+ static int
+ struct_DFS (struct struct_node **dfs_order, struct struct_node *n)
+ {
+   struct struct_edge **stack;
+   int sp;
+   int prenum = 1;
+   int postnum = 0;
+ 
+   /* Allocate stack for back-tracking up CFG.  */
+   stack =
+     (struct struct_edge **) xmalloc ((n_basic_blocks + 2) *
+ 				     sizeof (struct struct_edge *));
+   sp = 0;
+   n->visit = 1;
+   n->pre_dfs_index = 0;
+ 
+   /* Push the first edge on to the stack.  */
+   stack[sp++] = n->succ;
+ 
+   while (sp)
+     {
+       struct struct_edge *e;
+       struct struct_node *src;
+       struct struct_node *dest;
+ 
+       /* Look at the edge on the top of the stack.  */
+       e = stack[sp - 1];
+       src = e->src;
+       dest = e->dest;
+ 
+       /* Check if the edge destination has been visited yet.  */
+       if (!dest->visit)
+ 	{
+ 	  /* Mark that we have visited the destination.  */
+ 	  dest->visit = 1;
+ 
+ 	  dest->pre_dfs_index = prenum++;
+ 	  if (dest->succ)
+ 	    {
+ 	      /* Since the DEST node has been visited for the first
+ 	         time, check its successors.  */
+ 	      stack[sp++] = dest->succ;
+ 	    }
+ 	  else
+ 	    {
+ 	      dfs_order[postnum] = dest;
+ 	      dest->post_dfs_index = postnum++;
+ 	    }
+ 	}
+       else
+ 	{
+ 	  if (!e->succ_next)
+ 	    {
+ 	      dfs_order[postnum] = src;
+ 	      src->post_dfs_index = postnum++;
+ 	    }
+ 
+ 	  if (e->succ_next)
+ 	    stack[sp - 1] = e->succ_next;
+ 	  else
+ 	    sp--;
+ 	}
+     }
+ 
+   free (stack);
+   return postnum;
+ }
+ 
+ /* Reduce chain of nodes starting at SON into region of TYPE.
+    Update DFS_ORDER and set new entry type in case it has changed.  */
+ static struct struct_node *
+ reduce (struct flow_structure *st, struct struct_node *son,
+ 	enum node_type type, struct struct_node **dfs_order,
+ 	struct struct_node **entry)
+ {
+   struct struct_node *node;
+   struct struct_node *n;
+   int maxorder = son->post_dfs_index;
+   int minorder = son->pre_dfs_index;
+ 
+   /* Compute new DFS indexes.  */
+ #ifdef ENABLE_CHECKING
+   n = son;
+   while (n)
+     {
+       if (n->parent)
+ 	abort ();
+       n = n->son_next;
+     }
+ #endif
+ 
+   /* We are recogninzing blocks in pairs.  It looks prettier when we
+      concatenate them into single blocks containing multiple sons.  */
+   if (type == STRUCT_BLOCK
+       && son->son_next->type == STRUCT_BLOCK && !son->son_next->son_next)
+     {
+       node = son->son_next;
+ 
+       /* Create internal edge.  */
+       struct_remove_edge (st, son->succ);
+       if (son->succ)
+ 	abort ();
+       struct_create_edge (st, son, node->son);
+ 
+       /* Merge sons.  */
+       son->parent = node;
+       son->son_next = node->son;
+       node->son = son;
+       node->visit = 0;
+ 
+       /* Redirect incomming edges.  */
+       if (node->pred)
+ 	abort ();
+       while (son->pred)
+ 	{
+ 	  struct_create_edge (st, son->pred->src, node);
+ 	  struct_remove_edge (st, son->pred);
+ 	}
+     }
+   else
+     {
+ 
+       node = create_node (st, type);
+       node->son = son;
+ 
+       n = son;
+       while (n)
+ 	{
+ 	  n->parent = node;
+ 	  n = n->son_next;
+ 	}
+       if (!son)
+ 	abort ();
+       n = son;
+       while (n)
+ 	{
+ 	  struct struct_edge *e;
+ 	  e = n->succ;
+ 	  while (e)
+ 	    {
+ 	      struct struct_edge *next = e->succ_next;
+ 	      struct struct_node *d = e->dest;
+ 	      if (d == son && !LOOPING_NODE (type))
+ 		abort ();
+ 	      else if (d->parent != node)
+ 		{
+ 		  struct_remove_edge (st, e);
+ 		  struct_create_edge (st, node, d);
+ 		  n->exits = true;
+ 		}
+ 	      e = next;
+ 	    }
+ 	  e = n->pred;
+ 	  while (e)
+ 	    {
+ 	      struct struct_edge *next = e->pred_next;
+ 	      struct struct_node *s = e->src;
+ 	      if (s->parent != node)
+ 		{
+ 		  if (n != node->son)
+ 		    abort ();
+ 		  struct_remove_edge (st, e);
+ 		  struct_create_edge (st, s, node);
+ 		}
+ 	      e = next;
+ 	    }
+ 	  if (n == *entry)
+ 	    *entry = node;
+ 	  n = n->son_next;
+ 	}
+     }
+   dfs_order[maxorder] = node;
+   node->pre_dfs_index = minorder;
+   node->post_dfs_index = maxorder;
+   return node;
+ }
+ 
+ /* Return true when N is succesor of N2.  */
+ static bool
+ succ_of_p (struct struct_node *n, struct struct_node *n2)
+ {
+   struct struct_edge *e;
+ 
+   for (e = n2->succ; e; e = e->succ_next)
+     if (e->dest == n)
+       return true;
+   return false;
+ }
+ 
+ /* Proper region is maximal acyclic subgraph with only single entry point N.
+    We discover it by doing topological sort as long as we are able to.  */
+ static struct struct_node *
+ find_proper_region (struct struct_node *n)
+ {
+   struct struct_node *lastson = n;
+   struct struct_node *current = n;
+ 
+   while (current)
+     {
+       struct struct_edge *e = current->succ;
+       while (e)
+ 	{
+ 	  /* We ought to have an counter here, but I am lazy to do it for now
+ 	     so I just look for unknown predecesors by hand.  This makes
+ 	     algorithm potentially quadratic in number of nodes.  */
+ 	  struct struct_edge *e1 = e->dest->pred;
+ 
+ 	  if (!e->dest->son_next && e->dest != lastson)
+ 	    {
+ 	      while (e1)
+ 		{
+ 		  if (!e1->src->son_next && e1->src != lastson)
+ 		    break;
+ 		  e1 = e1->pred_next;
+ 		}
+ 	      if (!e1 && !succ_of_p (n, e->dest))
+ 		{
+ 		  lastson->son_next = e->dest;
+ 		  lastson = e->dest;
+ 		}
+ 	    }
+ 	  e = e->succ_next;
+ 	}
+       current = current->son_next;
+     }
+   return n;
+ }
+ 
+ /* Return true when A is ancestor of B in DFS search.  */
+ static bool
+ is_ancestor_p (struct struct_node *a, struct struct_node *b)
+ {
+   return (a->pre_dfs_index <= b->pre_dfs_index
+ 	  && a->post_dfs_index > b->post_dfs_index);
+ }
+ 
+ /* Reverse linked list representing structural node.  */
+ static struct struct_node *
+ reverse_son_list (struct struct_node *n)
+ {
+   struct struct_node *prev = 0, *next;
+   for (; n; n = next)
+     {
+       next = n->son_next;
+       n->son_next = prev;
+       prev = n;
+     }
+   return prev;
+ }
+ 
+ /* Add node NODE into list pointed to by WHERE.  */
+ static void
+ add_to_node_list (struct struct_node_list **where, struct struct_node *node)
+ {
+   struct struct_node_list *list = pool_alloc (list_pool);
+   list->node = node;
+   list->next = *where;
+   *where = list;
+ }
+ 
+ /* Identify the cyclic region in the graph entered by node n.  */
+ 
+ static struct struct_node *
+ find_cyclic_region (struct struct_node *n)
+ {
+   struct struct_edge *e = n->pred;
+   struct struct_node *lastson = n;
+   bool improper = false;
+ 
+   while (e)
+     {
+       /* Identify the back edges.  */
+       if (is_ancestor_p (n, e->src)
+ 	  && (!e->src->son_next && e->src != lastson))
+ 	{
+ 	  struct struct_node *n1 = e->src;
+ 	  struct struct_node *torev = lastson;
+ 
+ 	  lastson->son_next = n1;
+ 	  lastson = n1;
+ 	  /* When we are not looking at loopback edge, discover loop body
+ 	     by looking at predesecors of the basic block.  */
+ 	  while (n1)
+ 	    {
+ 	      struct struct_edge *e1 = n1->pred;
+ 	      while (e1)
+ 		{
+ 		  /* Look for blocks we didn't visited yet and link them
+ 		     into region.  */
+ 		  if (e1->src->parent)
+ 		    abort ();
+ 		  if (!e1->src->son_next && e1->src != lastson)
+ 		    {
+ 		      if (is_ancestor_p (n, e1->src))
+ 			{
+ 			  lastson->son_next = e1->src;
+ 			  lastson = e1->src;
+ 			}
+ 		      else
+ 			improper = true;
+ 		    }
+ 		  e1 = e1->pred_next;
+ 		}
+ 	      n1 = n1->son_next;
+ 	    }
+ 
+ 	  /*  Make ordering prettier - we discover the loop in reverse order.
+ 	   */
+ 	  lastson = torev->son_next;
+ 	  torev->son_next = reverse_son_list (torev->son_next);
+ 	}
+       e = e->pred_next;
+     }
+   /* Do we have improper region?  If so, we have to perform minimization.  */
+   if (n->son_next && improper)
+     {
+       struct struct_node *l, *head, *next;
+       basic_block ancestor = NULL;
+ 
+       if (!dom)
+ 	dom = calculate_dominance_info (CDI_DOMINATORS);
+ 
+       for (l = n; l; l = l->son_next)
+ 	{
+ 	  struct struct_node *l2 = l;
+ 	  basic_block b;
+ 
+ 	  while (l2->parent)
+ 	    l2 = l2->parent;
+ 	  b = l2->data.basic_block.basic_block;
+ 	  if (!ancestor)
+ 	    ancestor = b;
+ 	  else
+ 	    ancestor = nearest_common_dominator (dom, b, ancestor);
+ 	}
+       head = ancestor->aux;
+       while (head->parent)
+ 	head = head->parent;
+       for (l = n; l; l = next)
+ 	{
+ 	  next = l->son_next;
+ 	  l->son_next = NULL;
+ 	  if (l->improper_head != head)
+ 	    {
+ 	      add_to_node_list (&head->improper_nodes, l);
+ 	      l->improper_head = head;
+ 	    }
+ 	}
+     }
+   return n;
+ }
+ 
+ /* Return type of the acyclic region, STRUCT_NODE otherwise.  */
+ static enum node_type
+ acyclic_region_type (struct struct_node *n, struct struct_node **first)
+ {
+   struct struct_node *n1 = n;
+   struct struct_node *n2 = n;
+ 
+   /* Rule out self loops early.  */
+   if (succ_of_p (n, n))
+     return STRUCT_NONE;
+ 
+   /* Block.  */
+   if (n->succ && !n->succ->succ_next)
+     {
+       n2 = n->succ->dest;
+       if (n2->pred && !n2->pred->pred_next && !succ_of_p (n1, n2))
+ 	{
+ 	  n1->son_next = n2;
+ 	  n2->son_next = NULL;
+ 	  *first = n1;
+ 	  return STRUCT_BLOCK;
+ 	}
+     }
+ 
+   /* Nonlooping conditional jump...  */
+   if (n->succ && n->succ->succ_next && !n->succ->succ_next->succ_next
+       && n->succ->dest != n && n->succ->succ_next->dest != n)
+     {
+       n1 = n->succ->dest;
+       n2 = n->succ->succ_next->dest;
+       if (n1 == n2)
+ 	abort ();
+ 
+       /* If then else */
+       if (n1->succ && n2->succ && n1->succ->dest == n2->succ->dest
+ 	  && !n1->succ->succ_next && !n2->succ->succ_next
+ 	  && !n1->pred->pred_next && !n2->pred->pred_next
+ 	  /* Prohibit loops */
+ 	  && n1->succ->dest != n1 && n1->succ->dest != n
+ 	  && n1->succ->dest != n2)
+ 	{
+ 	  n->son_next = n2;
+ 	  n2->son_next = n1;
+ 	  n1->son_next = NULL;
+ 	  *first = n;
+ 	  return STRUCT_IF_THEN_ELSE;
+ 	}
+ 
+       /* if then */
+       if (n1->succ && n1->succ->dest == n2
+ 	  && !n1->succ->succ_next && n1->pred && !n1->pred->pred_next)
+ 	{
+ 	  n->son_next = n1;
+ 	  n1->son_next = NULL;
+ 	  *first = n;
+ 	  return STRUCT_IF_THEN;
+ 	}
+       /* The symetric case.  */
+       if (n2->succ && n2->succ->dest == n1
+ 	  && !n2->succ->succ_next && n2->pred && !n2->pred->pred_next)
+ 	{
+ 	  n->son_next = n2;
+ 	  n2->son_next = NULL;
+ 	  *first = n;
+ 	  return STRUCT_IF_THEN;
+ 	}
+     }
+ 
+   /* Handling of the switch statements is suggested too, but I don't see any
+      point to do that right now.  */
+   return STRUCT_NONE;
+ }
+ 
+ /* Return the type of cyclic region, STRUCT_NONE otherwise.
+    Also initialize improper_nodes lists in the case current node is
+    found to be in the improper region.  */
+ static enum node_type
+ cyclic_region_type (struct struct_node *n, struct struct_node **first)
+ {
+   /* The fast path - self loops and repeat loops are the most common
+      looping constructs.  */
+   if (succ_of_p (n, n))
+     {
+       *first = n;
+       return STRUCT_LOOP;
+     }
+   if (n->succ && !n->succ->succ_next
+       && !n->succ->dest->pred->pred_next && succ_of_p (n, n->succ->dest))
+     {
+       *first = n;
+       n->son_next = n->succ->dest;
+       return STRUCT_REPEAT;
+     }
+   *first = find_cyclic_region (n);
+ 
+   if ((*first)->son_next && !(*first)->son_next->son_next
+       && (*first)->son_next->succ && !(*first)->son_next->succ->succ_next)
+     return STRUCT_WHILE;
+ 
+   /* The existence of loops with multiple entry points is very unfortunate.
+      For now deal by converting whole graph to single improper region.
+      We will need to find more smart way how to discover them later.  */
+   if ((*first)->son_next)
+     return STRUCT_REDUCED_LOOP;
+   return STRUCT_NONE;
+ }
+ 
+ /* Look for closest header of improper region.  */
+ static void
+ minimize_improper_regions (struct struct_node *n)
+ {
+   struct struct_node *head = n->improper_head;
+   struct struct_edge *e;
+   int min_post_ord_seen = INT_MAX;
+ 
+   if (head)
+     min_post_ord_seen = head->post_dfs_index;
+   for (e = n->succ; e; e = e->succ_next)
+     if (e->dest->improper_head
+ 	&& min_post_ord_seen > e->dest->improper_head->post_dfs_index)
+       {
+ 	min_post_ord_seen = e->dest->improper_head->post_dfs_index;
+ 	head = e->dest->improper_head;
+       }
+   if (min_post_ord_seen != INT_MAX && n->improper_head != head)
+     {
+       n->improper_head = head;
+       add_to_node_list (&head->improper_nodes, n);
+     }
+ }
+ 
+ /* Build list of all nodes inside improper regions.
+    We may enocounter nested improper regions so we need to traverse
+    these recursivly.  */
+ static struct struct_node *
+ build_improper_region (struct struct_node *n)
+ {
+   struct struct_node_list *l;
+   struct struct_node *first = n;
+   struct struct_node *last = n;
+ 
+   for (l = n->improper_nodes; l; l = l->next)
+     {
+       struct struct_node *nn = l->node;
+       while (nn->parent)
+ 	nn = nn->parent;
+       if (nn != last && !nn->son_next)
+ 	{
+ 	  last->son_next = nn;
+ 	  last = nn;
+ 	}
+     }
+   return first;
+ }
+ 
+ /* Main entry point - build flow structure and return the pointer.  */
+ struct flow_structure *
+ build_flow_structure (void)
+ {
+   struct flow_structure *st;
+   struct struct_node *entry;
+   struct struct_node **dfs_order;
+   int npost;
+   int nnodes = n_basic_blocks + 2;
+   int index = 0;
+   struct struct_node *first;
+ 
+   st = xcalloc (sizeof (*st), 1);
+   st->edge_pool =
+     create_alloc_pool ("structural edges", sizeof (struct struct_edge),
+ 		       n_edges + 1);
+   st->node_pool =
+     create_alloc_pool ("structural nodes", sizeof (struct struct_node),
+ 		       n_basic_blocks + 4);
+   list_pool =
+     create_alloc_pool ("structural nodes lists",
+ 		       sizeof (struct struct_node_list), 1);
+   st->root = NULL;
+   st->nnodes = -2;
+   st->exit = create_exit_node (st);
+   st->entry = create_entry_node (st);
+ 
+   dfs_order =
+     (struct struct_node **) xmalloc ((n_basic_blocks + 2) *
+ 				     sizeof (struct struct_node *));
+   entry = mirror_cfg (st);
+ 
+ 
+   npost = struct_DFS (dfs_order, entry);
+   for (index = 0; index < npost; index++)
+     {
+       dfs_order[index]->post_dfs_index = index;
+       dfs_order[index]->visit = 0;
+     }
+   index = 0;
+   while (nnodes > 1 && index < npost)
+     {
+       struct struct_node *n = dfs_order[index];
+       enum node_type type;
+       bool noreduce;
+ 
+       do
+ 	{
+ 	  noreduce = false;
+ 	  if (n->improper_nodes)
+ 	    n = st->root =
+ 	      reduce (st, build_improper_region (n), STRUCT_IMPROPER,
+ 		      dfs_order, &entry);
+ 	  if (n->parent)
+ 	    {
+ 	      minimize_improper_regions (n);
+ 	      break;
+ 	    }
+ 	  /* Locate acyclic region if present.  */
+ 	  type = acyclic_region_type (n, &first);
+ 	  if (!type)
+ 	    {
+ 	      /* Locate the cyclict region if present.  */
+ 	      type = cyclic_region_type (n, &first);
+ 	    }
+ 	  if (type)
+ 	    n = st->root = reduce (st, first, type, dfs_order, &entry);
+ 	  else
+ 	    noreduce = true;
+ 	  minimize_improper_regions (n);
+ 	}
+       while (!noreduce);
+       index++;
+     }
+ 
+   while (entry->parent)
+     entry = entry->parent;
+ 
+   /*  Pack possible remaining irreducible acyclic nodes into single PROPER
+      basic block.  */
+   first = find_proper_region (entry);
+   if (first->son_next)
+     st->root = reduce (st, first, STRUCT_PROPER, dfs_order, &entry);
+ 
+   /*  Verify that we reduced whole CFG.  */
+   while (entry->parent)
+     entry = entry->parent;
+   if (entry->succ || entry->pred)
+     abort ();
+ 
+   if (dom)
+     free_dominance_info (dom);
+   clear_aux_for_blocks ();
+   free_alloc_pool (list_pool);
+   dom = NULL;
+   return st;
+ }
+ 
+ /* Release data used by flow structure.  */
+ void
+ free_flow_structure (struct flow_structure *st)
+ {
+   free_alloc_pool (st->edge_pool);
+   free_alloc_pool (st->node_pool);
+   free (st);
+ }
+ 
+ /* Dump whole flow structure in verbose way.  */
+ void
+ dump_flow_structure (struct flow_structure *st, FILE *out)
+ {
+   struct_print_node (out, st->root, 0);
+ }
+ 
+ /* Dump whole flow structure in pretty way.  */
+ void
+ pretty_dump_flow_structure (struct flow_structure *st, FILE *out)
+ {
+   struct_pretty_print_node (out, st->root, 0, false);
+ }
Index: sa.h
===================================================================
RCS file: sa.h
diff -N sa.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- sa.h	15 Jun 2003 18:13:37 -0000
***************
*** 0 ****
--- 1,138 ----
+ /* The structural control flow graph analysis.
+    Contributed by Jan Hubicka, SuSE Labs.
+    Copyright (C) 2003 Free Software Foundation, Inc.
+ 
+    This file is part of GCC.
+ 
+    GCC is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    GCC is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with GCC; see the file COPYING.  If not, write to the Free
+    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+    02111-1307, USA.  */
+ 
+ #ifndef SA_H
+ #define SA_H
+ /* Basic constructions we know of.  
+    Allow bit operations to represent classes of the struct constructions.  */
+ enum node_type
+   {
+     STRUCT_NONE,
+     STRUCT_BASIC_BLOCK,
+     STRUCT_ENTRY,
+     STRUCT_EXIT,
+     /*  son0->son1->son2.... */
+     STRUCT_BLOCK,
+     /*    Son0
+           /  |
+         son1 |
+           \  |
+            XXX  */
+     STRUCT_IF_THEN,
+     /*    Son0
+           /   \
+         son1 son2
+           \   /
+            XXX  */
+     STRUCT_IF_THEN_ELSE,
+     /* Arbitary acyclic region.  */
+     STRUCT_PROPER,
+     /* Self loop.  */
+     STRUCT_LOOP,
+     /*    Son1
+            | ^ 
+            V |
+           Son2
+            |
+            V 
+           XXXX   */
+     STRUCT_REPEAT,
+     /*    Son1---> XXX
+            | ^ 
+            V |
+           Son2  */
+     STRUCT_WHILE,
+     /* Arbitrary loop with single entry edge.  */
+     STRUCT_REDUCED_LOOP,
+     /* Improper region - may contain everything.  */
+     STRUCT_IMPROPER
+   };
+ 
+ #define LOOPING_NODE(type) (type >= STRUCT_LOOP)
+ struct struct_edge;
+ 
+ /* Structure used to represent each node. */
+ struct struct_node
+   {
+     enum node_type type;
+ 
+     /* Unique index used by dumping function.  */
+     int index;
+ 
+     /* We represent tree of nodes.  */
+     struct struct_node *parent;
+     struct struct_node *son;
+     struct struct_node *son_next;
+ 
+     struct struct_node_list
+       {
+         struct struct_node *node;
+         struct struct_node_list *next;
+       } *improper_nodes;
+     struct struct_node *improper_head;
+ 
+     /* As well as predecesor/succesor information.  */
+     struct struct_edge *pred, *succ;
+ 
+     /* Data that does depend on the type of node.  */
+     union
+       {
+ 	struct
+ 	  {
+ 	    struct basic_block_def *basic_block;
+ 	  }
+ 	basic_block;
+       }
+     data;
+ 
+     /* Used temporary by DFS searching routines.  Set to 0 otherwise.  */
+     int visit:1;
+     /* Whether control flow can leave the parent node here.  */
+     int exits:1;
+     int pre_dfs_index;
+     int post_dfs_index;
+   };
+ 
+ /* Structure used to represent edge.  */
+ struct struct_edge
+   {
+     struct struct_node *src, *dest;
+     struct struct_edge *succ_next, *pred_next;
+     struct struct_edge *succ_prev, *pred_prev;
+   };
+ 
+ /* Overall Central Flow Structure object.  */
+ struct flow_structure
+   {
+     /* Obstack used to allocate all the data structures.  */
+     struct alloc_pool_def *node_pool, *edge_pool;
+     struct struct_node *root;
+     struct struct_node *entry;
+     struct struct_node *exit;
+     int nnodes;
+   };
+ 
+ struct flow_structure *build_flow_structure (void);
+ void free_flow_structure (struct flow_structure *);
+ void dump_flow_structure (struct flow_structure *, FILE *);
+ void pretty_dump_flow_structure (struct flow_structure *, FILE *);
+ void debug_flow_structure (void);
+ #endif
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.769
diff -c -3 -p -r1.769 toplev.c
*** toplev.c	8 Jun 2003 19:35:53 -0000	1.769
--- toplev.c	15 Jun 2003 18:13:38 -0000
*************** Software Foundation, 59 Temple Place - S
*** 31,36 ****
--- 31,37 ----
  #include "coretypes.h"
  #include "tm.h"
  #include <signal.h>
+ #include "sa.h"
  
  #ifdef HAVE_SYS_RESOURCE_H
  # include <sys/resource.h>
*************** rest_of_handle_cfg (tree decl, rtx insns
*** 2848,2853 ****
--- 2849,2860 ----
    if (optimize)
      cleanup_cfg (CLEANUP_EXPENSIVE
  		 | (flag_thread_jumps ? CLEANUP_THREADING : 0));
+   if (rtl_dump_file)
+     {
+       struct flow_structure *st = build_flow_structure ();
+       pretty_dump_flow_structure (st, rtl_dump_file);
+       free_flow_structure (st);
+     }
  
    /* It may make more sense to mark constant functions after dead code is
       eliminated by life_analysis, but we need to do it early, as -fprofile-arcs


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