OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / gcse.c
index 771df43..00f0986 100644 (file)
@@ -190,16 +190,18 @@ along with GCC; see the file COPYING3.  If not see
 
    We perform the following steps:
 
-   1) Compute basic block information.
+   1) Compute table of places where registers are set.
 
-   2) Compute table of places where registers are set.
+   2) Perform copy/constant propagation.
 
-   3) Perform copy/constant propagation.
-
-   4) Perform global cse using lazy code motion if not optimizing
+   3) Perform global cse using lazy code motion if not optimizing
       for size, or code hoisting if we are.
 
-   5) Perform another pass of copy/constant propagation.
+   4) Perform another pass of copy/constant propagation.  Try to bypass
+      conditional jumps if the condition can be computed from a value of
+      an incoming edge.
+
+   5) Perform store motion.
 
    Two passes of copy/constant propagation are done because the first one
    enables more GCSE and the second one helps to clean up the copies that
@@ -212,6 +214,11 @@ along with GCC; see the file COPYING3.  If not see
    (set (pseudo-reg) (expression)).
    Function want_to_gcse_p says what these are.
 
+   In addition, expressions in REG_EQUAL notes are candidates for GXSE-ing.
+   This allows PRE to hoist expressions that are expressed in multiple insns,
+   such as comprex address calculations (e.g. for PIC code, or loads with a 
+   high part and as lowe part).
+
    PRE handles moving invariant expressions out of loops (by treating them as
    partially redundant).
 
@@ -235,9 +242,13 @@ along with GCC; see the file COPYING3.  If not see
    It was found doing copy propagation between each pass enables further
    substitutions.
 
+   This study was done before expressions in REG_EQUAL notes were added as
+   candidate expressions for optimization, and before the GIMPLE optimizers
+   were added.  Probably, multiple passes is even less efficient now than
+   at the time when the study was conducted.
+
    PRE is quite expensive in complicated functions because the DFA can take
-   a while to converge.  Hence we only perform one pass.  The parameter
-   max-gcse-passes can be modified if one wants to experiment.
+   a while to converge.  Hence we only perform one pass.
 
    **********************
 
