re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / valtrack.c
index b5c4913f54dc8d04f9ee75949bb31dffd3eb576b..80a0043196935469449731f367bafe5201420b8a 100644 (file)
@@ -1,6 +1,6 @@
 /* Infrastructure for tracking user variable locations and values
    throughout compilation.
-   Copyright (C) 2010-2014 Free Software Foundation, Inc.
+   Copyright (C) 2010-2015 Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>.
 
 This file is part of GCC.
@@ -24,7 +24,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "predict.h"
+#include "basic-block.h"
 #include "valtrack.h"
+#include "hard-reg-set.h"
 #include "function.h"
 #include "regs.h"
 #include "emit-rtl.h"
@@ -34,7 +37,7 @@ along with GCC; see the file COPYING3.  If not see
    instructions.  */
 
 static rtx
-gen_lowpart_for_debug (enum machine_mode mode, rtx x)
+gen_lowpart_for_debug (machine_mode mode, rtx x)
 {
   rtx result = gen_lowpart_if_possible (mode, x);
   if (result)
@@ -51,7 +54,7 @@ gen_lowpart_for_debug (enum machine_mode mode, rtx x)
    the same addresses without modifying the corresponding registers.  */
 
 static rtx
-cleanup_auto_inc_dec (rtx src, enum machine_mode mem_mode ATTRIBUTE_UNUSED)
+cleanup_auto_inc_dec (rtx src, machine_mode mem_mode ATTRIBUTE_UNUSED)
 {
   rtx x = src;
 #ifdef AUTO_INC_DEC
@@ -177,11 +180,12 @@ propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
    of THIS_BASIC_BLOCK.  */
 
 void
-propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src,
+propagate_for_debug (rtx_insn *insn, rtx_insn *last, rtx dest, rtx src,
                     basic_block this_basic_block)
 {
-  rtx next, loc, end = NEXT_INSN (BB_END (this_basic_block));
-  rtx (*saved_rtl_hook_no_emit) (enum machine_mode, rtx);
+  rtx_insn *next, *end = NEXT_INSN (BB_END (this_basic_block));
+  rtx loc;
+  rtx (*saved_rtl_hook_no_emit) (machine_mode, rtx);
 
   struct rtx_subst_pair p;
   p.to = src;
@@ -343,7 +347,7 @@ dead_debug_reset_uses (struct dead_debug_local *debug,
   while (head)
     {
       struct dead_debug_use *next = head->next;
-      rtx insn;
+      rtx_insn *insn;
 
       insn = DF_REF_INSN (head->use);
       if (!next || DF_REF_INSN (next->use) != insn)
@@ -431,7 +435,7 @@ dead_debug_promote_uses (struct dead_debug_local *debug)
                                                 REGNO (reg),
                                                 &debug->to_rescan))
              {
-               rtx insn = DF_REF_INSN (ref);
+               rtx_insn *insn = DF_REF_INSN (ref);
                INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
                bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
              }
@@ -447,7 +451,7 @@ dead_debug_promote_uses (struct dead_debug_local *debug)
                                         DEBUG_EXPR_TREE_DECL (entry->dtemp),
                                         gen_rtx_UNKNOWN_VAR_LOC (),
                                         VAR_INIT_STATUS_INITIALIZED);
-           rtx insn = emit_debug_insn_before (bind, DF_REF_INSN (ref));
+           rtx_insn *insn = emit_debug_insn_before (bind, DF_REF_INSN (ref));
            bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
          }
 
@@ -525,6 +529,22 @@ dead_debug_add (struct dead_debug_local *debug, df_ref use, unsigned int uregno)
   bitmap_set_bit (debug->used, uregno);
 }
 
+/* Like lowpart_subreg, but if a subreg is not valid for machine, force
+   it anyway - for use in debug insns.  */
+
+static rtx
+debug_lowpart_subreg (machine_mode outer_mode, rtx expr,
+                     machine_mode inner_mode)
+{
+  if (inner_mode == VOIDmode)
+    inner_mode = GET_MODE (expr);
+  int offset = subreg_lowpart_offset (outer_mode, inner_mode);
+  rtx ret = simplify_gen_subreg (outer_mode, expr, inner_mode, offset);
+  if (ret)
+    return ret;
+  return gen_rtx_raw_SUBREG (outer_mode, expr, offset);
+}
+
 /* If UREGNO is referenced by any entry in DEBUG, emit a debug insn
    before or after INSN (depending on WHERE), that binds a (possibly
    global) debug temp to the widest-mode use of UREGNO, if WHERE is
@@ -535,7 +555,7 @@ dead_debug_add (struct dead_debug_local *debug, df_ref use, unsigned int uregno)
 
 int
 dead_debug_insert_temp (struct dead_debug_local *debug, unsigned int uregno,
-                       rtx insn, enum debug_temp_where where)
+                       rtx_insn *insn, enum debug_temp_where where)
 {
   struct dead_debug_use **tailp = &debug->head;
   struct dead_debug_use *cur;
@@ -646,16 +666,14 @@ dead_debug_insert_temp (struct dead_debug_local *debug, unsigned int uregno,
             the debug temp to.  ??? We could bind the debug_expr to a
             CONCAT or PARALLEL with the split multi-registers, and
             replace them as we found the corresponding sets.  */
-         else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
-                  && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
-                      != hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
+         else if (REG_NREGS (reg) != REG_NREGS (dest))
            breg = NULL;
          /* Ok, it's the same (hardware) REG, but with a different
             mode, so SUBREG it.  */
          else
-           breg = lowpart_subreg (GET_MODE (reg),
-                                  cleanup_auto_inc_dec (src, VOIDmode),
-                                  GET_MODE (dest));
+           breg = debug_lowpart_subreg (GET_MODE (reg),
+                                        cleanup_auto_inc_dec (src, VOIDmode),
+                                        GET_MODE (dest));
        }
       else if (GET_CODE (dest) == SUBREG)
        {
@@ -670,14 +688,14 @@ dead_debug_insert_temp (struct dead_debug_local *debug, unsigned int uregno,
             setting REG in its mode would, we won't know what to bind
             the debug temp to.  */
          else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
-                  && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
+                  && (REG_NREGS (reg)
                       != hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
            breg = NULL;
          /* Yay, we can use SRC, just adjust its mode.  */
          else
-           breg = lowpart_subreg (GET_MODE (reg),
-                                  cleanup_auto_inc_dec (src, VOIDmode),
-                                  GET_MODE (dest));
+           breg = debug_lowpart_subreg (GET_MODE (reg),
+                                        cleanup_auto_inc_dec (src, VOIDmode),
+                                        GET_MODE (dest));
        }
       /* Oh well, we're out of luck.  */
       else
@@ -697,7 +715,7 @@ dead_debug_insert_temp (struct dead_debug_local *debug, unsigned int uregno,
      probably doesn't make sense to introduce a new debug temp.  */
   if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next)
     {
-      rtx next = DF_REF_INSN (uses->use);
+      rtx_insn *next = DF_REF_INSN (uses->use);
 
       if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next))
        {
@@ -731,7 +749,8 @@ dead_debug_insert_temp (struct dead_debug_local *debug, unsigned int uregno,
        *DF_REF_REAL_LOC (cur->use) = dval;
       else
        *DF_REF_REAL_LOC (cur->use)
-         = gen_lowpart_SUBREG (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval);
+         = debug_lowpart_subreg (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval,
+                                 GET_MODE (dval));
       /* ??? Should we simplify subreg of subreg?  */
       bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use)));
       uses = cur->next;