* i386.c (ix86_output_main_function_alignment_hack): New function.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 30 Jul 2001 20:30:23 +0000 (20:30 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 30 Jul 2001 20:30:23 +0000 (20:30 +0000)
(TARGET_ASM_FUNCTION_PROLOGUE): Default to it.

* flow.c (mark_dfs_back_edges): Move from loop_p ; mark back
edges by EDGE_DFS_BACK flag.
(dump_edge_info): Add dfs_back flag.
* basic-block.h (EDGE_DFS_BACK): New constant.
(mark_dfs_back_edges): Declare.
* alias.c (loop_p): Remove.
(mark_constant_function): Use mark_dfs_back_edges.

* reg-stack.c (block_info_def): Add predecesors counter and stack_out.
(reg_to_stack): Call mark_dfs_back_edges; count the predecesors.
(compensate_edge): Break out from ...
(convert_regs_1): ... here; do smart choosing of stack_out to copy.
(convert_regs_2): Set block_done once block is really done;
Do updating of the predecesors counts.

* toplev.c (rest_of_compilation): Recompute block_for_insn
before post-reload cfg_cleanup.
* function.c (thread_prologue_epilogue_insns):
Call set_block_for_new_insns when emitting prologue directly.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@44486 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/alias.c
gcc/basic-block.h
gcc/config/i386/i386.c
gcc/flow.c
gcc/function.c
gcc/reg-stack.c
gcc/toplev.c

index e6b7d91..c2e831a 100644 (file)
@@ -1,3 +1,28 @@
+Mon Jul 30 22:16:08 CEST 2001  Jan Hubicka  <jh@suse.cz>
+
+       * i386.c (ix86_output_main_function_alignment_hack): New function.
+       (TARGET_ASM_FUNCTION_PROLOGUE): Default to it.
+
+       * flow.c (mark_dfs_back_edges): Move from loop_p ; mark back
+       edges by EDGE_DFS_BACK flag.
+       (dump_edge_info): Add dfs_back flag.
+       * basic-block.h (EDGE_DFS_BACK): New constant.
+       (mark_dfs_back_edges): Declare.
+       * alias.c (loop_p): Remove.
+       (mark_constant_function): Use mark_dfs_back_edges.
+
+       * reg-stack.c (block_info_def): Add predecesors counter and stack_out.
+       (reg_to_stack): Call mark_dfs_back_edges; count the predecesors.
+       (compensate_edge): Break out from ...
+       (convert_regs_1): ... here; do smart choosing of stack_out to copy.
+       (convert_regs_2): Set block_done once block is really done;
+       Do updating of the predecesors counts.
+
+       * toplev.c (rest_of_compilation): Recompute block_for_insn
+       before post-reload cfg_cleanup.
+       * function.c (thread_prologue_epilogue_insns):
+       Call set_block_for_new_insns when emitting prologue directly.
+
 2001-07-30  Andreas Jaeger  <aj@suse.de>
 
         * jump.c: Add prototype for mark_modified_reg.
index 84a7663..bbde59b 100644 (file)
@@ -107,8 +107,6 @@ static int aliases_everything_p         PARAMS ((rtx));
 static int write_dependence_p           PARAMS ((rtx, rtx, int));
 static int nonlocal_mentioned_p         PARAMS ((rtx));
 
-static int loop_p                       PARAMS ((void));
-
 /* Set up all info needed to perform alias analysis on memory references.  */
 
 /* Returns the size in bytes of the mode of X.  */
@@ -2051,96 +2049,6 @@ nonlocal_mentioned_p (x)
   return 0;
 }
 