@@ -661,11 +672,7 @@ static bool is_too_expensive (const char *);
 static int
 gcse_main (rtx f ATTRIBUTE_UNUSED)
 {
-  int changed, pass;
-  /* Bytes used at start of pass.  */
-  int initial_bytes_used;
-  /* Maximum number of bytes used by a pass.  */
-  int max_pass_bytes;
+  int changed;
   /* Point to release obstack data from for each pass.  */
   char *gcse_obstack_bottom;
 
@@ -697,6 +704,7 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
 
   /* 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
@@ -704,101 +712,86 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
 
      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.  */
+     information about memory sets when we build the hash tables.
+     
+     ??? Actually, we already know the information that compute_sets computes
+     because it is available from DF.  FIXME.  */
 
   alloc_reg_set_mem (max_gcse_regno);
   compute_sets ();
 
-  pass = 0;
-  initial_bytes_used = bytes_used;
-  max_pass_bytes = 0;
   gcse_obstack_bottom = GOBNEWVAR (char, 1);
-  changed = 1;
-  while (changed && pass < MAX_GCSE_PASSES)
-    {
-      changed = 0;
-      if (dump_file)
-       fprintf (dump_file, "GCSE pass %d\n\n", pass + 1);
-
-      /* Initialize bytes_used to the space for the pred/succ lists,
-        and the reg_set_table data.  */
-      bytes_used = initial_bytes_used;
+  changed = 0;
+  if (dump_file)
+    fprintf (dump_file, "GCSE pass\n\n");
 
-      /* Each pass may create new registers, so recalculate each time.  */
-      max_gcse_regno = max_reg_num ();
+  max_gcse_regno = max_reg_num ();
 
-      alloc_gcse_mem ();
+  alloc_gcse_mem ();
 
-      /* Don't allow constant propagation to modify jumps
-        during this pass.  */
-      if (dbg_cnt (cprop1))
-       {
-         timevar_push (TV_CPROP1);
-         changed = one_cprop_pass (pass + 1, false, false);
-         timevar_pop (TV_CPROP1);
-       }
+  /* Don't allow constant propagation to modify jumps
+     during this pass.  */
+  if (dbg_cnt (cprop1))
+    {
+      timevar_push (TV_CPROP1);
+      changed = one_cprop_pass (1, false, false);
+      timevar_pop (TV_CPROP1);
+    }
 
-      if (optimize_size)
-       /* Do nothing.  */ ;
-      else
+  if (optimize_function_for_speed_p (cfun))
+    {
+      timevar_push (TV_PRE);
+      changed |= one_pre_gcse_pass (1);
+      /* We may have just created new basic blocks.  Release and
+        recompute various things which are sized on the number of
+        basic blocks.
+        ??? There would be no need for this if we used a block
+        based Lazy Code Motion variant, with all (or selected)
+        edges split before running the pass.  That would also
+        help find_implicit_sets for cprop.  FIXME.  */
+      if (changed)
        {
-         timevar_push (TV_PRE);
-         changed |= one_pre_gcse_pass (pass + 1);
-         /* We may have just created new basic blocks.  Release and
-            recompute various things which are sized on the number of
-            basic blocks.  */
-         if (changed)
-           {
-             free_modify_mem_tables ();
-             modify_mem_list = GCNEWVEC (rtx, last_basic_block);
-             canon_modify_mem_list = GCNEWVEC (rtx, last_basic_block);
-           }
-         free_reg_set_mem ();
-         alloc_reg_set_mem (max_reg_num ());
-         compute_sets ();
-         run_jump_opt_after_gcse = 1;
-         timevar_pop (TV_PRE);
+         free_modify_mem_tables ();
+         modify_mem_list = GCNEWVEC (rtx, last_basic_block);
+         canon_modify_mem_list = GCNEWVEC (rtx, last_basic_block);
        }
 
-      if (max_pass_bytes < bytes_used)
-       max_pass_bytes = bytes_used;
-
-      /* Free up memory, then reallocate for code hoisting.  We can
-        not re-use the existing allocated memory because the tables
-        will not have info for the insns or registers created by
-        partial redundancy elimination.  */
-      free_gcse_mem ();
-
-      /* It does not make sense to run code hoisting unless we are optimizing
+      /* ??? When we allocate this at the start of the function,
+        the comment says that "this data is kept accurate during
+        each pass".  Apparently this is not so?  FIXME.  */
+      free_reg_set_mem ();
+      alloc_reg_set_mem (max_reg_num ());
+      compute_sets ();
+      run_jump_opt_after_gcse = 1;
+      timevar_pop (TV_PRE);
+    }
+  else
+    {
+      /* This function is being optimized for code size.
+        It does not make sense to run code hoisting unless we are optimizing
         for code size -- it rarely makes programs faster, and can make
         them bigger if we did partial redundancy elimination (when optimizing
         for space, we don't run the partial redundancy algorithms).  */
-      if (optimize_size)
-       {
-         timevar_push (TV_HOIST);
-         max_gcse_regno = max_reg_num ();
-         alloc_gcse_mem ();
-         changed |= one_code_hoisting_pass ();
-         free_gcse_mem ();
-
-         if (max_pass_bytes < bytes_used)
-           max_pass_bytes = bytes_used;
-         timevar_pop (TV_HOIST);
-       }
+      timevar_push (TV_HOIST);
+      max_gcse_regno = max_reg_num ();
+      alloc_gcse_mem ();
+      one_code_hoisting_pass ();
+      timevar_pop (TV_HOIST);
+    }
 
-      if (dump_file)
-       {
-         fprintf (dump_file, "\n");
-         fflush (dump_file);
-       }
+  free_gcse_mem ();
 
-      obstack_free (&gcse_obstack, gcse_obstack_bottom);
-      pass++;
+  if (dump_file)
+    {
+      fprintf (dump_file, "\n");
+      fflush (dump_file);
     }
 
-  /* Do one last pass of copy propagation, including cprop into
-     conditional jumps.  */
+  obstack_free (&gcse_obstack, gcse_obstack_bottom);
 
+  /* Do the second const/copy propagation pass, including cprop into
+     conditional jumps.  */
   if (dbg_cnt (cprop2))
     {
       max_gcse_regno = max_reg_num ();
@@ -806,7 +799,7 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
 
       /* This time, go ahead and allow cprop to alter jumps.  */
       timevar_push (TV_CPROP2);
-      one_cprop_pass (pass + 1, true, true);
+      one_cprop_pass (2, true, true);
       timevar_pop (TV_CPROP2);
       free_gcse_mem ();
     }
@@ -815,17 +808,18 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
     {
       fprintf (dump_file, "GCSE of %s: %d basic blocks, ",
               current_function_name (), n_basic_blocks);
-      fprintf (dump_file, "%d pass%s, %d bytes\n\n",
-              pass, pass > 1 ? "es" : "", max_pass_bytes);
+      fprintf (dump_file, "pass 1, %d bytes\n\n", bytes_used);
     }
 
   obstack_free (&gcse_obstack, NULL);
   free_reg_set_mem ();
 
-  /* We are finished with alias.  */
+  /* We are finished with alias.
+     ??? Actually we recompute alias in store_motion.  */
   end_alias_analysis ();
 
-  if (!optimize_size && flag_gcse_sm)
+  /* Run store motion.  */
+  if (optimize_function_for_speed_p (cfun) && flag_gcse_sm)
     {
       timevar_push (TV_LSM);
       store_motion ();
@@ -2791,7 +2785,7 @@ find_avail_set (int regno, rtx insn)
 static int
 cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
 {
-  rtx new, set_src, note_src;
+  rtx new_rtx, set_src, note_src;
   rtx set = pc_set (jump);
   rtx note = find_reg_equal_equiv_note (jump);
 
@@ -2823,22 +2817,22 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
   else
     setcc = NULL_RTX;
 
-  new = simplify_replace_rtx (set_src, from, src);
+  new_rtx = simplify_replace_rtx (set_src, from, src);
 
   /* If no simplification can be made, then try the next register.  */
-  if (rtx_equal_p (new, SET_SRC (set)))
+  if (rtx_equal_p (new_rtx, SET_SRC (set)))
     return 0;
 
   /* If this is now a no-op delete it, otherwise this must be a valid insn.  */
-  if (new == pc_rtx)
+  if (new_rtx == pc_rtx)
     delete_insn (jump);
   else
     {
       /* Ensure the value computed inside the jump insn to be equivalent
          to one computed by setcc.  */
-      if (setcc && modified_in_p (new, setcc))
+      if (setcc && modified_in_p (new_rtx, setcc))
        return 0;
-      if (! validate_unshare_change (jump, &SET_SRC (set), new, 0))
+      if (! validate_unshare_change (jump, &SET_SRC (set), new_rtx, 0))
        {
          /* When (some) constants are not valid in a comparison, and there
             are two registers to be replaced by constants before the entire
@@ -2849,8 +2843,8 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
             we need to attach a note to the branch itself to make this
             optimization work.  */
 
-         if (!rtx_equal_p (new, note_src))
-           set_unique_reg_note (jump, REG_EQUAL, copy_rtx (new));
+         if (!rtx_equal_p (new_rtx, note_src))
+           set_unique_reg_note (jump, REG_EQUAL, copy_rtx (new_rtx));
          return 0;
        }
 
@@ -2881,7 +2875,7 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src)
   /* If a conditional jump has been changed into unconditional jump, remove
      the jump and make the edge fallthru - this is always called in
      cfglayout mode.  */
-  if (new != pc_rtx && simplejump_p (jump))
+  if (new_rtx != pc_rtx && simplejump_p (jump))
     {
       edge e;
       edge_iterator ei;
@@ -3306,7 +3300,7 @@ find_implicit_sets (void)
 {
   basic_block bb, dest;
   unsigned int count;
-  rtx cond, new;
+  rtx cond, new_rtx;
 
   count = 0;
   FOR_EACH_BB (bb)
@@ -3327,9 +3321,9 @@ find_implicit_sets (void)
            if (dest && single_pred_p (dest)
                && dest != EXIT_BLOCK_PTR)
              {
-               new = gen_rtx_SET (VOIDmode, XEXP (cond, 0),
+               new_rtx = gen_rtx_SET (VOIDmode, XEXP (cond, 0),
                                             XEXP (cond, 1));
-               implicit_sets[dest->index] = new;
+               implicit_sets[dest->index] = new_rtx;
                if (dump_file)
                  {
                    fprintf(dump_file, "Implicit set of reg %d in ",
@@ -3539,7 +3533,7 @@ bypass_block (basic_block bb, rtx setcc, rtx jump)
          unsigned int regno = REGNO (reg_used->reg_rtx);
          basic_block dest, old_dest;
          struct expr *set;
-         rtx src, new;
+         rtx src, new_rtx;
 
          if (regno >= max_gcse_regno)
            continue;
@@ -3560,7 +3554,7 @@ bypass_block (basic_block bb, rtx setcc, rtx jump)
                                          SET_DEST (PATTERN (setcc)),
                                          SET_SRC (PATTERN (setcc)));
 
-         new = simplify_replace_rtx (src, reg_used->reg_rtx,
+         new_rtx = simplify_replace_rtx (src, reg_used->reg_rtx,
                                      SET_SRC (set->expr));
 
          /* Jump bypassing may have already placed instructions on
@@ -3568,14 +3562,14 @@ bypass_block (basic_block bb, rtx setcc, rtx jump)
             has instructions associated with it, as these insns won't
             get executed if the incoming edge is redirected.  */
 
-         if (new == pc_rtx)
+         if (new_rtx == pc_rtx)
            {
              edest = FALLTHRU_EDGE (bb);
              dest = edest->insns.r ? NULL : edest->dest;
            }
-         else if (GET_CODE (new) == LABEL_REF)
+         else if (GET_CODE (new_rtx) == LABEL_REF)
            {
-             dest = BLOCK_FOR_INSN (XEXP (new, 0));
+             dest = BLOCK_FOR_INSN (XEXP (new_rtx, 0));
              /* Don't bypass edges containing instructions.  */
              edest = find_edge (bb, dest);
              if (edest && edest->insns.r)
@@ -4336,7 +4330,7 @@ pre_insert_copies (void)
 static rtx
 gcse_emit_move_after (rtx src, rtx dest, rtx insn)
 {
-  rtx new;
+  rtx new_rtx;
   rtx set = single_set (insn), set2;
   rtx note;
   rtx eqv;
@@ -4344,20 +4338,20 @@ gcse_emit_move_after (rtx src, rtx dest, rtx insn)
   /* This should never fail since we're creating a reg->reg copy
      we've verified to be valid.  */
 
-  new = emit_insn_after (gen_move_insn (dest, src), insn);
+  new_rtx = emit_insn_after (gen_move_insn (dest, src), insn);
 
   /* Note the equivalence for local CSE pass.  */
-  set2 = single_set (new);
+  set2 = single_set (new_rtx);
   if (!set2 || !rtx_equal_p (SET_DEST (set2), dest))
-    return new;
+    return new_rtx;
   if ((note = find_reg_equal_equiv_note (insn)))
     eqv = XEXP (note, 0);
   else
     eqv = SET_SRC (set);
 
-  set_unique_reg_note (new, REG_EQUAL, copy_insn_1 (eqv));
+  set_unique_reg_note (new_rtx, REG_EQUAL, copy_insn_1 (eqv));
 
-  return new;
+  return new_rtx;
 }
 
 /* Delete redundant computations.
@@ -4562,9 +4556,8 @@ add_label_notes (rtx x, rtx insn)
         such a LABEL_REF, so we don't have to handle REG_LABEL_TARGET
         notes.  */
       gcc_assert (!JUMP_P (insn));
-      REG_NOTES (insn)
-       = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
-                            REG_NOTES (insn));
+      add_reg_note (insn, REG_LABEL_OPERAND, XEXP (x, 0));
+
       if (LABEL_P (XEXP (x, 0)))
        LABEL_NUSES (XEXP (x, 0))++;
 
@@ -5385,7 +5378,7 @@ update_ld_motion_stores (struct expr * expr)
          rtx pat = PATTERN (insn);
          rtx src = SET_SRC (pat);
          rtx reg = expr->reaching_reg;
-         rtx copy, new;
+         rtx copy, new_rtx;
 
          /* If we've already copied it, continue.  */
          if (expr->reaching_reg == src)
@@ -5401,8 +5394,8 @@ update_ld_motion_stores (struct expr * expr)
            }
 
          copy = gen_move_insn ( reg, copy_rtx (SET_SRC (pat)));
-         new = emit_insn_before (copy, insn);
-         record_one_set (REGNO (reg), new);
+         new_rtx = emit_insn_before (copy, insn);
+         record_one_set (REGNO (reg), new_rtx);
          SET_SRC (pat) = reg;
          df_insn_rescan (insn);
 
@@ -6533,7 +6526,7 @@ bypass_jumps (void)
 
   max_gcse_regno = max_reg_num ();
   alloc_gcse_mem ();
-  changed = one_cprop_pass (MAX_GCSE_PASSES + 2, true, true);
+  changed = one_cprop_pass (3, true, true);
   free_gcse_mem ();
 
   if (dump_file)
@@ -6624,7 +6617,7 @@ struct rtl_opt_pass pass_jump_bypass =
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   TV_BYPASS,                            /* tv_id */
-  0,                                    /* properties_required */
+  PROP_cfglayout,                       /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
@@ -6695,7 +6688,7 @@ struct rtl_opt_pass pass_gcse =
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   TV_GCSE,                              /* tv_id */
-  0,                                    /* properties_required */
+  PROP_cfglayout,                       /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */