OSDN Git Service

* flow.c (find_basic_blocks): Calc upper bound for extra nops in
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 8 Oct 1998 01:26:18 +0000 (01:26 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 8 Oct 1998 01:26:18 +0000 (01:26 +0000)
        max_uids_for_flow.
        (find_basic_blocks_1): Add a nop to the end of a basic block when
        a trailing call insn does not have abnormal control flow.
        * gcse.c (pre_transpout): New variable.
        (alloc_pre_mem, free_pre_mem, dump_pre_data): Bookkeeping for it.
        (compute_pre_transpout): Calculate it.
        (compute_pre_ppinout): Use it to eliminate impossible placements
        due to abnormal control flow through calls.
        (compute_pre_data): Call compute_pre_transpout.

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

gcc/ChangeLog
gcc/flow.c
gcc/gcse.c

index 74dab80..d7d8490 100644 (file)
@@ -1,3 +1,16 @@
+Thu Oct  8 01:25:22 1998  Richard Henderson  <rth@cygnus.com>
+
+       * flow.c (find_basic_blocks): Calc upper bound for extra nops in
+       max_uids_for_flow.
+       (find_basic_blocks_1): Add a nop to the end of a basic block when
+       a trailing call insn does not have abnormal control flow.
+       * gcse.c (pre_transpout): New variable.
+       (alloc_pre_mem, free_pre_mem, dump_pre_data): Bookkeeping for it.
+       (compute_pre_transpout): Calculate it.
+       (compute_pre_ppinout): Use it to eliminate impossible placements
+       due to abnormal control flow through calls.
+       (compute_pre_data): Call compute_pre_transpout.
+
 Wed Oct  7 21:40:24 1998  David S. Miller  <davem@pierdol.cobaltmicro.com>
 
        * config/sparc/sol2-sld-64.h (ASM_CPU_SPEC): Fix typo.
index d602436..773aaf2 100644 (file)
@@ -306,6 +306,7 @@ find_basic_blocks (f, nregs, file, live_reachable_p)
   register int i;
   rtx nonlocal_label_list = nonlocal_label_rtx_list ();
   int in_libcall_block = 0;
+  int extra_uids_for_flow = 0;
 
   /* Count the basic blocks.  Also find maximum insn uid value used.  */
 
@@ -318,7 +319,6 @@ find_basic_blocks (f, nregs, file, live_reachable_p)
 
     for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
       {
-
        /* Track when we are inside in LIBCALL block.  */
        if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
            && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
@@ -327,13 +327,33 @@ find_basic_blocks (f, nregs, file, live_reachable_p)
        code = GET_CODE (insn);
        if (INSN_UID (insn) > max_uid_for_flow)
          max_uid_for_flow = INSN_UID (insn);
-       if (code == CODE_LABEL
-           || (GET_RTX_CLASS (code) == 'i'
-               && (prev_code == JUMP_INSN
-                   || (prev_code == CALL_INSN
-                       && (nonlocal_label_list != 0 || eh_region))
-                   || prev_code == BARRIER)))
+       if (code == CODE_LABEL)
          i++;
+       else if (GET_RTX_CLASS (code) == 'i')
+         {
+           if (prev_code == JUMP_INSN || prev_code == BARRIER)
+             i++;
+           else if (prev_code == CALL_INSN)
+             {
+               if (nonlocal_label_list != 0 || eh_region)
+                 i++;
+               else
+                 {
+                   /* Else this call does not force a new block to be
+                      created.  However, it may still be the end of a basic
+                      block if it is followed by a CODE_LABEL or a BARRIER.
+
+                      To disambiguate calls which force new blocks to be
+                      created from those which just happen to be at the end
+                      of a block we insert nops during find_basic_blocks_1
+                      after calls which are the last insn in a block by
+                      chance.  We must account for such insns in
+                      max_uid_for_flow.  */
+
+                   extra_uids_for_flow++;
+                 }
+             }
+         }
 
        /* We change the code of the CALL_INSN, so that it won't start a
           new block.  */
@@ -360,6 +380,7 @@ find_basic_blocks (f, nregs, file, live_reachable_p)
      These cases are rare, so we don't need too much space.  */
   max_uid_for_flow += max_uid_for_flow / 10;
 #endif
+  max_uid_for_flow += extra_uids_for_flow;
 
   /* Allocate some tables that last till end of compiling this function
      and some needed only in find_basic_blocks and life_analysis.  */
@@ -410,6 +431,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
   int depth, pass;
   int in_libcall_block = 0;
   int deleted_handler = 0;
+  int call_had_abnormal_edge = 0;
 
   pass = 1;
   active_eh_region = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int));