-/* Return non-zero if a loop (natural or otherwise) is present.
-   Inspired by Depth_First_Search_PP described in:
-
-     Advanced Compiler Design and Implementation
-     Steven Muchnick
-     Morgan Kaufmann, 1997
-
-   and heavily borrowed from flow_depth_first_order_compute.  */
-
-static int
-loop_p ()
-{
-  edge *stack;
-  int *pre;
-  int *post;
-  int sp;
-  int prenum = 1;
-  int postnum = 1;
-  sbitmap visited;
-
-  /* Allocate the preorder and postorder number arrays.  */
-  pre = (int *) xcalloc (n_basic_blocks, sizeof (int));
-  post = (int *) xcalloc (n_basic_blocks, sizeof (int));
-
-  /* Allocate stack for back-tracking up CFG.  */
-  stack = (edge *) xmalloc ((n_basic_blocks + 1) * sizeof (edge));
-  sp = 0;
-
-  /* Allocate bitmap to track nodes that have been visited.  */
-  visited = sbitmap_alloc (n_basic_blocks);
-
-  /* None of the nodes in the CFG have been visited yet.  */
-  sbitmap_zero (visited);
-
-  /* Push the first edge on to the stack.  */
-  stack[sp++] = ENTRY_BLOCK_PTR->succ;
-
-  while (sp)
-    {
-      edge e;
-      basic_block src;
-      basic_block 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 != EXIT_BLOCK_PTR && ! TEST_BIT (visited, dest->index))
-       {
-         /* Mark that we have visited the destination.  */
-         SET_BIT (visited, dest->index);
-
-         pre[dest->index] = prenum++;
-
-         if (dest->succ)
-           {
-             /* Since the DEST node has been visited for the first
-                time, check its successors.  */
-             stack[sp++] = dest->succ;
-           }
-         else
-           post[dest->index] = postnum++;
-       }
-      else
-       {
-         if (dest != EXIT_BLOCK_PTR && src != ENTRY_BLOCK_PTR
-             && pre[src->index] >= pre[dest->index]
-             && post[dest->index] == 0)
-           break;
-
-         if (! e->succ_next && src != ENTRY_BLOCK_PTR)
-           post[src->index] = postnum++;
-
-         if (e->succ_next)
-           stack[sp - 1] = e->succ_next;
-         else
-           sp--;
-       }
-    }
-
-  free (pre);
-  free (post);
-  free (stack);
-  sbitmap_free (visited);
-
-  return sp;
-}
-
 /* Mark the function if it is constant.  */
 
 void
@@ -2157,7 +2065,7 @@ mark_constant_function ()
     return;
 
   /* A loop might not return which counts as a side effect.  */
-  if (loop_p ())
+  if (mark_dfs_back_edges ())
     return;
 
   nonlocal_mentioned = 0;
index 7b467c2..d7893a5 100644 (file)
@@ -145,6 +145,7 @@ typedef struct edge_def {
 #define EDGE_ABNORMAL_CALL     8
 #define EDGE_EH                        16
 #define EDGE_FAKE              32
+#define EDGE_DFS_BACK          64
 
 #define EDGE_COMPLEX   (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
 
@@ -650,6 +651,7 @@ extern void conflict_graph_print        PARAMS ((conflict_graph, FILE*));
 extern conflict_graph conflict_graph_compute 
                                         PARAMS ((regset,
                                                 partition));
+extern bool mark_dfs_back_edges                PARAMS ((void));
 
 /* In dominance.c */
 
index 725a984..9017207 100644 (file)
@@ -574,6 +574,7 @@ static HOST_WIDE_INT ix86_GOT_alias_set PARAMS ((void));
 static void ix86_adjust_counter PARAMS ((rtx, HOST_WIDE_INT));
 static rtx ix86_expand_aligntest PARAMS ((rtx, int));
 static void ix86_expand_strlensi_unroll_1 PARAMS ((rtx, rtx));
+static void ix86_output_main_function_alignment_hack PARAMS ((FILE *f, int));
 
 struct ix86_address
 {
@@ -634,6 +635,10 @@ static int ix86_comp_type_attributes PARAMS ((tree, tree));
                                                          HOST_WIDE_INT));
 #  undef TARGET_ASM_FUNCTION_PROLOGUE
 #  define TARGET_ASM_FUNCTION_PROLOGUE ix86_osf_output_function_prologue
+#else
+#  undef TARGET_ASM_FUNCTION_PROLOGUE
+#  define TARGET_ASM_FUNCTION_PROLOGUE \
+   ix86_output_main_function_alignment_hack
 #endif
 
 #undef TARGET_ASM_OPEN_PAREN
