re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / shrink-wrap.c
index af23f0288d74730e11351915df91bd61f88fbaff..51c0e7bfd71ca0efab1c580aa2635f5cf0a7e306 100644 (file)
@@ -1,5 +1,5 @@
 /* Shrink-wrapping related optimizations.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,22 +24,32 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl-error.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "stor-layout.h"
 #include "varasm.h"
 #include "stringpool.h"
 #include "flags.h"
 #include "except.h"
+#include "hard-reg-set.h"
 #include "function.h"
+#include "rtl.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
 #include "expr.h"
+#include "insn-codes.h"
 #include "optabs.h"
 #include "libfuncs.h"
 #include "regs.h"
-#include "hard-reg-set.h"
-#include "insn-config.h"
 #include "recog.h"
 #include "output.h"
-#include "hashtab.h"
 #include "tm_p.h"
 #include "langhooks.h"
 #include "target.h"
@@ -48,6 +58,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "tree-pass.h"
 #include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "basic-block.h"
 #include "df.h"
 #include "params.h"
 #include "bb-reorder.h"
@@ -55,7 +69,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "regcprop.h"
 #include "rtl-iter.h"
 
-#ifdef HAVE_simple_return
 
 /* Return true if INSN requires the stack frame to be set up.
    PROLOGUE_USED contains the hard registers used in the function
@@ -176,47 +189,94 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
   basic_block next_block;
   edge live_edge;
 
-  /* Look for a simple register copy.  */
-  set = single_set (insn);
-  if (!set)
+  /* Look for a simple register assignment.  We don't use single_set here
+     because we can't deal with any CLOBBERs, USEs, or REG_UNUSED secondary
+     destinations.  */
+  if (!INSN_P (insn))
+    return false;
+  set = PATTERN (insn);
+  if (GET_CODE (set) != SET)
     return false;
   src = SET_SRC (set);
   dest = SET_DEST (set);
 
-  if (!REG_P (src))
+  /* For the destination, we want only a register.  Also disallow STACK
+     or FRAME related adjustments.  They are likely part of the prologue,
+     so keep them in the entry block.  */
+  if (!REG_P (dest)
+      || dest == stack_pointer_rtx
+      || dest == frame_pointer_rtx
+      || dest == hard_frame_pointer_rtx)
+    return false;
+
+  /* For the source, we want one of:
+      (1) A (non-overlapping) register
+      (2) A constant,
+      (3) An expression involving no more than one register.
+
+     That last point comes from the code following, which was originally
+     written to handle only register move operations, and still only handles
+     a single source register when checking for overlaps.  Happily, the
+     same checks can be applied to expressions like (plus reg const).  */
+
+  if (CONSTANT_P (src))
+    ;
+  else if (!REG_P (src))
     {
-      unsigned int reg_num = 0;
-      unsigned int nonconstobj_num = 0;
       rtx src_inner = NULL_RTX;
 
+      if (can_throw_internal (insn))
+       return false;
+
       subrtx_var_iterator::array_type array;
       FOR_EACH_SUBRTX_VAR (iter, array, src, ALL)
        {
          rtx x = *iter;
-         if (REG_P (x))
+         switch (GET_RTX_CLASS (GET_CODE (x)))
            {
-             reg_num++;
-             src_inner = x;
+           case RTX_CONST_OBJ:
+           case RTX_COMPARE:
+           case RTX_COMM_COMPARE:
+           case RTX_BIN_ARITH:
+           case RTX_COMM_ARITH:
+           case RTX_UNARY:
+           case RTX_TERNARY:
+             /* Constant or expression.  Continue.  */
+             break;
+
+           case RTX_OBJ:
+           case RTX_EXTRA:
+             switch (GET_CODE (x))
+               {
+               case UNSPEC:
+               case SUBREG:
+               case STRICT_LOW_PART:
+               case PC:
+               case LO_SUM:
+                 /* Ok.  Continue.  */
+                 break;
+
+               case REG:
+                 /* Fail if we see a second inner register.  */
+                 if (src_inner != NULL)
+                   return false;
+                 src_inner = x;
+                 break;
+
+               default:
+                 return false;
+               }
+             break;
+
+           default:
+             return false;
            }
-         else if (!CONSTANT_P (x) && OBJECT_P (x))
-           nonconstobj_num++;
        }
 
-      if (nonconstobj_num > 0
-         || reg_num > 1)
-       src = NULL_RTX;
-      else if (reg_num == 1)
+      if (src_inner != NULL)
        src = src_inner;
     }
 