@@ -456,8 +478,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
       else if (code == CODE_LABEL
               || (GET_RTX_CLASS (code) == 'i'
                   && (prev_code == JUMP_INSN
-                      || (prev_code == CALL_INSN
-                          && (nonlocal_label_list != 0 || eh_note))
+                      || (prev_code == CALL_INSN && call_had_abnormal_edge)
                       || prev_code == BARRIER)))
        {
          basic_block_head[++i] = insn;
@@ -466,12 +487,26 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
 
          if (code == CODE_LABEL)
            {
-               LABEL_REFS (insn) = insn;
-               /* Any label that cannot be deleted
-                  is considered to start a reachable block.  */
-               if (LABEL_PRESERVE_P (insn))
-                 block_live[i] = 1;
-             }
+             LABEL_REFS (insn) = insn;
+             /* Any label that cannot be deleted
+                is considered to start a reachable block.  */
+             if (LABEL_PRESERVE_P (insn))
+               block_live[i] = 1;
+           }
+
+         /* If the previous insn was a call that did not create an
+            abnormal edge, we want to add a nop so that the CALL_INSN
+            itself is not at basic_block_end.  This allows us to easily
+            distinguish between normal calls and those which create
+            abnormal edges in the flow graph.  */
+
+         if (i > 0 && !call_had_abnormal_edge
+             && GET_CODE (basic_block_end[i-1]) == CALL_INSN)
+           {
+             rtx nop = gen_rtx_USE (VOIDmode, const0_rtx);
+             nop = emit_insn_after (nop, basic_block_end[i-1]);
+             basic_block_end[i-1] = nop;
+           }
        }
 
       else if (GET_RTX_CLASS (code) == 'i')
@@ -524,6 +559,10 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
       if (code == CALL_INSN && in_libcall_block)
        code = INSN;
 
+      /* Record whether this call created an edge.  */
+      if (code == CALL_INSN)
+       call_had_abnormal_edge = (nonlocal_label_list != 0 || eh_note);
+
       if (code != NOTE)
        prev_code = code;
 
index c77aa33..0732cb4 100644 (file)
@@ -3888,6 +3888,11 @@ static sbitmap *pre_pavout;
 static sbitmap *pre_ppin;
 static sbitmap *pre_ppout;
 
+/* Nonzero for expressions that are transparent at the end of the block.
+   This is only zero for expressions killed by abnormal critical edge
+   created by a calls.  */
+static sbitmap *pre_transpout;
+
 /* Used while performing PRE to denote which insns are redundant.  */
 static sbitmap pre_redundant;
 
@@ -3910,6 +3915,8 @@ alloc_pre_mem (n_blocks, n_exprs)
   pre_pavout = sbitmap_vector_alloc (n_blocks, n_exprs);
   pre_ppin = sbitmap_vector_alloc (n_blocks, n_exprs);
   pre_ppout = sbitmap_vector_alloc (n_blocks, n_exprs);
+
+  pre_transpout = sbitmap_vector_alloc (n_blocks, n_exprs);
 }
 
 /* Free vars used for PRE analysis.  */
@@ -3920,7 +3927,6 @@ free_pre_mem ()
   free (pre_transp);
   free (pre_comp);
   free (pre_antloc);
-
   free (pre_avin);
   free (pre_avout);
   free (pre_antin);
@@ -3930,6 +3936,7 @@ free_pre_mem ()
   free (pre_pavout);
   free (pre_ppin);
   free (pre_ppout);
+  free (pre_transpout);
 }
 
 /* Dump PRE data.  */
@@ -3962,6 +3969,9 @@ dump_pre_data (file)
                       pre_ppin, n_basic_blocks);
   dump_sbitmap_vector (file, "PRE placement possible on outgoing", "BB",
                       pre_ppout, n_basic_blocks);
