re PR rtl-optimization/62078 (ICE: verify_flow_info failed: missing REG_EH_REGION...
[gcc.git] / gcc / dse.c
index 7b4260a3eec0cf7c09c3b75bc684d97bada57a9a..ea6f24585c532abe24944f75023d4f7ac975275e 100644 (file)
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -1,5 +1,5 @@
 /* RTL dead store elimination.
-   Copyright (C) 2005-2014 Free Software Foundation, Inc.
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
 
    Contributed by Richard Sandiford <rsandifor@codesourcery.com>
    and Kenneth Zadeck <zadeck@naturalbridge.com>
@@ -28,21 +28,48 @@ along with GCC; see the file COPYING3.  If not see
 #include "hash-table.h"
 #include "tm.h"
 #include "rtl.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "real.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "stor-layout.h"
 #include "tm_p.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "regset.h"
 #include "flags.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "predict.h"
+#include "basic-block.h"
 #include "df.h"
 #include "cselib.h"
 #include "tree-pass.h"
 #include "alloc-pool.h"
-#include "alias.h"
 #include "insn-config.h"
+#include "hashtab.h"
+#include "function.h"
+#include "statistics.h"
+#include "fixed-value.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
 #include "recog.h"
+#include "insn-codes.h"
 #include "optabs.h"
 #include "dbgcnt.h"
 #include "target.h"
@@ -53,6 +80,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "is-a.h"
 #include "gimple.h"
 #include "gimple-ssa.h"
+#include "rtl-iter.h"
+#include "cfgcleanup.h"
 
 /* This file contains three techniques for performing Dead Store
    Elimination (dse).
@@ -364,9 +393,11 @@ struct insn_info
        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.  */
+     This field is set after reload for const function calls and before
+     reload for const tail function calls on targets where arg pointer
+     is the frame pointer.  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.
@@ -420,7 +451,7 @@ static alloc_pool insn_info_pool;
 static insn_info_t active_local_stores;
 static int active_local_stores_len;
 
-struct bb_info
+struct dse_bb_info
 {
 
   /* Pointer to the insn info for the last insn in the block.  These
@@ -478,7 +509,7 @@ struct bb_info
   bitmap regs_live;
 };
 
-typedef struct bb_info *bb_info_t;
+typedef struct dse_bb_info *bb_info_t;
 static alloc_pool bb_info_pool;
 
 /* Table to hold all bb_infos.  */
@@ -588,7 +619,7 @@ static htab_t clear_alias_mode_table;
 struct clear_alias_mode_holder
 {
   alias_set_type alias_set;
-  enum machine_mode mode;
+  machine_mode mode;
 };
 
 /* This is true except if cfun->stdarg -- i.e. we cannot do
@@ -756,7 +787,7 @@ dse_step0 (void)
                         sizeof (struct insn_info), 100);
   bb_info_pool
     = create_alloc_pool ("bb_info_pool",
-                        sizeof (struct bb_info), 100);
+                        sizeof (struct dse_bb_info), 100);
   rtx_group_info_pool
     = create_alloc_pool ("rtx_group_info_pool",
                         sizeof (struct group_info), 100);
@@ -811,7 +842,7 @@ free_store_info (insn_info_t insn_info)
 
 typedef struct
 {
-  rtx first, current;
+  rtx_insn *first, *current;
   regset fixed_regs_live;
   bool failure;
 } note_add_store_info;
@@ -822,7 +853,7 @@ typedef struct
 static void
 note_add_store (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *data)
 {
-  rtx insn;
+  rtx_insn *insn;
   note_add_store_info *info = (note_add_store_info *) data;
   int r, n;
 
@@ -863,7 +894,7 @@ emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
                          rtx dest, rtx src, rtx srcoff, void *arg)
 {
   insn_info_t insn_info = (insn_info_t) arg;
-  rtx insn = insn_info->insn, new_insn, cur;
+  rtx_insn *insn = insn_info->insn, *new_insn, *cur;
   note_add_store_info info;
 
   /* We can reuse all operands without copying, because we are about
@@ -876,7 +907,7 @@ emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
       end_sequence ();
     }
   else
-    new_insn = gen_move_insn (dest, src);
+    new_insn = as_a <rtx_insn *> (gen_move_insn (dest, src));
   info.first = new_insn;
   info.fixed_regs_live = insn_info->fixed_regs_live;
   info.failure = false;
@@ -893,7 +924,7 @@ emit_inc_dec_insn_before (rtx mem ATTRIBUTE_UNUSED,
 
   emit_insn_before (new_insn, insn);
 
-  return -1;
+  return 0;
 }
 
 /* Before we delete INSN_INFO->INSN, make sure that the auto inc/dec, if it
@@ -906,7 +937,8 @@ check_for_inc_dec_1 (insn_info_t insn_info)
   rtx_insn *insn = insn_info->insn;
   rtx note = find_reg_note (insn, REG_INC, NULL_RTX);
   if (note)
-    return for_each_inc_dec (&insn, emit_inc_dec_insn_before, insn_info) == 0;
+    return for_each_inc_dec (PATTERN (insn), emit_inc_dec_insn_before,
+                            insn_info) == 0;
   return true;
 }
 
@@ -925,7 +957,8 @@ check_for_inc_dec (rtx_insn *insn)
   insn_info.fixed_regs_live = NULL;
   note = find_reg_note (insn, REG_INC, NULL_RTX);
   if (note)
-    return for_each_inc_dec (&insn, emit_inc_dec_insn_before, &insn_info) == 0;
+    return for_each_inc_dec (PATTERN (insn), emit_inc_dec_insn_before,
+                            &insn_info) == 0;
   return true;
 }
 
@@ -1165,7 +1198,7 @@ canon_address (rtx mem,
               HOST_WIDE_INT *offset,
               cselib_val **base)
 {
-  enum machine_mode address_mode = get_address_mode (mem);
+  machine_mode address_mode = get_address_mode (mem);
   rtx mem_address = XEXP (mem, 0);
   rtx expanded_address, address;
   int expanded;
@@ -1356,7 +1389,7 @@ all_positions_needed_p (store_info_t s_info, int start, int width)
 }
 
 
-static rtx get_stored_val (store_info_t, enum machine_mode, HOST_WIDE_INT,
+static rtx get_stored_val (store_info_t, machine_mode, HOST_WIDE_INT,
                           HOST_WIDE_INT, basic_block, bool);
 
 
@@ -1720,11 +1753,11 @@ dump_insn_info (const char * start, insn_info_t insn_info)
 static rtx
 find_shift_sequence (int access_size,
                     store_info_t store_info,
-                    enum machine_mode read_mode,
+                    machine_mode read_mode,
                     int shift, bool speed, bool require_cst)
 {
-  enum machine_mode store_mode = GET_MODE (store_info->mem);
-  enum machine_mode new_mode;
+  machine_mode store_mode = GET_MODE (store_info->mem);
+  machine_mode new_mode;
   rtx read_reg = NULL;
 
   /* Some machines like the x86 have shift insns for each size of
@@ -1739,7 +1772,8 @@ find_shift_sequence (int access_size,
        GET_MODE_BITSIZE (new_mode) <= BITS_PER_WORD;
        new_mode = GET_MODE_WIDER_MODE (new_mode))
     {
-      rtx target, new_reg, shift_seq, insn, new_lhs;
+      rtx target, new_reg, new_lhs;
+      rtx_insn *shift_seq, *insn;
       int cost;
 
       /* If a constant was stored into memory, try to simplify it here,
@@ -1853,11 +1887,11 @@ look_for_hardregs (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
    if not successful.  If REQUIRE_CST is true, return always constant.  */
 
 static rtx
-get_stored_val (store_info_t store_info, enum machine_mode read_mode,
+get_stored_val (store_info_t store_info, machine_mode read_mode,
                HOST_WIDE_INT read_begin, HOST_WIDE_INT read_end,
                basic_block bb, bool require_cst)
 {
-  enum machine_mode store_mode = GET_MODE (store_info->mem);
+  machine_mode store_mode = GET_MODE (store_info->mem);
   int shift;
   int access_size; /* In bytes.  */
   rtx read_reg;
@@ -1957,9 +1991,10 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
              read_info_t read_info, insn_info_t read_insn, rtx *loc,
              bitmap regs_live)
 {
-  enum machine_mode store_mode = GET_MODE (store_info->mem);
-  enum machine_mode read_mode = GET_MODE (read_info->mem);
-  rtx insns, this_insn, read_reg;
+  machine_mode store_mode = GET_MODE (store_info->mem);
+  machine_mode read_mode = GET_MODE (read_info->mem);
+  rtx_insn *insns, *this_insn;
+  rtx read_reg;
   basic_block bb;
 
   if (!dbg_cnt (dse))
@@ -2087,15 +2122,13 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
     }
 }
 
-/* A for_each_rtx callback in which DATA is the bb_info.  Check to see
-   if LOC is a mem and if it is look at the address and kill any
-   appropriate stores that may be active.  */
+/* Check the address of MEM *LOC and kill any appropriate stores that may
+   be active.  */
 
-static int
-check_mem_read_rtx (rtx *loc, void *data)
+static void
+check_mem_read_rtx (rtx *loc, bb_info_t bb_info)
 {
   rtx mem = *loc, mem_addr;
-  bb_info_t bb_info;
   insn_info_t insn_info;
   HOST_WIDE_INT offset = 0;
   HOST_WIDE_INT width = 0;
@@ -2104,10 +2137,6 @@ check_mem_read_rtx (rtx *loc, void *data)
   int group_id;
   read_info_t read_info;
 
-  if (!mem || !MEM_P (mem))
-    return 0;
-
-  bb_info = (bb_info_t) data;
   insn_info = bb_info->last_insn;
 
   if ((MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
@@ -2117,20 +2146,20 @@ check_mem_read_rtx (rtx *loc, void *data)
        fprintf (dump_file, " adding wild read, volatile or barrier.\n");
       add_wild_read (bb_info);
       insn_info->cannot_delete = true;
-      return 0;
+      return;
     }
 
   /* If it is reading readonly mem, then there can be no conflict with
      another write. */
   if (MEM_READONLY_P (mem))
-    return 0;
+    return;
 
   if (!canon_address (mem, &spill_alias_set, &group_id, &offset, &base))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, " adding wild read, canon_address failure.\n");
       add_wild_read (bb_info);
-      return 0;
+      return;
     }
 
   if (GET_MODE (mem) == BLKmode)
@@ -2258,7 +2287,7 @@ check_mem_read_rtx (rtx *loc, void *data)
                                                 width)
                      && replace_read (store_info, i_ptr, read_info,
                                       insn_info, loc, bb_info->regs_live))
-                   return 0;
+                   return;
 
                  /* The bases are the same, just see if the offsets
                     overlap.  */
@@ -2325,7 +2354,7 @@ check_mem_read_rtx (rtx *loc, void *data)
                                         offset - store_info->begin, width)
              && replace_read (store_info, i_ptr,  read_info, insn_info, loc,
                               bb_info->regs_live))
-           return 0;
+           return;
 
          if (!store_info->alias_set)
            remove = canon_true_dependence (store_info->mem,
@@ -2349,17 +2378,22 @@ check_mem_read_rtx (rtx *loc, void *data)
          i_ptr = i_ptr->next_local_store;
        }
     }
-  return 0;
 }
 
-/* A for_each_rtx callback in which DATA points the INSN_INFO for
+/* A note_uses callback in which DATA points the INSN_INFO for
    as check_mem_read_rtx.  Nullify the pointer if i_m_r_m_r returns
    true for any part of *LOC.  */
 
 static void
 check_mem_read_use (rtx *loc, void *data)
 {
-  for_each_rtx (loc, check_mem_read_rtx, data);
+  subrtx_ptr_iterator::array_type array;
+  FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
+    {
+      rtx *loc = *iter;
+      if (MEM_P (*loc))
+       check_mem_read_rtx (loc, (bb_info_t) data);
+    }
 }
 
 
@@ -2382,7 +2416,7 @@ get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
        arg != void_list_node && idx < nargs;
        arg = TREE_CHAIN (arg), idx++)
     {
-      enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
+      machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
       rtx reg, link, tmp;
       reg = targetm.calls.function_arg (args_so_far, mode, NULL_TREE, true);
       if (!reg || !REG_P (reg) || GET_MODE (reg) != mode
@@ -2506,7 +2540,13 @@ scan_insn (bb_info_t bb_info, rtx_insn *insn)
                     const_call ? "const" : "memset", INSN_UID (insn));
 
          /* See the head comment of the frame_read field.  */
-         if (reload_completed)
+         if (reload_completed
+             /* Tail calls are storing their arguments using
+                arg pointer.  If it is a frame pointer on the target,
+                even before reload we need to kill frame pointer based
+                stores.  */
+             || (SIBLING_CALL_P (insn)
+                 && HARD_FRAME_POINTER_IS_ARG_POINTER))
            insn_info->frame_read = true;
 
          /* Loop over the active stores and remove those which are
@@ -2580,7 +2620,11 @@ scan_insn (bb_info_t bb_info, rtx_insn *insn)
                }
            }
        }
-
+      else if (SIBLING_CALL_P (insn) && reload_completed)
+       /* Arguments for a sibling call that are pushed to memory are passed
+          using the incoming argument pointer of the current function.  After
+          reload that might be (and likely is) frame pointer based.  */
+       add_wild_read (bb_info);
       else
        /* Every other call, including pure functions, may read any memory
            that is not relative to the frame.  */
@@ -2696,7 +2740,7 @@ dse_step1 (void)
       insn_info_t ptr;
       bb_info_t bb_info = (bb_info_t) pool_alloc (bb_info_pool);
 
-      memset (bb_info, 0, sizeof (struct bb_info));
+      memset (bb_info, 0, sizeof (struct dse_bb_info));
       bitmap_set_bit (all_blocks, bb->index);
       bb_info->regs_live = regs_live;
 
@@ -3703,6 +3747,14 @@ rest_of_handle_dse (void)
   if (dump_file)
     fprintf (dump_file, "dse: local deletions = %d, global deletions = %d, spill deletions = %d\n",
             locally_deleted, globally_deleted, spill_deleted);
+
+  /* DSE can eliminate potentially-trapping MEMs.
+     Remove any EH edges associated with them.  */
+  if ((locally_deleted || globally_deleted)
+      && cfun->can_throw_non_call_exceptions
+      && purge_all_dead_edges ())
+    cleanup_cfg (0);
+
   return 0;
 }