@@ -10775,3 +10780,45 @@ ix86_memory_move_cost (mode, class, in)
                * (int) GET_MODE_SIZE (mode) / 4);
     }
 }
+
+/* Most of current runtimes (Jul 2001) do not align stack properly when
+   entering main, so emit an wrapper to align stack before the real main
+   code is called.
+  
+   This can eventually go if we manage to fix the runtimes or teach gcc
+   to dynamically align stack in main automatically.
+
+   Adding check to configure is probably not good idea, as binarry can move
+   from one shared library to older.  */
+
+static void
+ix86_output_main_function_alignment_hack (file, size)
+     FILE *file;
+     int size ATTRIBUTE_UNUSED;
+{
+  rtx label;
+  char buf[256];
+  /* Check that we see main function with maximally 8 bytes of arguments.
+     if so, emit the hack to align stack for runtimes, where this constraint
+     is broken.  */
+  if (strcmp (cfun->name, "main"))
+    return;
+  if (cfun->pops_args || cfun->args_size > 12)
+    return;
+  if (PREFERRED_STACK_BOUNDARY <= 2)
+    return;
+  label = gen_label_rtx ();
+  fprintf (file, "\tpushl\t%%ebp\n");
+  fprintf (file, "\tmovl\t%%esp, %%ebp\n");
+  fprintf (file, "\tandl\t$0xfffffff0, %%esp\n");
+  fprintf (file, "\tpushl\t%%ebp\n");
+  fprintf (file, "\tpushl\t16(%%ebp)\n");
+  fprintf (file, "\tpushl\t12(%%ebp)\n");
+  fprintf (file, "\tpushl\t8(%%ebp)\n");
+  fprintf (file, "\tcall\t");
+  ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (label));
+  assemble_name (file, buf);
+  fprintf (file, "\n\tleave\n");
+  fprintf (file, "\tret\n");
+  ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (label));
+}
index 69e7747..b13591f 100644 (file)
@@ -1528,6 +1528,99 @@ mark_critical_edges ()
     }
 }
 \f
+/* Mark the back edges in DFS traversal.
+   Return non-zero if a loop (natural or otherwise) is present.
+   Inspired by Depth_First_Search_PP described in:
+
+     Advanced Compiler Design and Implementation
+     Steven Muchnick
+     Morgan Kaufmann, 1997
+
+   and heavily borrowed from flow_depth_first_order_compute.  */
+
+bool
+mark_dfs_back_edges ()
+{
+  edge *stack;
+  int *pre;
+  int *post;
+  int sp;
+  int prenum = 1;
+  int postnum = 1;
+  sbitmap visited;
+  bool found = false;
+
+  /* Allocate the preorder and postorder number arrays.  */
+  pre = (int *) xcalloc (n_basic_blocks, sizeof (int));
+  post = (int *) xcalloc (n_basic_blocks, sizeof (int));
+
+  /* Allocate stack for back-tracking up CFG.  */
+  stack = (edge *) xmalloc ((n_basic_blocks + 1) * sizeof (edge));
+  sp = 0;
+
+  /* Allocate bitmap to track nodes that have been visited.  */
+  visited = sbitmap_alloc (n_basic_blocks);
+
+  /* None of the nodes in the CFG have been visited yet.  */
+  sbitmap_zero (visited);
+
+  /* Push the first edge on to the stack.  */
+  stack[sp++] = ENTRY_BLOCK_PTR->succ;
+
+  while (sp)
+    {
+      edge e;
+      basic_block src;
+      basic_block dest;
+
+      /* Look at the edge on the top of the stack.  */
+      e = stack[sp - 1];
+      src = e->src;
+      dest = e->dest;
+      e->flags &= ~EDGE_DFS_BACK;
+
+      /* Check if the edge destination has been visited yet.  */
+      if (dest != EXIT_BLOCK_PTR && ! TEST_BIT (visited, dest->index))
+       {
+         /* Mark that we have visited the destination.  */
+         SET_BIT (visited, dest->index);
+
+         pre[dest->index] = prenum++;
+
+         if (dest->succ)
+           {
+             /* Since the DEST node has been visited for the first
+                time, check its successors.  */
+             stack[sp++] = dest->succ;
+           }
+         else
+           post[dest->index] = postnum++;
+       }
+      else
+       {
+         if (dest != EXIT_BLOCK_PTR && src != ENTRY_BLOCK_PTR
+             && pre[src->index] >= pre[dest->index]
+             && post[dest->index] == 0)
+           e->flags |= EDGE_DFS_BACK, found = true;
+
+         if (! e->succ_next && src != ENTRY_BLOCK_PTR)
+           post[src->index] = postnum++;
+
+         if (e->succ_next)
+           stack[sp - 1] = e->succ_next;
+         else
+           sp--;
+       }
+    }
+
+  free (pre);
+  free (post);
+  free (stack);
+  sbitmap_free (visited);
+
+  return found;
+}
+\f
 /* Split a block BB after insn INSN creating a new fallthru edge.
    Return the new edge.  Note that to keep other parts of the compiler happy,
    this function renumbers all the basic blocks so that the new
@@ -7779,7 +7872,7 @@ dump_edge_info (file, e, do_succ)
   if (e->flags)
     {
       static const char * const bitnames[] = {
-       "fallthru", "crit", "ab", "abcall", "eh", "fake"
+       "fallthru", "crit", "ab", "abcall", "eh", "fake", "dfs_back"
       };
       int comma = 0;
       int i, flags = e->flags;
index 4dec34e..a2284a0 100644 (file)
@@ -7226,7 +7226,8 @@ thread_prologue_and_epilogue_insns (f)
          inserted = 1;
        }
       else
-       emit_insn_after (seq, f);
+       set_block_for_new_insns (emit_insn_after (seq, f),
+                                ENTRY_BLOCK_PTR->succ);
     }
 #endif
 
index 38803b2..342477c 100644 (file)
@@ -194,8 +194,11 @@ typedef struct stack_def
 typedef struct block_info_def
 {
   struct stack_def stack_in;   /* Input stack configuration.  */
