OSDN Git Service

* timevar.c (getrusage): Don't ever declare if not HAVE_GETRUSAGE.
[pf3gnuchains/gcc-fork.git] / gcc / gcse.c
index 081275a..f25a4cf 100644 (file)
@@ -1,6 +1,6 @@
 /* Global common subexpression elimination/Partial redundancy elimination
    and global constant/copy propagation for GNU compiler.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -145,6 +145,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "toplev.h"
 
 #include "rtl.h"
@@ -612,7 +614,7 @@ static int load_killed_in_block_p    PARAMS ((basic_block, int, rtx, int));
 static void canon_list_insert        PARAMS ((rtx, rtx, void *));
 static int cprop_insn          PARAMS ((rtx, int));
 static int cprop               PARAMS ((int));
-static int one_cprop_pass      PARAMS ((int, int));
+static int one_cprop_pass      PARAMS ((int, int, int));
 static bool constprop_register PARAMS ((rtx, rtx, rtx, int));
 static struct expr *find_bypass_set PARAMS ((int, int));
 static int bypass_block                    PARAMS ((basic_block, rtx, rtx));
@@ -719,10 +721,6 @@ gcse_main (f, file)
   /* Point to release obstack data from for each pass.  */
   char *gcse_obstack_bottom;
 
-  /* Insertion of instructions on edges can create new basic blocks; we
-     need the original basic block count so that we can properly deallocate
-     arrays sized on the number of basic blocks originally in the cfg.  */
-  int orig_bb_count;
   /* We do not construct an accurate cfg in functions which call
      setjmp, so just punt to be safe.  */
   if (current_function_calls_setjmp)
@@ -742,7 +740,6 @@ gcse_main (f, file)
   if (file)
     dump_flow_info (file);
 
-  orig_bb_count = n_basic_blocks;
   /* Return if there's nothing to do.  */
   if (n_basic_blocks <= 1)
     return 0;
@@ -822,7 +819,7 @@ gcse_main (f, file)
 
       /* Don't allow constant propagation to modify jumps
         during this pass.  */
-      changed = one_cprop_pass (pass + 1, 0);
+      changed = one_cprop_pass (pass + 1, 0, 0);
 
       if (optimize_size)
        changed |= one_classic_gcse_pass (pass + 1);
@@ -841,7 +838,6 @@ gcse_main (f, file)
                = (rtx *) gmalloc (last_basic_block * sizeof (rtx));
              memset ((char *) modify_mem_list, 0, last_basic_block * sizeof (rtx));
              memset ((char *) canon_modify_mem_list, 0, last_basic_block * sizeof (rtx));
-             orig_bb_count = n_basic_blocks;
            }
          free_reg_set_mem ();
          alloc_reg_set_mem (max_reg_num ());
@@ -890,7 +886,7 @@ gcse_main (f, file)
   max_gcse_regno = max_reg_num ();
   alloc_gcse_mem (f);
   /* This time, go ahead and allow cprop to alter jumps.  */
-  one_cprop_pass (pass + 1, 1);
+  one_cprop_pass (pass + 1, 1, 0);
   free_gcse_mem ();
 
   if (file)
