OSDN Git Service

* unwind-generic.h: Fix comment typos.
[pf3gnuchains/gcc-fork.git] / gcc / dse.c
index a957783..2b86018 100644 (file)
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -284,12 +284,29 @@ struct insn_info
      contains a wild read, the use_rec will be null.  */
   bool wild_read;
 
-  /* This field is set for const function calls.  Const functions
-     cannot read memory, but they can read the stack because that is
-     where they may get their parms.  So having this set is less
-     severe than a wild read, it just means that all of the stores to
-     the stack are killed rather than all stores.  */
-  bool stack_read;
+  /* This field is only used for the processing of const functions.
+     These functions cannot read memory, but they can read the stack
+     because that is where they may get their parms.  We need to be
+     this conservative because, like the store motion pass, we don't
+     consider CALL_INSN_FUNCTION_USAGE when processing call insns.
+     Moreover, we need to distinguish two cases:
+     1. Before reload (register elimination), the stores related to
+       outgoing arguments are stack pointer based and thus deemed
+       of non-constant base in this pass.  This requires special
+       handling but also means that the frame pointer based stores
+       need not be killed upon encountering a const function call.
+     2. After reload, the stores related to outgoing arguments can be
+       either stack pointer or hard frame pointer based.  This means
+       that we have no other choice than also killing all the frame
+       pointer based stores upon encountering a const function call.
+     This field is set after reload for const function calls.  Having
+     this set is less severe than a wild read, it just means that all
+     the frame related stores are killed rather than all the stores.  */
+  bool frame_read;
+
+  /* This field is only used for the processing of const functions.
+     It is set if the insn may contain a stack pointer based store.  */
+  bool stack_pointer_based;
 
   /* This is true if any of the sets within the store contains a
      cselib base.  Such stores can only be deleted by the local
@@ -941,8 +958,9 @@ add_wild_read (bb_info_t bb_info)
 }
 
 
-/* Return true if X is a constant or one of the registers that behaves
-   as a constant over the life of a function.  */
+/* Return true if X is a constant or one of the registers that behave
+   as a constant over the life of a function.  This is equivalent to
+   !rtx_varies_p for memory addresses.  */
 
 static bool
 const_or_frame_p (rtx x)