+  struct stack_def stack_out;  /* Output stack configuration.  */
   HARD_REG_SET out_reg_set;    /* Stack regs live on output.  */
   int done;                    /* True if block already converted.  */
+  int predecesors;             /* Number of predecesors that needs
+                                  to be visited.  */
 } *block_info;
 
 #define BLOCK_INFO(B)  ((block_info) (B)->aux)
@@ -263,6 +266,7 @@ static int convert_regs                     PARAMS ((FILE *));
 static void print_stack                PARAMS ((FILE *, stack));
 static rtx next_flags_user             PARAMS ((rtx));
 static void record_label_references    PARAMS ((rtx, rtx));
+static bool compensate_edge            PARAMS ((edge, FILE *));
 \f
 /* Return non-zero if any stack register is mentioned somewhere within PAT.  */
 
@@ -443,11 +447,20 @@ reg_to_stack (first, file)
     find_basic_blocks (first, max_reg_num (), file);
   count_or_remove_death_notes (NULL, 1);
   life_analysis (first, file, PROP_DEATH_NOTES);
+  mark_dfs_back_edges ();
 
   /* Set up block info for each basic block.  */
   bi = (block_info) xcalloc ((n_basic_blocks + 1), sizeof (*bi));
   for (i = n_basic_blocks - 1; i >= 0; --i)
-    BASIC_BLOCK (i)->aux = bi + i;
+    {
+      edge e;
+      basic_block bb = BASIC_BLOCK (i);
+      bb->aux = bi + i;
+      for (e = bb->pred; e; e=e->pred_next)
+       if (!(e->flags & EDGE_DFS_BACK)
+           && e->src != ENTRY_BLOCK_PTR)
+         BLOCK_INFO (bb)->predecesors++;
+    }
   EXIT_BLOCK_PTR->aux = bi + n_basic_blocks;
 
   /* Create the replacement registers up front.  */
@@ -2452,6 +2465,143 @@ convert_regs_exit ()
     }
 }
 