+
+  dump_sbitmap_vector (file, "PRE transparent on outgoing", "BB",
+                      pre_transpout, n_basic_blocks);
 }
 
 /* Compute the local properties of each recorded expression.
@@ -4129,6 +4139,57 @@ compute_pre_pavinout ()
     fprintf (gcse_file, "partially avail expr computation: %d passes\n", passes);
 }
 
+/* Compute transparent outgoing information for each block.
+
+   An expression is transparent to an edge unless it is killed by
+   the edge itself.  This can only happen with abnormal control flow,
+   when the edge is traversed through a call.  This happens with
+   non-local labels and exceptions.
+
+   This would not be necessary if we split the edge.  While this is
+   normally impossible for abnormal critical edges, with some effort
+   it should be possible with exception handling, since we still have
+   control over which handler should be invoked.  But due to increased
+   EH table sizes, this may not be worthwhile.  */
+
+static void
+compute_pre_transpout ()
+{
+  int bb;
+
+  sbitmap_vector_ones (pre_transpout, n_basic_blocks);
+
+  for (bb = 0; bb < n_basic_blocks; ++bb)
+    {
+      int i;
+
+      /* Note that flow inserted a nop a the end of basic blocks that
+        end in call instructions for reasons other than abnormal
+        control flow.  */
+      if (GET_CODE (BLOCK_END (bb)) != CALL_INSN)
+       continue;
+
+      for (i = 0; i < expr_hash_table_size; i++)
+       {
+         struct expr *expr;
+         for (expr = expr_hash_table[i]; expr ; expr = expr->next_same_hash)
+           if (GET_CODE (expr->expr) == MEM)
+             {
+               rtx addr = XEXP (expr->expr, 0);
+
+               if (GET_CODE (addr) == SYMBOL_REF
+                   && CONSTANT_POOL_ADDRESS_P (addr))
+                 continue;
+               
+               /* ??? Optimally, we would use interprocedural alias
+                  analysis to determine if this mem is actually killed
+                  by this call.  */
+               RESET_BIT (pre_transpout[bb], expr->bitmap_index);
+             }
+       }
+    }
+}   
+
 /* Compute "placement possible" information on entrance and exit of
    each block.
 
@@ -4209,11 +4270,12 @@ compute_pre_ppinout ()
       for (bb = 0; bb < n_basic_blocks - 1; bb++)
        {
          sbitmap_ptr ppout = pre_ppout[bb]->elms;
+         sbitmap_ptr transpout = pre_transpout[bb]->elms;
 
          for (i = 0; i < size; i++)
            {
              int_list_ptr succ;
-             SBITMAP_ELT_TYPE tmp = -1L;
+             SBITMAP_ELT_TYPE tmp = *transpout;
 
              for (succ = s_succs[bb]; succ != NULL; succ = succ->next)
                {
@@ -4226,13 +4288,14 @@ compute_pre_ppinout ()
                  ppin = pre_ppin[succ_bb]->elms + i;
                  tmp &= *ppin;
                }
+
              if (*ppout != tmp)
                {
                  changed = 1;
-                 *ppout++ = tmp;
+                 *ppout = tmp;
                }
-             else
-               ppout++;
+
+             ppout++; transpout++;
            }
        }
 
@@ -4252,6 +4315,7 @@ compute_pre_data ()
   compute_pre_avinout ();
   compute_pre_antinout ();
   compute_pre_pavinout ();
+  compute_pre_transpout ();
   compute_pre_ppinout ();
   if (gcse_file)
     fprintf (gcse_file, "\n");
@@ -4376,10 +4440,7 @@ pre_insert_insn (expr, bb)
     }
   /* Likewise if the last insn is a call, as will happen in the presence
      of exception handling.  */
-  /* ??? The flag_exceptions test is not exact.  We don't know if we are
-     actually in an eh region.  Fix flow to tell us this.  */
-  else if (GET_CODE (insn) == CALL_INSN
-          && (current_function_has_nonlocal_label || flag_exceptions))
+  else if (GET_CODE (insn) == CALL_INSN)
     {
       HARD_REG_SET parm_regs;
       int nparm_regs;
@@ -4409,7 +4470,7 @@ pre_insert_insn (expr, bb)
          {
            int regno = REGNO (XEXP (XEXP (p, 0), 0));
            if (regno >= FIRST_PSEUDO_REGISTER)
-             abort();
+             abort ();
            SET_HARD_REG_BIT (parm_regs, regno);
            nparm_regs++;
          }