@@ -1245,8 +1263,15 @@ record_store (rtx body, bb_info_t bb_info)
     }
   else
     {
-      store_info = pool_alloc (cse_store_info_pool);
+      rtx base_term = find_base_term (XEXP (mem, 0));
+      if (!base_term
+         || (GET_CODE (base_term) == ADDRESS
+             && GET_MODE (base_term) == Pmode
+             && XEXP (base_term, 0) == stack_pointer_rtx))
+       insn_info->stack_pointer_based = true;
       insn_info->contains_cselib_groups = true;
+
+      store_info = pool_alloc (cse_store_info_pool);
       group_id = -1;
 
       if (dump_file)
@@ -1399,6 +1424,7 @@ find_shift_sequence (rtx read_reg,
 {
   enum machine_mode store_mode = GET_MODE (store_info->mem);
   enum machine_mode read_mode = GET_MODE (read_info->mem);
+  rtx chosen_seq = NULL;
 
   /* Some machines like the x86 have shift insns for each size of
      operand.  Other machines like the ppc or the ia-64 may only have
@@ -1409,8 +1435,9 @@ find_shift_sequence (rtx read_reg,
 
   for (; access_size <= UNITS_PER_WORD; access_size *= 2)
     {
-      rtx target, new_reg;
+      rtx target, new_reg, shift_seq, insn;
       enum machine_mode new_mode;
+      int cost;
 
       /* Try a wider mode if truncating the store mode to ACCESS_SIZE
         bytes requires a real instruction.  */
@@ -1420,7 +1447,7 @@ find_shift_sequence (rtx read_reg,
        continue;
 
       new_mode = smallest_mode_for_size (access_size * BITS_PER_UNIT,
-                                        GET_MODE_CLASS (read_mode));
+                                        MODE_INT);
       new_reg = gen_reg_rtx (new_mode);
 
       start_sequence ();
@@ -1431,67 +1458,56 @@ find_shift_sequence (rtx read_reg,
       target = expand_binop (new_mode, lshr_optab, new_reg,
                             GEN_INT (shift), new_reg, 1, OPTAB_DIRECT);
 
-      if (target == new_reg)
-       {
-         rtx shift_seq = get_insns ();
-         end_sequence ();
+      shift_seq = get_insns ();
+      end_sequence ();
 
-         /* If cost is too great, set target to NULL and
-            let the iteration happen. */
-         if (shift_seq != NULL)
-           {
-             int cost = 0;
-             rtx insn;
-
-             for (insn = shift_seq; insn != NULL_RTX; insn = NEXT_INSN (insn))
-               if (INSN_P (insn))
-                 cost += insn_rtx_cost (PATTERN (insn));
-
-             /* The computation up to here is essentially independent
-                of the arguments and could be precomputed.  It may
-                not be worth doing so.  We could precompute if
-                worthwhile or at least cache the results.  The result
-                technically depends on SHIFT, ACCESS_SIZE, and
-                GET_MODE_CLASS (READ_MODE).  But in practice the
-                answer will depend only on ACCESS_SIZE.  */
-
-             if (cost <= COSTS_N_INSNS (1))
-               {
-                 /* We found an acceptable shift.  Generate a move to
-                    take the value from the store and put it into the
-                    shift pseudo, then shift it, then generate another
-                    move to put in into the target of the read.  */
-                 start_sequence ();
-                 emit_move_insn (new_reg, gen_lowpart (new_mode, store_info->rhs));
-                 emit_insn (shift_seq);
-                 convert_move (read_reg, new_reg, 1);
+      if (target != new_reg || shift_seq == NULL)
+       continue;
+
+      cost = 0;
+      for (insn = shift_seq; insn != NULL_RTX; insn = NEXT_INSN (insn))
+       if (INSN_P (insn))
+         cost += insn_rtx_cost (PATTERN (insn));
+
+      /* The computation up to here is essentially independent
+        of the arguments and could be precomputed.  It may
+        not be worth doing so.  We could precompute if
+        worthwhile or at least cache the results.  The result
+        technically depends on both SHIFT and ACCESS_SIZE,
+        but in practice the answer will depend only on ACCESS_SIZE.  */
+
+      if (cost > COSTS_N_INSNS (1))
+       continue;
+
+      /* We found an acceptable shift.  Generate a move to
+        take the value from the store and put it into the
+        shift pseudo, then shift it, then generate another
+        move to put in into the target of the read.  */
+      start_sequence ();
+      emit_move_insn (new_reg, gen_lowpart (new_mode, store_info->rhs));
+      emit_insn (shift_seq);
+      convert_move (read_reg, new_reg, 1);
                  
-                 if (dump_file)
-                   {
-                     fprintf (dump_file, " -- adding extract insn r%d:%s = r%d:%s\n",
-                              REGNO (new_reg), GET_MODE_NAME (new_mode),
-                              REGNO (store_info->rhs), GET_MODE_NAME (store_mode));
+      if (dump_file)
+       {
+         fprintf (dump_file, " -- adding extract insn r%d:%s = r%d:%s\n",
+                  REGNO (new_reg), GET_MODE_NAME (new_mode),
+                  REGNO (store_info->rhs), GET_MODE_NAME (store_mode));
                      
-                     fprintf (dump_file, " -- with shift of r%d by %d\n",
-                              REGNO(new_reg), shift);
-                     fprintf (dump_file, " -- and second extract insn r%d:%s = r%d:%s\n",
-                              REGNO (read_reg), GET_MODE_NAME (read_mode),
-                              REGNO (new_reg), GET_MODE_NAME (new_mode));
-                   }
-                 
-                 /* Get the three insn sequence and return it.  */
-                 shift_seq = get_insns ();
-                 end_sequence ();
-                 return shift_seq;
-               }
-           }
+         fprintf (dump_file, " -- with shift of r%d by %d\n",
+                  REGNO(new_reg), shift);
+         fprintf (dump_file, " -- and second extract insn r%d:%s = r%d:%s\n",
+                  REGNO (read_reg), GET_MODE_NAME (read_mode),
+                  REGNO (new_reg), GET_MODE_NAME (new_mode));
        }
-      else
-       /* End the sequence.  */
-       end_sequence ();
+                 
+      /* Get the three insn sequence and return it.  */
+      chosen_seq = get_insns ();
+      end_sequence ();
+      break;
     }
 
-  return NULL;
+  return chosen_seq;
 }
 
 
@@ -1540,7 +1556,8 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
   if (!dbg_cnt (dse))
     return false;
 
-  if (GET_MODE_CLASS (read_mode) != GET_MODE_CLASS (store_mode))
+  if (GET_MODE_CLASS (read_mode) != MODE_INT
+      || GET_MODE_CLASS (store_mode) != MODE_INT)
     return false;
 
   /* To get here the read is within the boundaries of the write so
@@ -1563,7 +1580,7 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
      call to get rid of the read.  */
   if (shift)
     {
-      if (access_size > UNITS_PER_WORD || FLOAT_MODE_P (store_mode))
+      if (access_size > UNITS_PER_WORD)
        return false;
 
       shift_seq = find_shift_sequence (read_reg, access_size, store_info,
@@ -1956,9 +1973,10 @@ scan_insn (bb_info_t bb_info, rtx insn)
   if (CALL_P (insn))
     {
       insn_info->cannot_delete = true;
+
       /* Const functions cannot do anything bad i.e. read memory,
-        however, they can read their parameters which may have been
-        pushed onto the stack.  */
+        however, they can read their parameters which may have
+        been pushed onto the stack.  */
       if (CONST_OR_PURE_CALL_P (insn) && !pure_call_p (insn))
        {
          insn_info_t i_ptr = active_local_stores;
@@ -1967,17 +1985,36 @@ scan_insn (bb_info_t bb_info, rtx insn)
          if (dump_file)
            fprintf (dump_file, "const call %d\n", INSN_UID (insn));
 
+         /* See the head comment of the frame_read field.  */
+         if (reload_completed)
+           insn_info->frame_read = true;
+
+         /* Loop over the active stores and remove those which are
+            killed by the const function call.  */
          while (i_ptr)
            {
-             store_info_t store_info = i_ptr->store_rec;
+             bool remove_store = false;
 
-             /* Skip the clobbers.  */
-             while (!store_info->is_set)
-               store_info = store_info->next;
+             /* The stack pointer based stores are always killed.  */
+             if (i_ptr->stack_pointer_based)
+               remove_store = true;
+
+             /* If the frame is read, the frame related stores are killed.  */
+             else if (insn_info->frame_read)
+               {
+                 store_info_t store_info = i_ptr->store_rec;
+
+                 /* Skip the clobbers.  */
+                 while (!store_info->is_set)
+                   store_info = store_info->next;
 
-             /* Remove the frame related stores.  */
-             if (store_info->group_id >= 0
-                 && VEC_index (group_info_t, rtx_group_vec, store_info->group_id)->frame_related)
+                 if (store_info->group_id >= 0
+                     && VEC_index (group_info_t, rtx_group_vec,
+                                   store_info->group_id)->frame_related)
+                   remove_store = true;
+               }
+
+             if (remove_store)
                {
                  if (dump_file)
                    dump_insn_info ("removing from active", i_ptr);
@@ -1989,23 +2026,22 @@ scan_insn (bb_info_t bb_info, rtx insn)
                }
              else
                last = i_ptr;
+
              i_ptr = i_ptr->next_local_store;
            }
-
-         insn_info->stack_read = true;
-         
-         return;
        }
 
-      /* Every other call, including pure functions may read memory.  */
-      add_wild_read (bb_info);
+      else
+       /* Every other call, including pure functions, may read memory.  */
+       add_wild_read (bb_info);
+
       return;
     }
 
   /* Assuming that there are sets in these insns, we cannot delete
      them.  */
   if ((GET_CODE (PATTERN (insn)) == CLOBBER)
-      || volatile_insn_p (PATTERN (insn))
+      || volatile_refs_p (PATTERN (insn))
       || (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
       || (RTX_FRAME_RELATED_P (insn))
       || find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX))
@@ -2500,8 +2536,8 @@ scan_reads_nospill (insn_info_t insn_info, bitmap gen, bitmap kill)
   int i;
   group_info_t group;
 
-  /* For const function calls kill the stack related stores.  */
-  if (insn_info->stack_read)
+  /* If this insn reads the frame, kill all the frame related stores.  */
+  if (insn_info->frame_read)
     {
       for (i = 0; VEC_iterate (group_info_t, rtx_group_vec, i, group); i++)
        if (group->process_globally && group->frame_related)