+/* Adjust the stack of this block on exit to match the stack of the
+   target block, or copy stack info into the stack of the successor
+   of the successor hasn't been processed yet.  */
+static bool
+compensate_edge (e, file)
+    edge e;
+    FILE *file;
+{
+  basic_block block = e->src, target = e->dest;
+  block_info bi = BLOCK_INFO (block);
+  struct stack_def regstack, tmpstack;
+  stack target_stack = &BLOCK_INFO (target)->stack_in;
+  int reg;
+
+  current_block = block;
+  regstack = bi->stack_out;
+  if (file)
+    fprintf (file, "Edge %d->%d: ", block->index, target->index);
+
+  if (target_stack->top == -2)
+    {
+      /* The target block hasn't had a stack order selected.
+         We need merely ensure that no pops are needed.  */
+      for (reg = regstack.top; reg >= 0; --reg)
+       if (!TEST_HARD_REG_BIT (target_stack->reg_set, regstack.reg[reg]))
+         break;
+
+      if (reg == -1)
+       {
+         if (file)
+           fprintf (file, "new block; copying stack position\n");
+
+         /* change_stack kills values in regstack.  */
+         tmpstack = regstack;
+
+         change_stack (block->end, &tmpstack, target_stack, EMIT_AFTER);
+          return false;
+       }
+
+      if (file)
+       fprintf (file, "new block; pops needed\n");
+    }
+  else
+    {
+      if (target_stack->top == regstack.top)
+       {
+         for (reg = target_stack->top; reg >= 0; --reg)
+           if (target_stack->reg[reg] != regstack.reg[reg])
+             break;
+
+         if (reg == -1)
+           {
+             if (file)
+               fprintf (file, "no changes needed\n");
+             return false;
+           }
+       }
+
+      if (file)
+       {
+         fprintf (file, "correcting stack to ");
+         print_stack (file, target_stack);
+       }
+    }
+
+  /* Care for non-call EH edges specially.  The normal return path have
+     values in registers.  These will be popped en masse by the unwind
+     library.  */
+  if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH)
+    target_stack->top = -1;
+
+  /* Other calls may appear to have values live in st(0), but the
+     abnormal return path will not have actually loaded the values.  */
+  else if (e->flags & EDGE_ABNORMAL_CALL)
+    {
+      /* Assert that the lifetimes are as we expect -- one value
+         live at st(0) on the end of the source block, and no
+         values live at the beginning of the destination block.  */
+      HARD_REG_SET tmp;
+
+      CLEAR_HARD_REG_SET (tmp);
+      GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1);
+      abort ();
+    eh1:
+
+      SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
+      GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
+      abort ();
+    eh2:
+
+      target_stack->top = -1;
+    }
+
+  /* It is better to output directly to the end of the block
+     instead of to the edge, because emit_swap can do minimal
+     insn scheduling.  We can do this when there is only one
+     edge out, and it is not abnormal.  */
+  else if (block->succ->succ_next == NULL && !(e->flags & EDGE_ABNORMAL))
+    {
+      /* change_stack kills values in regstack.  */
+      tmpstack = regstack;
+
+      change_stack (block->end, &tmpstack, target_stack,
+                   (GET_CODE (block->end) == JUMP_INSN
+                    ? EMIT_BEFORE : EMIT_AFTER));
+    }
+  else
+    {
+      rtx seq, after;
+
+      /* We don't support abnormal edges.  Global takes care to
+         avoid any live register across them, so we should never
+         have to insert instructions on such edges.  */
+      if (e->flags & EDGE_ABNORMAL)
+       abort ();
+
+      current_block = NULL;
+      start_sequence ();
+
+      /* ??? change_stack needs some point to emit insns after. 
+         Also needed to keep gen_sequence from returning a 
+         pattern as opposed to a sequence, which would lose
+         REG_DEAD notes.  */
+      after = emit_note (NULL, NOTE_INSN_DELETED);
+
+      tmpstack = regstack;
+      change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
+
+      seq = gen_sequence ();
+      end_sequence ();
+
+      insert_insn_on_edge (seq, e);
+      return true;
+    }
+  return false;
+}
+
 /* Convert stack register references in one block.  */
 
 static int