@@ -1264,7 +1260,7 @@ record_set_info (dest, setter, data)
 /* Scan the function and record each set of each pseudo-register.
 
    This is called once, at the start of the gcse pass.  See the comments for
-   `reg_set_table' for further documenation.  */
+   `reg_set_table' for further documentation.  */
 
 static void
 compute_sets (f)
@@ -1309,6 +1305,7 @@ want_to_gcse_p (x)
     case CONST_DOUBLE:
     case CONST_VECTOR:
     case CALL:
+    case CONSTANT_P_RTX:
       return 0;
 
     default:
@@ -1597,7 +1594,7 @@ hash_expr_1 (x, mode, do_not_record_p)
   const char *fmt;
 
   /* Used to turn recursion into iteration.  We can't rely on GCC's
-     tail-recursion eliminatio since we need to keep accumulating values
+     tail-recursion elimination since we need to keep accumulating values
      in HASH.  */
 
   if (x == 0)
@@ -2220,7 +2217,8 @@ hash_scan_set (pat, insn, table)
                    && REGNO (src) >= FIRST_PSEUDO_REGISTER
                    && can_copy_p [GET_MODE (dest)]
                    && REGNO (src) != regno)
-                  || CONSTANT_P (src))
+                  || (CONSTANT_P (src)
+                      && GET_CODE (src) != CONSTANT_P_RTX))
               /* A copy is not available if its src or dest is subsequently
                  modified.  Here we want to search from INSN+1 on, but
                  oprs_available_p searches from INSN on.  */
@@ -3956,7 +3954,7 @@ try_replace_reg (from, to, insn)
 
   /* REG_EQUAL may get simplified into register.
      We don't allow that. Remove that note. This code ought
-     not to hapen, because previous code ought to syntetize
+     not to happen, because previous code ought to synthesize
      reg-reg move, but be on the safe side.  */
   if (note && REG_P (XEXP (note, 0)))
     remove_note (insn, note);
@@ -4036,7 +4034,7 @@ find_avail_set (regno, insn)
 
 /* Subroutine of cprop_insn that tries to propagate constants into
    JUMP_INSNS.  JUMP must be a conditional jump.  If SETCC is non-NULL
-   it is the instruction that immediately preceeds JUMP, and must be a
+   it is the instruction that immediately precedes JUMP, and must be a
    single SET of a register.  FROM is what we will try to replace,
    SRC is the constant we will try to substitute for it.  Returns nonzero
    if a change was made.  */
@@ -4128,6 +4126,7 @@ constprop_register (insn, from, to, alter_jumps)
      conditional branch instructions first.  */
   if (alter_jumps
       && (sset = single_set (insn)) != NULL
+      && NEXT_INSN (insn)
       && any_condjump_p (NEXT_INSN (insn)) && onlyjump_p (NEXT_INSN (insn)))
     {
       rtx dest = SET_DEST (sset);
@@ -4251,6 +4250,7 @@ cprop_insn (insn, alter_jumps)
 
 /* LIBCALL_SP is a zero-terminated array of insns at the end of a libcall;
    their REG_EQUAL notes need updating.  */
+
 static bool
 do_local_cprop (x, insn, alter_jumps, libcall_sp)
      rtx x;
@@ -4260,10 +4260,12 @@ do_local_cprop (x, insn, alter_jumps, libcall_sp)
 {
   rtx newreg = NULL, newcnst = NULL;
 
-  /* Rule out USE instructions and ASM statements as we don't want to change the hard registers mentioned.  */
+  /* Rule out USE instructions and ASM statements as we don't want to
+     change the hard registers mentioned.  */
   if (GET_CODE (x) == REG
       && (REGNO (x) >= FIRST_PSEUDO_REGISTER
-          || (GET_CODE (PATTERN (insn)) != USE && asm_noperands (PATTERN (insn)) < 0)))
+          || (GET_CODE (PATTERN (insn)) != USE
+             && asm_noperands (PATTERN (insn)) < 0)))
     {
       cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
       struct elt_loc_list *l;
@@ -4275,7 +4277,11 @@ do_local_cprop (x, insn, alter_jumps, libcall_sp)
          rtx this_rtx = l->loc;
          rtx note;
 
-         if (CONSTANT_P (this_rtx))
+         if (l->in_libcall)
+           continue;
+
+         if (CONSTANT_P (this_rtx)
+             && GET_CODE (this_rtx) != CONSTANT_P_RTX)
            newcnst = this_rtx;
          if (REG_P (this_rtx) && REGNO (this_rtx) >= FIRST_PSEUDO_REGISTER
              /* Don't copy propagate if it has attached REG_EQUIV note.
@@ -4290,7 +4296,7 @@ do_local_cprop (x, insn, alter_jumps, libcall_sp)
       if (newcnst && constprop_register (insn, x, newcnst, alter_jumps))
        {
          /* If we find a case where we can't fix the retval REG_EQUAL notes
-            match the new register, we either have to abandom this replacement
+            match the new register, we either have to abandon this replacement
             or fix delete_trivially_dead_insns to preserve the setting insn,
             or make it delete the REG_EUAQL note, and fix up all passes that
             require the REG_EQUAL note there.  */
@@ -4373,6 +4379,7 @@ local_cprop_pass (alter_jumps)
   rtx insn;
   struct reg_use *reg_used;
   rtx libcall_stack[MAX_NESTED_LIBCALLS + 1], *libcall_sp;
+  bool changed = false;
 
   cselib_init ();
   libcall_sp = &libcall_stack[MAX_NESTED_LIBCALLS];
@@ -4404,13 +4411,24 @@ local_cprop_pass (alter_jumps)
                   reg_used++, reg_use_count--)
                if (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps,
                    libcall_sp))
-                 break;
+                 {
+                   changed = true;
+                   break;
+                 }
            }
          while (reg_use_count);
        }
       cselib_process_insn (insn);
     }
   cselib_finish ();
+  /* Global analysis may get into infinite loops for unreachable blocks.  */
+  if (changed && alter_jumps)
+    {
+      delete_unreachable_blocks ();
+      free_reg_set_mem ();
+      alloc_reg_set_mem (max_reg_num ());
+      compute_sets (get_insns ());
+    }
 }
 
 /* Forward propagate copies.  This includes copies and constants.  Return
@@ -4461,20 +4479,22 @@ cprop (alter_jumps)
 }
 
 /* Perform one copy/constant propagation pass.
-   F is the first insn in the function.
-   PASS is the pass count.  */
+   PASS is the pass count.  If CPROP_JUMPS is true, perform constant
+   propagation into conditional jumps.  If BYPASS_JUMPS is true,
+   perform conditional jump bypassing optimizations.  */
 
 static int
-one_cprop_pass (pass, alter_jumps)
+one_cprop_pass (pass, cprop_jumps, bypass_jumps)
      int pass;
-     int alter_jumps;
+     int cprop_jumps;
+     int bypass_jumps;
 {
   int changed = 0;
 
   const_prop_count = 0;
   copy_prop_count = 0;
 
-  local_cprop_pass (alter_jumps);
+  local_cprop_pass (cprop_jumps);
 
   alloc_hash_table (max_cuid, &set_hash_table, 1);
   compute_hash_table (&set_hash_table);
@@ -4484,8 +4504,8 @@ one_cprop_pass (pass, alter_jumps)
     {
       alloc_cprop_mem (last_basic_block, set_hash_table.n_elems);
       compute_cprop_data ();
-      changed = cprop (alter_jumps);
-      if (alter_jumps)
+      changed = cprop (cprop_jumps);
+      if (bypass_jumps)
        changed |= bypass_conditional_jumps ();
       free_cprop_mem ();
     }
@@ -4499,12 +4519,22 @@ one_cprop_pass (pass, alter_jumps)
       fprintf (gcse_file, "%d const props, %d copy props\n\n",
               const_prop_count, copy_prop_count);
     }
+  /* Global analysis may get into infinite loops for unreachable blocks.  */
+  if (changed && cprop_jumps)
+    delete_unreachable_blocks ();
 
   return changed;
 }
 \f
 /* Bypass conditional jumps.  */
 
+/* The value of last_basic_block at the beginning of the jump_bypass
+   pass.  The use of redirect_edge_and_branch_force may introduce new
+   basic blocks, but the data flow analysis is only valid for basic
+   block indices less than bypass_last_basic_block.  */
+
+static int bypass_last_basic_block;
+
 /* Find a set of REGNO to a constant that is available at the end of basic
    block BB.  Returns NULL if no such set is found.  Based heavily upon
    find_avail_set.  */
@@ -4575,6 +4605,13 @@ bypass_block (bb, setcc, jump)
   for (e = bb->pred; e; e = enext)
     {
       enext = e->pred_next;
+      if (e->flags & EDGE_COMPLEX)
+       continue;
+
+      /* We can't redirect edges from new basic blocks.  */
+      if (e->src->index >= bypass_last_basic_block)
+       continue;
+
       for (i = 0; i < reg_use_count; i++)
        {
          struct reg_use *reg_used = &reg_use_table[i];
@@ -4608,12 +4645,13 @@ bypass_block (bb, setcc, jump)
          else
            dest = NULL;
 
-         /* Once basic block indices are stable, we should be able
-            to use redirect_edge_and_branch_force instead.  */
          old_dest = e->dest;
-         if (dest != NULL && dest != old_dest
-             && redirect_edge_and_branch (e, dest))
-           {
+         if (dest != NULL
+             && dest != old_dest
+             && dest != EXIT_BLOCK_PTR)
+            {
+             redirect_edge_and_branch_force (e, dest);
+
              /* Copy the register setter to the redirected edge.
                 Don't copy CC0 setters, as CC0 is dead after jump.  */
              if (setcc)
@@ -4657,6 +4695,8 @@ bypass_conditional_jumps ()
   if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR)
     return 0;
 
+  bypass_last_basic_block = last_basic_block;
+
   changed = 0;
   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb->next_bb,
                  EXIT_BLOCK_PTR, next_bb)
@@ -4693,7 +4733,7 @@ bypass_conditional_jumps ()
     }
 
   /* If we bypassed any register setting insns, we inserted a
-     copy on the redirected edge.  These need to be commited.  */
+     copy on the redirected edge.  These need to be committed.  */
   if (changed)
     commit_edge_insertions();
 
@@ -5035,7 +5075,7 @@ insert_insn_end_bb (expr, bb, pre)
       /* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers,
         we search backward and place the instructions before the first
         parameter is loaded.  Do this for everyone for consistency and a
-        presumtion that we'll get better code elsewhere as well.
+        presumption that we'll get better code elsewhere as well.
 
         It should always be the case that we can put these instructions
         anywhere in the basic block with performing PRE optimizations.
@@ -5291,7 +5331,7 @@ gcse_emit_move_after (src, dest, insn)
   else
     eqv = SET_SRC (set);
 
-  set_unique_reg_note (new, REG_EQUAL, copy_insn_1 (src));
+  set_unique_reg_note (new, REG_EQUAL, copy_insn_1 (eqv));
 
   return new;
 }
@@ -5680,7 +5720,7 @@ delete_null_pointer_checks_1 (block_reg, nonnull_avin,
     }
 
   /* Now compute global properties based on the local properties.   This
-     is a classic global availablity algorithm.  */
+     is a classic global availability algorithm.  */
   compute_available (nonnull_local, nonnull_killed,
                     nonnull_avout, nonnull_avin);
 
@@ -5761,7 +5801,7 @@ delete_null_pointer_checks_1 (block_reg, nonnull_avin,
    reference of that form, then we know the register can not have the value
    zero at the conditional branch.
 
-   So we merely need to compute the local properies and propagate that data
+   So we merely need to compute the local properties and propagate that data
    around the cfg, then optimize where possible.
 
    We run this pass two times.  Once before CSE, then again after CSE.  This
@@ -6943,7 +6983,7 @@ store_killed_after (x, insn, bb)
      Note that if registers are changed ANYWHERE in the block, we'll
      decide we can't move it, regardless of whether it changed above
      or below the store. This could be improved by checking the register
-     operands while lookinng for aliasing in each insn.  */
+     operands while looking for aliasing in each insn.  */
   if (!store_ops_ok (XEXP (x, 0), bb))
     return 1;
 
@@ -6970,7 +7010,7 @@ store_killed_before (x, insn, bb)
      Note that if registers are changed ANYWHERE in the block, we'll
      decide we can't move it, regardless of whether it changed above
      or below the store. This could be improved by checking the register
-     operands while lookinng for aliasing in each insn.  */
+     operands while looking for aliasing in each insn.  */
   if (!store_ops_ok (XEXP (x, 0), bb))
     return 1;
 
@@ -7016,7 +7056,7 @@ build_store_vectors ()
 
          if (!store_killed_after (ptr->pattern, insn, bb))
            {
-             /* If we've already seen an availale expression in this block,
+             /* If we've already seen an available expression in this block,
                 we can delete the one we saw already (It occurs earlier in
                 the block), and replace it with this one). We'll copy the
                 old SRC expression to an unused register in case there
@@ -7080,7 +7120,7 @@ build_store_vectors ()
              Load in the middle here if we push the store down. It happens in
                    gcc.c-torture/execute/960311-1.c with -O3
              If we always kill it in this case, we'll sometimes do
-             uneccessary work, but it shouldn't actually hurt anything.
+             unnecessary work, but it shouldn't actually hurt anything.
            if (!TEST_BIT (ae_gen[b], ptr->index)).  */
            SET_BIT (ae_kill[b->index], ptr->index);
          }
@@ -7103,7 +7143,7 @@ build_store_vectors ()
     }
 }
 
-/* Insert an instruction at the begining of a basic block, and update
+/* Insert an instruction at the beginning of a basic block, and update
    the BLOCK_HEAD if needed.  */
 
 static void
@@ -7346,4 +7386,109 @@ store_motion ()
   end_alias_analysis ();
 }
 
+\f
+/* Entry point for jump bypassing optimization pass.  */
+
+int
+bypass_jumps (file)
+     FILE *file;
+{
+  int changed;
+
+  /* We do not construct an accurate cfg in functions which call
+     setjmp, so just punt to be safe.  */
+  if (current_function_calls_setjmp)
+    return 0;
+
+  /* For calling dump_foo fns from gdb.  */
+  debug_stderr = stderr;
+  gcse_file = file;
+
+  /* Identify the basic block information for this function, including
+     successors and predecessors.  */
+  max_gcse_regno = max_reg_num ();
+
+  if (file)
+    dump_flow_info (file);
+
+  /* Return if there's nothing to do.  */
+  if (n_basic_blocks <= 1)
+    return 0;
+
+  /* Trying to perform global optimizations on flow graphs which have
+     a high connectivity will take a long time and is unlikely to be
+     particularly useful.
+
+     In normal circumstances a cfg should have about twice as many edges
+     as blocks.  But we do not want to punish small functions which have
+     a couple switch statements.  So we require a relatively large number
+     of basic blocks and the ratio of edges to blocks to be high.  */
+  if (n_basic_blocks > 1000 && n_edges / n_basic_blocks >= 20)
+    {
+      if (warn_disabled_optimization)
+        warning ("BYPASS disabled: %d > 1000 basic blocks and %d >= 20 edges/basic block",
+                 n_basic_blocks, n_edges / n_basic_blocks);
+      return 0;
+    }
+
+  /* If allocating memory for the cprop bitmap would take up too much
+     storage it's better just to disable the optimization.  */
+  if ((n_basic_blocks
+       * SBITMAP_SET_SIZE (max_gcse_regno)
+       * sizeof (SBITMAP_ELT_TYPE)) > MAX_GCSE_MEMORY)
+    {
+      if (warn_disabled_optimization)
+        warning ("GCSE disabled: %d basic blocks and %d registers",
+                 n_basic_blocks, max_gcse_regno);
+
+      return 0;
+    }
+
+  /* See what modes support reg/reg copy operations.  */
+  if (! can_copy_init_p)
+    {
+      compute_can_copy ();
+      can_copy_init_p = 1;
+    }
+
+  gcc_obstack_init (&gcse_obstack);
+  bytes_used = 0;
+
+  /* We need alias.  */
+  init_alias_analysis ();
+
+  /* Record where pseudo-registers are set.  This data is kept accurate
+     during each pass.  ??? We could also record hard-reg information here
+     [since it's unchanging], however it is currently done during hash table
+     computation.
+
+     It may be tempting to compute MEM set information here too, but MEM sets
+     will be subject to code motion one day and thus we need to compute
+     information about memory sets when we build the hash tables.  */
+
+  alloc_reg_set_mem (max_gcse_regno);
+  compute_sets (get_insns ());
+
+  max_gcse_regno = max_reg_num ();
+  alloc_gcse_mem (get_insns ());
+  changed = one_cprop_pass (1, 1, 1);
+  free_gcse_mem ();
+
+  if (file)
+    {
+      fprintf (file, "BYPASS of %s: %d basic blocks, ",
+              current_function_name, n_basic_blocks);
+      fprintf (file, "%d bytes\n\n", bytes_used);
+    }
+
+  obstack_free (&gcse_obstack, NULL);
+  free_reg_set_mem ();
+
+  /* We are finished with alias.  */
+  end_alias_analysis ();
+  allocate_reg_info (max_reg_num (), FALSE, FALSE);
+
+  return changed;
+}
+
 #include "gt-gcse.h"