-  if (!REG_P (dest) || src == NULL_RTX
-      /* STACK or FRAME related adjustment might be part of prologue.
-        So keep them in the entry block.  */
-      || dest == stack_pointer_rtx
-      || dest == frame_pointer_rtx
-      || dest == hard_frame_pointer_rtx)
-    return false;
-
   /* Make sure that the source register isn't defined later in BB.  */
   if (REG_P (src))
     {
@@ -250,16 +310,21 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
       if (!df_live)
        return false;
 
+      basic_block old_dest = live_edge->dest;
       next_block = split_edge (live_edge);
 
       /* We create a new basic block.  Call df_grow_bb_info to make sure
         all data structures are allocated.  */
       df_grow_bb_info (df_live);
-      bitmap_copy (df_get_live_in (next_block), df_get_live_out (bb));
+
+      bitmap_and (df_get_live_in (next_block), df_get_live_out (bb),
+                 df_get_live_in (old_dest));
       df_set_bb_dirty (next_block);
 
       /* We should not split more than once for a function.  */
-      gcc_assert (!(*split_p));
+      if (*split_p)
+       return false;
+
       *split_p = true;
     }
 
@@ -476,7 +541,7 @@ try_shrink_wrapping (edge *entry_edge, edge orig_entry_edge,
        break;
       }
 
-  if (flag_shrink_wrap && HAVE_simple_return
+  if (SHRINK_WRAPPING_ENABLED
       && (targetm.profile_before_prologue () || !crtl->profile)
       && nonempty_prologue && !crtl->calls_eh_return)
     {
@@ -528,7 +593,8 @@ try_shrink_wrapping (edge *entry_edge, edge orig_entry_edge,
       if (frame_pointer_needed)
        add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
                             HARD_FRAME_POINTER_REGNUM);
-      if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+      if (pic_offset_table_rtx 
+         && (unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
        add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
                             PIC_OFFSET_TABLE_REGNUM);
       if (crtl->drap_reg)
@@ -741,7 +807,6 @@ try_shrink_wrapping (edge *entry_edge, edge orig_entry_edge,
            FOR_EACH_BB_REVERSE_FN (bb, cfun)
              {
                basic_block copy_bb, tbb;
-               rtx_insn *insert_point;
                int eflags;
 
                if (!bitmap_clear_bit (&bb_tail, bb->index))
@@ -771,8 +836,8 @@ try_shrink_wrapping (edge *entry_edge, edge orig_entry_edge,
                    BB_COPY_PARTITION (copy_bb, bb);
                  }
 
-               insert_point = emit_note_after (NOTE_INSN_DELETED,
-                                               BB_END (copy_bb));
+               rtx_note *insert_point = emit_note_after (NOTE_INSN_DELETED,
+                                                         BB_END (copy_bb));
                emit_barrier_after (BB_END (copy_bb));
 
                tbb = bb;
@@ -936,12 +1001,11 @@ convert_to_simple_return (edge entry_edge, edge orig_entry_edge,
          else if (*pdest_bb == NULL)
            {
              basic_block bb;
-             rtx_insn *start;
 
              bb = create_basic_block (NULL, NULL, exit_pred);
              BB_COPY_PARTITION (bb, e->src);
-             start = emit_jump_insn_after (gen_simple_return (),
-                                           BB_END (bb));
+             rtx_insn *ret = targetm.gen_simple_return ();
+             rtx_jump_insn *start = emit_jump_insn_after (ret, BB_END (bb));
              JUMP_LABEL (start) = simple_return_rtx;
              emit_barrier_after (start);
 
@@ -965,5 +1029,3 @@ convert_to_simple_return (edge entry_edge, edge orig_entry_edge,
          }
     }
 }
-
-#endif