@@ -2459,14 +2609,48 @@ convert_regs_1 (file, block)
      FILE *file;
      basic_block block;
 {
-  struct stack_def regstack, tmpstack;
+  struct stack_def regstack;
   block_info bi = BLOCK_INFO (block);
   int inserted, reg;
   rtx insn, next;
-  edge e;
+  edge e, beste = NULL;
 
-  current_block = block;
+  inserted = 0;
+
+  /* Find the edge we will copy stack from.  It should be the most frequent
+     one as it will get cheapest after compensation code is generated,
+     if multiple such exists, take one with largest count, preffer critical
+     one (as splitting critical edges is more expensive), or one with lowest
+     index, to avoid random changes with different orders of the edges.  */
+  for (e = block->pred; e ; e = e->pred_next)
+    {
+      if (e->flags & EDGE_DFS_BACK)
+       ;
+      else if (! beste)
+       beste = e;
+      else if (EDGE_FREQUENCY (beste) < EDGE_FREQUENCY (e))
+       beste = e;
+      else if (beste->count < e->count)
+       beste = e;
+      else if (beste->count > e->count)
+       ;
+      else if ((e->flags & EDGE_CRITICAL) != (beste->flags & EDGE_CRITICAL))
+       {
+         if (e->flags & EDGE_CRITICAL)
+           beste = e;
+       }
+      else if (e->src->index < beste->src->index)
+       beste = e;
+    }
+
+  /* Entry block does have stack already initialized.  */
+  if (bi->stack_in.top == -2)
+    inserted |= compensate_edge (beste, file);
+  else
+    beste = NULL;
   
+  current_block = block;
+
   if (file)
     {
       fprintf (file, "\nBasic block %d\nInput stack: ", block->index);
@@ -2546,137 +2730,28 @@ convert_regs_1 (file, block)
   GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
   abort ();
  win:
+  bi->stack_out = regstack;
 
-  /* Adjust the stack of this block on exit to match the stack of the
-     target block, or copy stack info into the stack of the successor
-     of the successor hasn't been processed yet.  */
-  inserted = 0;
+  /* Compensate the back edges, as those wasn't visited yet.  */
   for (e = block->succ; e ; e = e->succ_next)
     {
-      basic_block target = e->dest;
-      stack target_stack = &BLOCK_INFO (target)->stack_in;
-
-      if (file)
-       fprintf (file, "Edge to block %d: ", target->index);
-
-      if (target_stack->top == -2)
-       {
-         /* The target block hasn't had a stack order selected.
-            We need merely ensure that no pops are needed.  */
-         for (reg = regstack.top; reg >= 0; --reg)
-           if (! TEST_HARD_REG_BIT (target_stack->reg_set,
-                                    regstack.reg[reg]))
-             break;
-
-         if (reg == -1)
-           {
-             if (file)
-               fprintf (file, "new block; copying stack position\n");
-
-             /* change_stack kills values in regstack.  */
-             tmpstack = regstack;
-
-             change_stack (block->end, &tmpstack,
-                           target_stack, EMIT_AFTER);
-             continue;
-           }
-
-         if (file)
-           fprintf (file, "new block; pops needed\n");
-       }
-      else
+      if (e->flags & EDGE_DFS_BACK
+         || (e->dest == EXIT_BLOCK_PTR))
        {
-         if (target_stack->top == regstack.top)
-           {
-             for (reg = target_stack->top; reg >= 0; --reg)
-               if (target_stack->reg[reg] != regstack.reg[reg])
-                 break;
-
-             if (reg == -1)
-               {
-                 if (file)
-                   fprintf (file, "no changes needed\n");
-                 continue;
-               }
-           }
-
-         if (file)
-           {
-             fprintf (file, "correcting stack to ");
-             print_stack (file, target_stack);
-           }
-       }
-
-      /* Care for non-call EH edges specially.  The normal return path have
-        values in registers.  These will be popped en masse by the unwind
-        library.  */
-      if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH)
-       target_stack->top = -1;
-
-      /* Other calls may appear to have values live in st(0), but the
-        abnormal return path will not have actually loaded the values.  */
-      else if (e->flags & EDGE_ABNORMAL_CALL)
-       {
-         /* Assert that the lifetimes are as we expect -- one value
-            live at st(0) on the end of the source block, and no
-            values live at the beginning of the destination block.  */
-         HARD_REG_SET tmp;
-
-         CLEAR_HARD_REG_SET (tmp);
-         GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1);
-         abort();
-       eh1:
-
-         SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
-         GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
-         abort();
-       eh2:
-
-         target_stack->top = -1;
-       }
-
-      /* It is better to output directly to the end of the block
-        instead of to the edge, because emit_swap can do minimal
-        insn scheduling.  We can do this when there is only one
-        edge out, and it is not abnormal.  */
-      else if (block->succ->succ_next == NULL
-              && ! (e->flags & EDGE_ABNORMAL))
-       {
-         /* change_stack kills values in regstack.  */
-         tmpstack = regstack;
-
-         change_stack (block->end, &tmpstack, target_stack,
-                       (GET_CODE (block->end) == JUMP_INSN
-                        ? EMIT_BEFORE : EMIT_AFTER));
+         if (!BLOCK_INFO (e->dest)->done
+             && e->dest != block)
+           abort ();
+          inserted |= compensate_edge (e, file);
        }
-      else
+    }
+  for (e = block->pred; e ; e = e->pred_next)
+    {
+      if (e != beste && !(e->flags & EDGE_DFS_BACK)
+         && e->src != ENTRY_BLOCK_PTR)
        {
-         rtx seq, after;
-
-         /* We don't support abnormal edges.  Global takes care to
-            avoid any live register across them, so we should never
-            have to insert instructions on such edges.  */
-         if (e->flags & EDGE_ABNORMAL)
+         if (!BLOCK_INFO (e->src)->done)
            abort ();
-
-         current_block = NULL;
-         start_sequence ();
-                 
-         /* ??? change_stack needs some point to emit insns after. 
-            Also needed to keep gen_sequence from returning a 
-            pattern as opposed to a sequence, which would lose
-            REG_DEAD notes.  */
-         after = emit_note (NULL, NOTE_INSN_DELETED);
-
-         tmpstack = regstack;
-         change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
-
-         seq = gen_sequence ();
-         end_sequence ();
-
-         insert_insn_on_edge (seq, e);
-         inserted = 1;
-         current_block = block;
+          inserted |= compensate_edge (e, file);
        }
     }
 
@@ -2697,7 +2772,6 @@ convert_regs_2 (file, block)
   sp = stack;
 
   *sp++ = block;
-  BLOCK_INFO (block)->done = 1;
 
   inserted = 0;
   do
@@ -2706,12 +2780,14 @@ convert_regs_2 (file, block)
 
       block = *--sp;
       inserted |= convert_regs_1 (file, block);
+      BLOCK_INFO (block)->done = 1;
 
       for (e = block->succ; e ; e = e->succ_next)
-       if (! BLOCK_INFO (e->dest)->done)
+       if (! (e->flags & EDGE_DFS_BACK))
          {
-           *sp++ = e->dest;
-           BLOCK_INFO (e->dest)->done = 1;
+           BLOCK_INFO (e->dest)->predecesors--;
+           if (!BLOCK_INFO (e->dest)->predecesors)
+              *sp++ = e->dest;
          }
     }
   while (sp != stack);
index 07de29b..f3b50d1 100644 (file)
@@ -3473,11 +3473,13 @@ rest_of_compilation (decl)
   verify_flow_info ();
 #endif
 
+  compute_bb_for_insn (get_max_uid ());
+
   /* If optimizing, then go ahead and split insns now.  */
   if (optimize > 0)
     split_all_insns (0);
 
-  cleanup_cfg (0);
+  cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
 
   /* On some machines, the prologue and epilogue code, or parts thereof,
      can be represented as RTL.  Doing so lets us schedule insns between
@@ -3485,8 +3487,6 @@ rest_of_compilation (decl)
      scheduling to operate in the epilogue.  */
   thread_prologue_and_epilogue_insns (insns);
 
-  compute_bb_for_insn (get_max_uid ());
-
   if (optimize)
     {
       cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_CROSSJUMP);