]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/auto-inc-dec.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / auto-inc-dec.c
index bde2a75fb28076d6c3f8e66a08e5f156db8e9ae3..c531df8815ccfbd148fc3c59a68ed262ccd6f93c 100644 (file)
@@ -1,12 +1,12 @@
 /* Discovery of auto-inc and auto-dec instructions.
-   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2006-2021 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
-   
+
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,38 +15,35 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
-#include "tm_p.h"
-#include "hard-reg-set.h"
-#include "basic-block.h"
+#include "tree.h"
+#include "predict.h"
+#include "df.h"
 #include "insn-config.h"
-#include "regs.h"
-#include "flags.h"
-#include "output.h"
-#include "function.h"
-#include "except.h"
-#include "toplev.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
 #include "recog.h"
+#include "cfgrtl.h"
 #include "expr.h"
-#include "timevar.h"
 #include "tree-pass.h"
-#include "df.h"
 #include "dbgcnt.h"
+#include "print-rtl.h"
+#include "valtrack.h"
 
 /* This pass was originally removed from flow.c. However there is
    almost nothing that remains of that code.
 
    There are (4) basic forms that are matched:
 
+      (1) FORM_PRE_ADD
            a <- b + c
            ...
            *a
@@ -56,25 +53,50 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
            a <- b
            ...
            *(a += c) pre
+
+        or, alternately,
+
+           a <- b + c
+           ...
+           *b
+
+        becomes
+
+           a <- b
+           ...
+           *(a += c) post
+
+        This uses a post-add, but it's handled as FORM_PRE_ADD because
+        the "increment" insn appears before the memory access.
+
+
+      (2) FORM_PRE_INC
            a += c
            ...
            *a
 
         becomes
 
+           ...
            *(a += c) pre
+
+
+      (3) FORM_POST_ADD
            *a
            ...
            b <- a + c
 
-          for this case to be true, b must not be assigned or used between 
-          the *a and the assignment to b.  B must also be a Pmode reg.
+          (For this case to be true, b must not be assigned or used between
+          the *a and the assignment to b.  B must also be a Pmode reg.)
 
         becomes
 
            b <- a
-           ...
            *(b += c) post
+           ...
+
+
+      (4) FORM_POST_INC
            *a
            ...
            a <- a + c
@@ -82,6 +104,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
         becomes
 
            *(a += c) post
+           ...
+
 
   There are three types of values of c.
 
@@ -94,63 +118,14 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
        by the pointer.  This is useful for machines that have
        HAVE_PRE_MODIFY_DISP, HAVE_POST_MODIFY_DISP defined.
 
-    3) c is a register.  This is useful for machines that have 
-       HAVE_PRE_MODIFY_REG,  HAVE_POST_MODIFY_REG  
-  
+    3) c is a register.  This is useful for machines that have
+       HAVE_PRE_MODIFY_REG,  HAVE_POST_MODIFY_REG
+
   The is one special case: if a already had an offset equal to it +-
   its width and that offset is equal to -c when the increment was
   before the ref or +c if the increment was after the ref, then if we
-  can do the combination but switch the pre/post bit.
-
-        (1) FORM_PRE_ADD
+  can do the combination but switch the pre/post bit.  */
 
-           a <- b + c
-           ...
-           *(a - c)
-
-        becomes
-
-           a <- b
-           ...
-           *(a += c) post
-
-        (2) FORM_PRE_INC
-
-           a += c
-           ...
-           *(a - c)
-
-        becomes
-
-           *(a += c) post
-
-        (3) FORM_POST_ADD
-
-           *(a + c)
-           ...
-           b <- a + c
-
-          for this case to be true, b must not be assigned or used between 
-          the *a and the assignment to b. B must also be a Pmode reg.
-
-        becomes
-
-           b <- a
-           ...
-           *(b += c) pre
-
-
-        (4) FORM_POST_INC
-
-           *(a + c)
-           ...
-           a <- a + c 
-
-        becomes
-
-           *(a += c) pre
-*/
-#ifdef AUTO_INC_DEC
 
 enum form
 {
@@ -167,7 +142,7 @@ enum form
    ANY is used for constants that are not +-size or 0.  REG is used if
    the forms are reg1 + reg2.  */
 
-enum inc_state 
+enum inc_state
 {
   INC_ZERO,           /* == 0  */
   INC_NEG_SIZE,       /* == +size  */
@@ -196,14 +171,14 @@ enum gen_form
 static rtx mem_tmp;
 
 static enum inc_state
-set_inc_state (HOST_WIDE_INT val, int size)
+set_inc_state (HOST_WIDE_INT val, poly_int64 size)
 {
   if (val == 0)
     return INC_ZERO;
   if (val < 0)
-    return (val == -size) ? INC_NEG_SIZE : INC_NEG_ANY;
+    return known_eq (val, -size) ? INC_NEG_SIZE : INC_NEG_ANY;
   else
-    return (val == size) ? INC_POS_SIZE : INC_POS_ANY;
+    return known_eq (val, size) ? INC_POS_SIZE : INC_POS_ANY;
 }
 
 /* The DECISION_TABLE that describes what form, if any, the increment
@@ -333,9 +308,9 @@ init_decision_table (void)
 /* Parsed fields of an inc insn of the form "reg_res = reg0+reg1" or
    "reg_res = reg0+c".  */
 
-static struct inc_insn 
+static struct inc_insn
 {
-  rtx insn;           /* The insn being parsed.  */
+  rtx_insn *insn;     /* The insn being parsed.  */
   rtx pat;            /* The pattern of the insn.  */
   bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg.  */
   enum form form;
@@ -349,10 +324,10 @@ static struct inc_insn
 
 /* Dump the parsed inc insn to FILE.  */
 
-static void 
+static void
 dump_inc_insn (FILE *file)
 {
-  const char *f = ((inc_insn.form == FORM_PRE_ADD) 
+  const char *f = ((inc_insn.form == FORM_PRE_ADD)
              || (inc_insn.form == FORM_PRE_INC)) ? "pre" : "post";
 
   dump_insn_slim (file, inc_insn.insn);
@@ -362,26 +337,26 @@ dump_inc_insn (FILE *file)
     case FORM_PRE_ADD:
     case FORM_POST_ADD:
       if (inc_insn.reg1_is_const)
-       fprintf (file, "found %s add(%d) r[%d]=r[%d]+%d\n", 
-                f, INSN_UID (inc_insn.insn), 
-                REGNO (inc_insn.reg_res), 
+       fprintf (file, "found %s add(%d) r[%d]=r[%d]+%d\n",
+                f, INSN_UID (inc_insn.insn),
+                REGNO (inc_insn.reg_res),
                 REGNO (inc_insn.reg0), (int) inc_insn.reg1_val);
       else
-       fprintf (file, "found %s add(%d) r[%d]=r[%d]+r[%d]\n", 
-                f, INSN_UID (inc_insn.insn), 
-                REGNO (inc_insn.reg_res), 
+       fprintf (file, "found %s add(%d) r[%d]=r[%d]+r[%d]\n",
+                f, INSN_UID (inc_insn.insn),
+                REGNO (inc_insn.reg_res),
                 REGNO (inc_insn.reg0), REGNO (inc_insn.reg1));
       break;
-      
+
     case FORM_PRE_INC:
     case FORM_POST_INC:
       if (inc_insn.reg1_is_const)
-       fprintf (file, "found %s inc(%d) r[%d]+=%d\n", 
-                f, INSN_UID (inc_insn.insn), 
+       fprintf (file, "found %s inc(%d) r[%d]+=%d\n",
+                f, INSN_UID (inc_insn.insn),
                 REGNO (inc_insn.reg_res), (int) inc_insn.reg1_val);
       else
-       fprintf (file, "found %s inc(%d) r[%d]+=r[%d]\n", 
-                f, INSN_UID (inc_insn.insn), 
+       fprintf (file, "found %s inc(%d) r[%d]+=r[%d]\n",
+                f, INSN_UID (inc_insn.insn),
                 REGNO (inc_insn.reg_res), REGNO (inc_insn.reg1));
       break;
 
@@ -395,7 +370,7 @@ dump_inc_insn (FILE *file)
 
 static struct mem_insn
 {
-  rtx insn;           /* The insn being parsed.  */
+  rtx_insn *insn;     /* The insn being parsed.  */
   rtx pat;            /* The pattern of the insn.  */
   rtx *mem_loc;       /* The address of the field that holds the mem */
                       /* that is to be replaced.  */
@@ -410,18 +385,18 @@ static struct mem_insn
 
 /* Dump the parsed mem insn to FILE.  */
 
-static void 
+static void
 dump_mem_insn (FILE *file)
 {
   dump_insn_slim (file, mem_insn.insn);
 
   if (mem_insn.reg1_is_const)
-    fprintf (file, "found mem(%d) *(r[%d]+%d)\n", 
-            INSN_UID (mem_insn.insn), 
+    fprintf (file, "found mem(%d) *(r[%d]+%d)\n",
+            INSN_UID (mem_insn.insn),
             REGNO (mem_insn.reg0), (int) mem_insn.reg1_val);
   else
-    fprintf (file, "found mem(%d) *(r[%d]+r[%d])\n", 
-            INSN_UID (mem_insn.insn), 
+    fprintf (file, "found mem(%d) *(r[%d]+r[%d])\n",
+            INSN_UID (mem_insn.insn),
             REGNO (mem_insn.reg0), REGNO (mem_insn.reg1));
 }
 
@@ -437,9 +412,10 @@ dump_mem_insn (FILE *file)
    must be compared with the current block.
 */
 
-static rtx *reg_next_use = NULL;
-static rtx *reg_next_inc_use = NULL;
-static rtx *reg_next_def = NULL;
+static rtx_insn **reg_next_debug_use = NULL;
+static rtx_insn **reg_next_use = NULL;
+static rtx_insn **reg_next_inc_use = NULL;
+static rtx_insn **reg_next_def = NULL;
 
 
 /* Move dead note that match PATTERN to TO_INSN from FROM_INSN.  We do
@@ -447,17 +423,17 @@ static rtx *reg_next_def = NULL;
    insn.  Moving the REG_EQUAL and REG_EQUIV is clearly wrong and it
    does not appear that there are any other kinds of relevant notes.  */
 
-static void 
-move_dead_notes (rtx to_insn, rtx from_insn, rtx pattern)
+static void
+move_dead_notes (rtx_insn *to_insn, rtx_insn *from_insn, rtx pattern)
 {
-  rtx note; 
+  rtx note;
   rtx next_note;
   rtx prev_note = NULL;
 
   for (note = REG_NOTES (from_insn); note; note = next_note)
     {
       next_note = XEXP (note, 1);
-      
+
       if ((REG_NOTE_KIND (note) == REG_DEAD)
          && pattern == XEXP (note, 0))
        {
@@ -472,24 +448,6 @@ move_dead_notes (rtx to_insn, rtx from_insn, rtx pattern)
     }
 }
 
-
-/* Create a mov insn DEST_REG <- SRC_REG and insert it before
-   NEXT_INSN.  */
-
-static rtx
-insert_move_insn_before (rtx next_insn, rtx dest_reg, rtx src_reg)
-{
-  rtx insns;
-
-  start_sequence ();
-  emit_move_insn (dest_reg, src_reg);
-  insns = get_insns ();
-  end_sequence ();
-  emit_insn_before (insns, next_insn);
-  return insns;
-}
-
-  
 /* Change mem_insn.mem_loc so that uses NEW_ADDR which has an
    increment of INC_REG.  To have reached this point, the change is a
    legitimate one from a dataflow point of view.  The only questions
@@ -508,22 +466,38 @@ attempt_change (rtx new_addr, rtx inc_reg)
      passes are for.  The two cases where we have an inc insn will be
      handled mov free.  */
 
-  basic_block bb = BASIC_BLOCK (BLOCK_NUM (mem_insn.insn));
-  rtx mov_insn = NULL;
+  basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
+  rtx_insn *mov_insn = NULL;
   int regno;
   rtx mem = *mem_insn.mem_loc;
-  enum machine_mode mode = GET_MODE (mem);
+  machine_mode mode = GET_MODE (mem);
+  int align = MEM_ALIGN (mem);
   rtx new_mem;
   int old_cost = 0;
   int new_cost = 0;
+  bool speed = optimize_bb_for_speed_p (bb);
 
   PUT_MODE (mem_tmp, mode);
   XEXP (mem_tmp, 0) = new_addr;
+  set_mem_align (mem_tmp, align);
+
+  old_cost = (set_src_cost (mem, mode, speed)
+             + set_rtx_cost (PATTERN (inc_insn.insn), speed));
+
+  new_cost = set_src_cost (mem_tmp, mode, speed);
+
+  /* In the FORM_PRE_ADD and FORM_POST_ADD cases we emit an extra move
+     whose cost we should account for.  */
+  if (inc_insn.form == FORM_PRE_ADD
+      || inc_insn.form == FORM_POST_ADD)
+    {
+      start_sequence ();
+      emit_move_insn (inc_insn.reg_res, inc_insn.reg0);
+      mov_insn = get_insns ();
+      end_sequence ();
+      new_cost += seq_cost (mov_insn, speed);
+    }
 
-  old_cost = rtx_cost (mem, 0) 
-    + rtx_cost (PATTERN (inc_insn.insn), 0);
-  new_cost = rtx_cost (mem_tmp, 0);
-  
   /* The first item of business is to see if this is profitable.  */
   if (old_cost < new_cost)
     {
@@ -532,7 +506,7 @@ attempt_change (rtx new_addr, rtx inc_reg)
       return false;
     }
 
-  /* Jump thru a lot of hoops to keep the attributes up to date.  We
+  /* Jump through a lot of hoops to keep the attributes up to date.  We
      do not want to call one of the change address variants that take
      an offset even though we know the offset in many cases.  These
      assume you are changing where the address is pointing by the
@@ -541,7 +515,7 @@ attempt_change (rtx new_addr, rtx inc_reg)
   if (! validate_change (mem_insn.insn, mem_insn.mem_loc, new_mem, 0))
     {
       if (dump_file)
-       fprintf (dump_file, "validation failure\n"); 
+       fprintf (dump_file, "validation failure\n");
       return false;
     }
 
@@ -551,44 +525,123 @@ attempt_change (rtx new_addr, rtx inc_reg)
   switch (inc_insn.form)
     {
     case FORM_PRE_ADD:
-      mov_insn = insert_move_insn_before (mem_insn.insn, 
-                                         inc_insn.reg_res, inc_insn.reg0);
-      move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
+      /* Replace the addition with a move.  Do it at the location of
+        the addition since the operand of the addition may change
+        before the memory reference.  */
+      gcc_assert (mov_insn);
+      emit_insn_before (mov_insn, inc_insn.insn);
+      regno = REGNO (inc_insn.reg0);
+      /* ??? Could REGNO possibly be used in MEM_INSN other than in
+        the MEM address, and still die there, so that move_dead_notes
+        would incorrectly move the note?  */
+      if (reg_next_use[regno] == mem_insn.insn)
+       move_dead_notes (mov_insn, mem_insn.insn, inc_insn.reg0);
+      else
+       move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
 
       regno = REGNO (inc_insn.reg_res);
+      if (reg_next_debug_use && reg_next_debug_use[regno]
+         && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
+       {
+         rtx adjres = gen_rtx_PLUS (GET_MODE (inc_insn.reg_res),
+                                    inc_insn.reg_res, inc_insn.reg1);
+         if (dump_file)
+           fprintf (dump_file, "adjusting debug insns\n");
+         propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
+                              mem_insn.insn,
+                              inc_insn.reg_res, adjres, bb);
+         reg_next_debug_use[regno] = NULL;
+       }
       reg_next_def[regno] = mov_insn;
       reg_next_use[regno] = NULL;
+
       regno = REGNO (inc_insn.reg0);
+      if (reg_next_debug_use && reg_next_debug_use[regno]
+         && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb
+         && find_reg_note (mov_insn, REG_DEAD, inc_insn.reg0))
+       {
+         if (dump_file)
+           fprintf (dump_file, "remapping debug insns\n");
+         propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
+                              mem_insn.insn,
+                              inc_insn.reg0, inc_insn.reg_res, bb);
+         reg_next_debug_use[regno] = NULL;
+       }
       reg_next_use[regno] = mov_insn;
       df_recompute_luids (bb);
       break;
 
     case FORM_POST_INC:
       regno = REGNO (inc_insn.reg_res);
+      if (reg_next_debug_use && reg_next_debug_use[regno]
+         && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
+       {
+         rtx adjres = gen_rtx_MINUS (GET_MODE (inc_insn.reg_res),
+                                     inc_insn.reg_res, inc_insn.reg1);
+         if (dump_file)
+           fprintf (dump_file, "adjusting debug insns\n");
+         propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
+                              inc_insn.insn,
+                              inc_insn.reg_res, adjres, bb);
+         reg_next_debug_use[regno] = NULL;
+       }
       if (reg_next_use[regno] == reg_next_inc_use[regno])
        reg_next_inc_use[regno] = NULL;
 
       /* Fallthru.  */
     case FORM_PRE_INC:
       regno = REGNO (inc_insn.reg_res);
+      /* Despite the fall-through, we won't run this twice: we'll have
+        already cleared reg_next_debug_use[regno] before falling
+        through.  */
+      if (reg_next_debug_use && reg_next_debug_use[regno]
+         && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
+       {
+         rtx adjres = gen_rtx_PLUS (GET_MODE (inc_insn.reg_res),
+                                    inc_insn.reg_res, inc_insn.reg1);
+         if (dump_file)
+           fprintf (dump_file, "adjusting debug insns\n");
+         propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
+                              mem_insn.insn,
+                              inc_insn.reg_res, adjres, bb);
+         if (DF_INSN_LUID (mem_insn.insn)
+             < DF_INSN_LUID (reg_next_debug_use[regno]))
+           reg_next_debug_use[regno] = NULL;
+       }
       reg_next_def[regno] = mem_insn.insn;
       reg_next_use[regno] = NULL;
 
       break;
 
     case FORM_POST_ADD:
-      mov_insn = insert_move_insn_before (mem_insn.insn, 
-                                         inc_insn.reg_res, inc_insn.reg0);
+      gcc_assert (mov_insn);
+      emit_insn_before (mov_insn, mem_insn.insn);
       move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
 
       /* Do not move anything to the mov insn because the instruction
         pointer for the main iteration has not yet hit that.  It is
         still pointing to the mem insn. */
       regno = REGNO (inc_insn.reg_res);
+      /* The pseudo is now set earlier, so it must have been dead in
+        that range, and dead registers cannot be referenced in debug
+        insns.  */
+      gcc_assert (!(reg_next_debug_use && reg_next_debug_use[regno]
+                   && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb));
       reg_next_def[regno] = mem_insn.insn;
       reg_next_use[regno] = NULL;
 
       regno = REGNO (inc_insn.reg0);
+      if (reg_next_debug_use && reg_next_debug_use[regno]
+         && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb
+         && find_reg_note (mov_insn, REG_DEAD, inc_insn.reg0))
+       {
+         if (dump_file)
+           fprintf (dump_file, "remapping debug insns\n");
+         propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
+                              inc_insn.insn,
+                              inc_insn.reg0, inc_insn.reg_res, bb);
+         reg_next_debug_use[regno] = NULL;
+       }
       reg_next_use[regno] = mem_insn.insn;
       if ((reg_next_use[regno] == reg_next_inc_use[regno])
          || (reg_next_inc_use[regno] == inc_insn.insn))
@@ -619,8 +672,7 @@ attempt_change (rtx new_addr, rtx inc_reg)
     }
 
   /* Record that this insn has an implicit side effect.  */
-  REG_NOTES (mem_insn.insn) 
-    = alloc_EXPR_LIST (REG_INC, inc_reg, REG_NOTES (mem_insn.insn));
+  add_reg_note (mem_insn.insn, REG_INC, inc_reg);
 
   if (dump_file)
     {
@@ -634,11 +686,11 @@ attempt_change (rtx new_addr, rtx inc_reg)
 
 /* Try to combine the instruction in INC_INSN with the instruction in
    MEM_INSN.  First the form is determined using the DECISION_TABLE
-   and and the results of parsing the INC_INSN and the MEM_INSN.
+   and the results of parsing the INC_INSN and the MEM_INSN.
    Assuming the form is ok, a prototype new address is built which is
    passed to ATTEMPT_CHANGE for final processing.  */
 
-static bool 
+static bool
 try_merge (void)
 {
   enum gen_form gen_form;
@@ -647,8 +699,9 @@ try_merge (void)
     inc_insn.reg_res : mem_insn.reg0;
 
   /* The width of the mem being accessed.  */
-  int size = GET_MODE_SIZE (GET_MODE (mem));
-  rtx last_insn = NULL;
+  poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
+  rtx_insn *last_insn = NULL;
+  machine_mode reg_mode = GET_MODE (inc_reg);
 
   switch (inc_insn.form)
     {
@@ -674,7 +727,7 @@ try_merge (void)
     }
 
   /* Look to see if the inc register is dead after the memory
-     reference.  If it is do not do the combination.  */
+     reference.  If it is, do not do the combination.  */
   if (find_regno_note (last_insn, REG_DEAD, REGNO (inc_reg)))
     {
       if (dump_file)
@@ -682,13 +735,13 @@ try_merge (void)
       return false;
     }
 
-  mem_insn.reg1_state = (mem_insn.reg1_is_const) 
+  mem_insn.reg1_state = (mem_insn.reg1_is_const)
     ? set_inc_state (mem_insn.reg1_val, size) : INC_REG;
   inc_insn.reg1_state = (inc_insn.reg1_is_const)
     ? set_inc_state (inc_insn.reg1_val, size) : INC_REG;
 
   /* Now get the form that we are generating.  */
-  gen_form = decision_table 
+  gen_form = decision_table
     [inc_insn.reg1_state][mem_insn.reg1_state][inc_insn.form];
 
   if (dbg_cnt (auto_inc_dec) == false)
@@ -703,70 +756,62 @@ try_merge (void)
     case SIMPLE_PRE_INC:     /* ++size  */
       if (dump_file)
        fprintf (dump_file, "trying SIMPLE_PRE_INC\n");
-      return attempt_change (gen_rtx_PRE_INC (Pmode, inc_reg), inc_reg);
-      break;
-      
+      return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg);
+
     case SIMPLE_POST_INC:    /* size++  */
       if (dump_file)
        fprintf (dump_file, "trying SIMPLE_POST_INC\n");
-      return attempt_change (gen_rtx_POST_INC (Pmode, inc_reg), inc_reg);
-      break;
-      
+      return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg);
+
     case SIMPLE_PRE_DEC:     /* --size  */
       if (dump_file)
        fprintf (dump_file, "trying SIMPLE_PRE_DEC\n");
-      return attempt_change (gen_rtx_PRE_DEC (Pmode, inc_reg), inc_reg);
-      break;
-      
+      return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg);
+
     case SIMPLE_POST_DEC:    /* size--  */
       if (dump_file)
        fprintf (dump_file, "trying SIMPLE_POST_DEC\n");
-      return attempt_change (gen_rtx_POST_DEC (Pmode, inc_reg), inc_reg);
-      break;
-      
+      return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg);
+
     case DISP_PRE:           /* ++con   */
       if (dump_file)
        fprintf (dump_file, "trying DISP_PRE\n");
-      return attempt_change (gen_rtx_PRE_MODIFY (Pmode, 
+      return attempt_change (gen_rtx_PRE_MODIFY (reg_mode,
                                                 inc_reg,
-                                                gen_rtx_PLUS (Pmode,
+                                                gen_rtx_PLUS (reg_mode,
                                                               inc_reg,
                                                               inc_insn.reg1)),
                             inc_reg);
-      break;
-      
+
     case DISP_POST:          /* con++   */
       if (dump_file)
        fprintf (dump_file, "trying POST_DISP\n");
-      return attempt_change (gen_rtx_POST_MODIFY (Pmode,
+      return attempt_change (gen_rtx_POST_MODIFY (reg_mode,
                                                  inc_reg,
-                                                 gen_rtx_PLUS (Pmode,
+                                                 gen_rtx_PLUS (reg_mode,
                                                                inc_reg,
                                                                inc_insn.reg1)),
                             inc_reg);
-      break;
-      
+
     case REG_PRE:            /* ++reg   */
       if (dump_file)
        fprintf (dump_file, "trying PRE_REG\n");
-      return attempt_change (gen_rtx_PRE_MODIFY (Pmode, 
+      return attempt_change (gen_rtx_PRE_MODIFY (reg_mode,
                                                 inc_reg,
-                                                gen_rtx_PLUS (Pmode,
+                                                gen_rtx_PLUS (reg_mode,
                                                               inc_reg,
                                                               inc_insn.reg1)),
                             inc_reg);
-      break;
-      
+
     case REG_POST:            /* reg++   */
       if (dump_file)
        fprintf (dump_file, "trying POST_REG\n");
-      return attempt_change (gen_rtx_POST_MODIFY (Pmode, 
+      return attempt_change (gen_rtx_POST_MODIFY (reg_mode,
                                                  inc_reg,
-                                                 gen_rtx_PLUS (Pmode,
+                                                 gen_rtx_PLUS (reg_mode,
                                                                inc_reg,
                                                                inc_insn.reg1)),
                             inc_reg);
-      break;
     }
 }
 
@@ -774,13 +819,13 @@ try_merge (void)
    NEXT_ARRAY) or defines (if reg_next_def is passed in NEXT_ARRAY)
    REGNO in BB.  */
 
-static rtx
-get_next_ref (int regno, basic_block bb, rtx *next_array)
+static rtx_insn *
+get_next_ref (int regno, basic_block bb, rtx_insn **next_array)
 {
-  rtx insn = next_array[regno];
+  rtx_insn *insn = next_array[regno];
 
   /* Lazy about cleaning out the next_arrays.  */
-  if (insn && BASIC_BLOCK (BLOCK_NUM (insn)) != bb)
+  if (insn && BLOCK_FOR_INSN (insn) != bb)
     {
       next_array[regno] = NULL;
       insn = NULL;
@@ -790,32 +835,10 @@ get_next_ref (int regno, basic_block bb, rtx *next_array)
 }
 
 
-/* Reverse the operands in a mem insn.  */
-
-static void 
-reverse_mem (void)
-{
-  rtx tmp = mem_insn.reg1; 
-  mem_insn.reg1 = mem_insn.reg0;
-  mem_insn.reg0 = tmp;
-}
-
-
-/* Reverse the operands in a inc insn.  */
-
-static void 
-reverse_inc (void)
-{
-  rtx tmp = inc_insn.reg1; 
-  inc_insn.reg1 = inc_insn.reg0;
-  inc_insn.reg0 = tmp;
-}
-
-
 /* Return true if INSN is of a form "a = b op c" where a and b are
    regs.  op is + if c is a reg and +|- if c is a const.  Fill in
-   INC_INSN with what is found.  
-   
+   INC_INSN with what is found.
+
    This function is called in two contexts, if BEFORE_MEM is true,
    this is called for each insn in the basic block.  If BEFORE_MEM is
    false, it is called for the instruction in the block that uses the
@@ -823,7 +846,7 @@ reverse_inc (void)
    processed.  */
 
 static bool
-parse_add_or_inc (rtx insn, bool before_mem)
+parse_add_or_inc (rtx_insn *insn, bool before_mem)
 {
   rtx pat = single_set (insn);
   if (!pat)
@@ -844,12 +867,18 @@ parse_add_or_inc (rtx insn, bool before_mem)
   inc_insn.pat = pat;
   inc_insn.reg_res = SET_DEST (pat);
   inc_insn.reg0 = XEXP (SET_SRC (pat), 0);
+
+  /* Block any auto increment of the frame pointer since it expands into
+     an addition and cannot be removed by copy propagation.  */
+  if (inc_insn.reg0 == frame_pointer_rtx)
+    return false;
+
   if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg0))
     inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC;
-  else 
+  else
     inc_insn.form = before_mem ? FORM_PRE_ADD : FORM_POST_ADD;
 
-  if (GET_CODE (XEXP (SET_SRC (pat), 1)) == CONST_INT)
+  if (CONST_INT_P (XEXP (SET_SRC (pat), 1)))
     {
       /* Process a = b + c where c is a const.  */
       inc_insn.reg1_is_const = true;
@@ -872,19 +901,19 @@ parse_add_or_inc (rtx insn, bool before_mem)
       /* Process a = b + c where c is a reg.  */
       inc_insn.reg1 = XEXP (SET_SRC (pat), 1);
       inc_insn.reg1_is_const = false;
-      
-      if (inc_insn.form == FORM_PRE_INC 
+
+      if (inc_insn.form == FORM_PRE_INC
          || inc_insn.form == FORM_POST_INC)
        return true;
       else if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg1))
        {
          /* Reverse the two operands and turn *_ADD into *_INC since
             a = c + a.  */
-         reverse_inc ();
+         std::swap (inc_insn.reg0, inc_insn.reg1);
          inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC;
          return true;
        }
-      else 
+      else
        return true;
     }
 
@@ -894,13 +923,15 @@ parse_add_or_inc (rtx insn, bool before_mem)
 
 /* A recursive function that checks all of the mem uses in
    ADDRESS_OF_X to see if any single one of them is compatible with
-   what has been found in inc_insn.
+   what has been found in inc_insn.  To avoid accidental matches, we
+   will only find MEMs with FINDREG, be it inc_insn.reg_res, be it
+   inc_insn.reg0.
 
-   -1 is returned for success.  0 is returned if nothing was found and 
+   -1 is returned for success.  0 is returned if nothing was found and
    1 is returned for failure. */
 
 static int
-find_address (rtx *address_of_x)
+find_address (rtx *address_of_x, rtx findreg)
 {
   rtx x = *address_of_x;
   enum rtx_code code = GET_CODE (x);
@@ -909,9 +940,10 @@ find_address (rtx *address_of_x)
   int value = 0;
   int tem;
 
-  if (code == MEM && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res))
+  if (code == MEM && findreg == inc_insn.reg_res
+      && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res))
     {
-      /* Match with *reg0.  */
+      /* Match with *reg_res.  */
       mem_insn.mem_loc = address_of_x;
       mem_insn.reg0 = inc_insn.reg_res;
       mem_insn.reg1_is_const = true;
@@ -919,7 +951,21 @@ find_address (rtx *address_of_x)
       mem_insn.reg1 = GEN_INT (0);
       return -1;
     }
-  if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS
+  if (code == MEM && inc_insn.reg1_is_const && inc_insn.reg0
+      && findreg == inc_insn.reg0
+      && rtx_equal_p (XEXP (x, 0), inc_insn.reg0))
+    {
+      /* Match with *reg0, assumed to be equivalent to
+         *(reg_res - reg1_val); callers must check whether this is the case.  */
+      mem_insn.mem_loc = address_of_x;
+      mem_insn.reg0 = inc_insn.reg_res;
+      mem_insn.reg1_is_const = true;
+      mem_insn.reg1_val = -inc_insn.reg1_val;
+      mem_insn.reg1 = GEN_INT (mem_insn.reg1_val);
+      return -1;
+    }
+  if (code == MEM && findreg == inc_insn.reg_res
+      && GET_CODE (XEXP (x, 0)) == PLUS
       && rtx_equal_p (XEXP (XEXP (x, 0), 0), inc_insn.reg_res))
     {
       rtx b = XEXP (XEXP (x, 0), 1);
@@ -927,19 +973,19 @@ find_address (rtx *address_of_x)
       mem_insn.reg0 = inc_insn.reg_res;
       mem_insn.reg1 = b;
       mem_insn.reg1_is_const = inc_insn.reg1_is_const;
-      if (GET_CODE (b) == CONST_INT)
+      if (CONST_INT_P (b))
        {
          /* Match with *(reg0 + reg1) where reg1 is a const. */
          HOST_WIDE_INT val = INTVAL (b);
-         if (inc_insn.reg1_is_const 
+         if (inc_insn.reg1_is_const
              && (inc_insn.reg1_val == val || inc_insn.reg1_val == -val))
            {
              mem_insn.reg1_val = val;
              return -1;
            }
        }
-      else if (!inc_insn.reg1_is_const 
-              && rtx_equal_p (inc_insn.reg1, b)) 
+      else if (!inc_insn.reg1_is_const
+              && rtx_equal_p (inc_insn.reg1, b))
        /* Match with *(reg0 + reg1). */
        return -1;
     }
@@ -948,7 +994,7 @@ find_address (rtx *address_of_x)
     {
       /* If REG occurs inside a MEM used in a bit-field reference,
         that is unacceptable.  */
-      if (find_address (&XEXP (x, 0)))
+      if (find_address (&XEXP (x, 0), findreg))
        return 1;
     }
 
@@ -960,7 +1006,7 @@ find_address (rtx *address_of_x)
     {
       if (fmt[i] == 'e')
        {
-         tem = find_address (&XEXP (x, i));
+         tem = find_address (&XEXP (x, i), findreg);
          /* If this is the first use, let it go so the rest of the
             insn can be checked.  */
          if (value == 0)
@@ -974,7 +1020,7 @@ find_address (rtx *address_of_x)
          int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            {
-             tem = find_address (&XVECEXP (x, i, j));
+             tem = find_address (&XVECEXP (x, i, j), findreg);
              /* If this is the first use, let it go so the rest of
                 the insn can be checked.  */
              if (value == 0)
@@ -999,19 +1045,19 @@ find_address (rtx *address_of_x)
    add of the second register.  The FIRST_TRY parameter is used to
    only allow the parameters to be reversed once.  */
 
-static bool 
+static bool
 find_inc (bool first_try)
 {
-  rtx insn;
-  basic_block bb = BASIC_BLOCK (BLOCK_NUM (mem_insn.insn));
-  rtx other_insn;
-  struct df_ref **def_rec;
+  rtx_insn *insn;
+  basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
+  rtx_insn *other_insn;
+  df_ref def;
 
   /* Make sure this reg appears only once in this insn.  */
   if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg0, 1) != 1)
     {
       if (dump_file)
-       fprintf (dump_file, "mem count failure\n"); 
+       fprintf (dump_file, "mem count failure\n");
       return false;
     }
 
@@ -1019,8 +1065,8 @@ find_inc (bool first_try)
     dump_mem_insn (dump_file);
 
   /* Find the next use that is an inc.  */
-  insn = get_next_ref (REGNO (mem_insn.reg0), 
-                      BASIC_BLOCK (BLOCK_NUM (mem_insn.insn)), 
+  insn = get_next_ref (REGNO (mem_insn.reg0),
+                      BLOCK_FOR_INSN (mem_insn.insn),
                       reg_next_inc_use);
   if (!insn)
     return false;
@@ -1031,29 +1077,28 @@ find_inc (bool first_try)
     {
       /* Next use was not an add.  Look for one extra case. It could be
         that we have:
-        
+
         *(a + b)
         ...= a;
         ...= b + a
-        
+
         if we reverse the operands in the mem ref we would
         find this.  Only try it once though.  */
       if (first_try && !mem_insn.reg1_is_const)
        {
-         reverse_mem ();
+         std::swap (mem_insn.reg0, mem_insn.reg1);
          return find_inc (false);
        }
       else
        return false;
     }
 
-  /* Need to assure that none of the operands of the inc instruction are 
+  /* Need to assure that none of the operands of the inc instruction are
      assigned to by the mem insn.  */
-  for (def_rec = DF_INSN_DEFS (mem_insn.insn); *def_rec; def_rec++)
+  FOR_EACH_INSN_DEF (def, mem_insn.insn)
     {
-      struct df_ref *def = *def_rec;
       unsigned int regno = DF_REF_REGNO (def);
-      if ((regno == REGNO (inc_insn.reg0)) 
+      if ((regno == REGNO (inc_insn.reg0))
          || (regno == REGNO (inc_insn.reg_res)))
        {
          if (dump_file)
@@ -1075,26 +1120,26 @@ find_inc (bool first_try)
     {
       /* Make sure that there is no insn that assigns to inc_insn.res
         between the mem_insn and the inc_insn.  */
-      rtx other_insn = get_next_ref (REGNO (inc_insn.reg_res), 
-                                    BASIC_BLOCK (BLOCK_NUM (mem_insn.insn)), 
-                                    reg_next_def);
+      rtx_insn *other_insn = get_next_ref (REGNO (inc_insn.reg_res),
+                                          BLOCK_FOR_INSN (mem_insn.insn),
+                                          reg_next_def);
       if (other_insn != inc_insn.insn)
        {
          if (dump_file)
-           fprintf (dump_file, 
+           fprintf (dump_file,
                     "result of add is assigned to between mem and inc insns.\n");
          return false;
        }
 
-      other_insn = get_next_ref (REGNO (inc_insn.reg_res), 
-                                BASIC_BLOCK (BLOCK_NUM (mem_insn.insn)), 
+      other_insn = get_next_ref (REGNO (inc_insn.reg_res),
+                                BLOCK_FOR_INSN (mem_insn.insn),
                                 reg_next_use);
-      if (other_insn 
+      if (other_insn
          && (other_insn != inc_insn.insn)
          && (DF_INSN_LUID (inc_insn.insn) > DF_INSN_LUID (other_insn)))
        {
          if (dump_file)
-           fprintf (dump_file, 
+           fprintf (dump_file,
                     "result of add is used between mem and inc insns.\n");
          return false;
        }
@@ -1102,7 +1147,7 @@ find_inc (bool first_try)
       /* For the post_add to work, the result_reg of the inc must not be
         used in the mem insn since this will become the new index
         register.  */
-      if (count_occurrences (PATTERN (mem_insn.insn), inc_insn.reg_res, 1) != 0)
+      if (reg_overlap_mentioned_p (inc_insn.reg_res, PATTERN (mem_insn.insn)))
        {
          if (dump_file)
            fprintf (dump_file, "base reg replacement failure.\n");
@@ -1121,11 +1166,13 @@ find_inc (bool first_try)
              int luid = DF_INSN_LUID (inc_insn.insn);
              if (inc_insn.form == FORM_POST_ADD)
                {
-                 /* The trick is that we are not going to increment r0, 
+                 /* The trick is that we are not going to increment r0,
                     we are going to increment the result of the add insn.
                     For this trick to be correct, the result reg of
                     the inc must be a valid addressing reg.  */
-                 if (GET_MODE (inc_insn.reg_res) != Pmode)
+                 addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc);
+                 if (GET_MODE (inc_insn.reg_res)
+                     != targetm.addr_space.address_mode (as))
                    {
                      if (dump_file)
                        fprintf (dump_file, "base reg mode failure.\n");
@@ -1134,16 +1181,16 @@ find_inc (bool first_try)
 
                  /* We also need to make sure that the next use of
                     inc result is after the inc.  */
-                 other_insn 
+                 other_insn
                    = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use);
                  if (other_insn && luid > DF_INSN_LUID (other_insn))
                    return false;
 
                  if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
-                   reverse_inc (); 
+                   std::swap (inc_insn.reg0, inc_insn.reg1);
                }
 
-             other_insn 
+             other_insn
                = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
              if (other_insn && luid > DF_INSN_LUID (other_insn))
                return false;
@@ -1162,19 +1209,21 @@ find_inc (bool first_try)
         need to treat it as if it was *(b + a).  It may also be that
         the add is of the form a + c where c does not match b and
         then we just abandon this.  */
-      
+
       int luid = DF_INSN_LUID (inc_insn.insn);
-      rtx other_insn;
-      
+      rtx_insn *other_insn;
+
       /* Make sure this reg appears only once in this insn.  */
       if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg1, 1) != 1)
        return false;
-      
+
       if (inc_insn.form == FORM_POST_ADD)
        {
          /* For this trick to be correct, the result reg of the inc
             must be a valid addressing reg.  */
-         if (GET_MODE (inc_insn.reg_res) != Pmode)
+         addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc);
+         if (GET_MODE (inc_insn.reg_res)
+             != targetm.addr_space.address_mode (as))
            {
              if (dump_file)
                fprintf (dump_file, "base reg mode failure.\n");
@@ -1188,7 +1237,7 @@ find_inc (bool first_try)
                  /* See comment above on find_inc (false) call.  */
                  if (first_try)
                    {
-                     reverse_mem ();
+                     std::swap (mem_insn.reg0, mem_insn.reg1);
                      return find_inc (false);
                    }
                  else
@@ -1197,7 +1246,7 @@ find_inc (bool first_try)
 
              /* Need to check that there are no assignments to b
                 before the add insn.  */
-             other_insn 
+             other_insn
                = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
              if (other_insn && luid > DF_INSN_LUID (other_insn))
                return false;
@@ -1207,7 +1256,7 @@ find_inc (bool first_try)
            {
              /* We know that mem_insn.reg0 must equal inc_insn.reg1
                 or else we would not have found the inc insn.  */
-             reverse_mem ();
+             std::swap (mem_insn.reg0, mem_insn.reg1);
              if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
                {
                  /* See comment above on find_inc (false) call.  */
@@ -1218,14 +1267,14 @@ find_inc (bool first_try)
                }
              /* To have gotten here know that.
               *(b + a)
-              
+
               ... = (b + a)
-              
+
               We also know that the lhs of the inc is not b or a.  We
               need to make sure that there are no assignments to b
-              between the mem ref and the inc.  */      
-             
-             other_insn 
+              between the mem ref and the inc.  */
+
+             other_insn
                = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_def);
              if (other_insn && luid > DF_INSN_LUID (other_insn))
                return false;
@@ -1233,35 +1282,35 @@ find_inc (bool first_try)
 
          /* Need to check that the next use of the add result is later than
             add insn since this will be the reg incremented.  */
-         other_insn 
+         other_insn
            = get_next_ref (REGNO (inc_insn.reg_res), bb, reg_next_use);
          if (other_insn && luid > DF_INSN_LUID (other_insn))
            return false;
        }
       else /* FORM_POST_INC.  There is less to check here because we
-             know that operands must line up.  */ 
+             know that operands must line up.  */
        {
          if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1))
            /* See comment above on find_inc (false) call.  */
            {
              if (first_try)
                {
-                 reverse_mem ();
+                 std::swap (mem_insn.reg0, mem_insn.reg1);
                  return find_inc (false);
                }
-             else 
+             else
                return false;
            }
-      
+
          /* To have gotten here know that.
           *(a + b)
-          
+
           ... = (a + b)
-          
+
           We also know that the lhs of the inc is not b.  We need to make
           sure that there are no assignments to b between the mem ref and
           the inc.  */
-         other_insn 
+         other_insn
            = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
          if (other_insn && luid > DF_INSN_LUID (other_insn))
            return false;
@@ -1270,7 +1319,7 @@ find_inc (bool first_try)
 
   if (inc_insn.form == FORM_POST_INC)
     {
-      other_insn 
+      other_insn
        = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_use);
       /* When we found inc_insn, we were looking for the
         next add or inc, not the next insn that used the
@@ -1315,7 +1364,7 @@ find_mem (rtx *address_of_x)
       mem_insn.mem_loc = address_of_x;
       mem_insn.reg0 = XEXP (XEXP (x, 0), 0);
       mem_insn.reg1 = reg1;
-      if (GET_CODE (reg1) == CONST_INT)
+      if (CONST_INT_P (reg1))
        {
          mem_insn.reg1_is_const = true;
          /* Match with *(reg0 + c) where c is a const. */
@@ -1365,8 +1414,8 @@ find_mem (rtx *address_of_x)
 static void
 merge_in_block (int max_reg, basic_block bb)
 {
-  rtx insn;
-  rtx curr;
+  rtx_insn *insn;
+  rtx_insn *curr;
   int success_in_block = 0;
 
   if (dump_file)
@@ -1374,16 +1423,27 @@ merge_in_block (int max_reg, basic_block bb)
 
   FOR_BB_INSNS_REVERSE_SAFE (bb, insn, curr)
     {
-      unsigned int uid = INSN_UID (insn);
       bool insn_is_add_or_inc = true;
 
-      if (!INSN_P (insn))
-       continue;       
+      if (!NONDEBUG_INSN_P (insn))
+       {
+         if (DEBUG_BIND_INSN_P (insn))
+           {
+             df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
+             df_ref use;
+
+             if (dump_file)
+               dump_insn_slim (dump_file, insn);
+
+             FOR_EACH_INSN_INFO_USE (use, insn_info)
+               reg_next_debug_use[DF_REF_REGNO (use)] = insn;
+           }
+         continue;
+       }
 
-      /* This continue is deliberate.  We do not want the uses of the
-        jump put into reg_next_use because it is not considered safe to 
-        combine a preincrement with a jump.  */
-      if (JUMP_P (insn))
+      /* Reload should handle auto-inc within a jump correctly, while LRA
+        is known to have issues with autoinc.  */
+      if (JUMP_P (insn) && targetm.lra_p ())
        continue;
 
       if (dump_file)
@@ -1411,23 +1471,122 @@ merge_in_block (int max_reg, basic_block bb)
                         clear of c because the inc insn is going to move
                         into the mem_insn.insn.  */
                      int luid = DF_INSN_LUID (mem_insn.insn);
-                     rtx other_insn 
+                     rtx_insn *other_insn
                        = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use);
-                     
+
                      if (other_insn && luid > DF_INSN_LUID (other_insn))
                        ok = false;
-                     
-                     other_insn 
+
+                     other_insn
                        = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
-                     
+
                      if (other_insn && luid > DF_INSN_LUID (other_insn))
                        ok = false;
                    }
-                 
+
                  if (dump_file)
                    dump_inc_insn (dump_file);
-                 
-                 if (ok && find_address (&PATTERN (mem_insn.insn)) == -1)
+
+                 if (ok && find_address (&PATTERN (mem_insn.insn),
+                                         inc_insn.reg_res) == -1)
+                   {
+                     if (dump_file)
+                       dump_mem_insn (dump_file);
+                     if (try_merge ())
+                       {
+                         success_in_block++;
+                         insn_is_add_or_inc = false;
+                       }
+                   }
+               }
+
+             if (insn_is_add_or_inc
+                 /* find_address will only recognize an address
+                    with a reg0 that's not reg_res when
+                    reg1_is_const, so cut it off early if we
+                    already know it won't match.  */
+                 && inc_insn.reg1_is_const
+                 && inc_insn.reg0
+                 && inc_insn.reg0 != inc_insn.reg_res)
+               {
+                 /* If we identified an inc_insn that uses two
+                    different pseudos, it's of the form
+
+                    (set reg_res (plus reg0 reg1))
+
+                    where reg1 is a constant (*).
+
+                    The next use of reg_res was not identified by
+                    find_address as a mem_insn that we could turn
+                    into auto-inc, so see if we find a suitable
+                    MEM in the next use of reg0, as long as it's
+                    before any subsequent use of reg_res:
+
+                    ... (mem (... reg0 ...)) ...
+
+                    ... reg_res ...
+
+                    In this case, we can turn the plus into a
+                    copy, and the reg0 in the MEM address into a
+                    post_inc of reg_res:
+
+                    (set reg_res reg0)
+
+                    ... (mem (... (post_add reg_res reg1) ...)) ...
+
+                    reg_res will then have the correct value at
+                    subsequent uses, and reg0 will remain
+                    unchanged.
+
+                    (*) We could support non-const reg1, but then
+                    we'd have to check that reg1 remains
+                    unchanged all the way to the modified MEM,
+                    and we'd have to extend find_address to
+                    represent a non-const negated reg1.  */
+                 regno = REGNO (inc_insn.reg0);
+                 rtx_insn *reg0_use = get_next_ref (regno, bb,
+                                                    reg_next_use);
+
+                 /* Give up if the next use of reg0 is after the next
+                    use of reg_res (same insn is ok; we might have
+                    found a MEM with reg_res before, and that failed,
+                    but now we try reg0, which might work), or defs
+                    of reg_res (same insn is not ok, we'd introduce
+                    another def in the same insn) or reg0.  */
+                 if (reg0_use)
+                   {
+                     int luid = DF_INSN_LUID (reg0_use);
+
+                     /* It might seem pointless to introduce an
+                        auto-inc if there's no subsequent use of
+                        reg_res (i.e., mem_insn.insn == NULL), but
+                        the next use might be in the next iteration
+                        of a loop, and it won't hurt if we make the
+                        change even if it's not needed.  */
+                     if (mem_insn.insn
+                         && luid > DF_INSN_LUID (mem_insn.insn))
+                       reg0_use = NULL;
+
+                     rtx_insn *other_insn
+                       = get_next_ref (REGNO (inc_insn.reg_res), bb,
+                                       reg_next_def);
+
+                     if (other_insn && luid >= DF_INSN_LUID (other_insn))
+                       reg0_use = NULL;
+
+                     other_insn
+                       = get_next_ref (REGNO (inc_insn.reg0), bb,
+                                       reg_next_def);
+
+                     if (other_insn && luid > DF_INSN_LUID (other_insn))
+                       reg0_use = NULL;
+                   }
+
+                 mem_insn.insn = reg0_use;
+
+                 if (mem_insn.insn
+                     && find_address (&PATTERN (mem_insn.insn),
+                                      inc_insn.reg0) == -1)
                    {
                      if (dump_file)
                        dump_mem_insn (dump_file);
@@ -1443,38 +1602,52 @@ merge_in_block (int max_reg, basic_block bb)
       else
        {
          insn_is_add_or_inc = false;
-         mem_insn.insn = insn;
-         if (find_mem (&PATTERN (insn)))
-           success_in_block++;
+         /* We can't use auto inc/dec for bare USEs and CLOBBERs,
+            since they aren't supposed to generate any code.  */
+         rtx_code code = GET_CODE (PATTERN (insn));
+         if (code != USE && code != CLOBBER)
+           {
+             mem_insn.insn = insn;
+             if (find_mem (&PATTERN (insn)))
+               success_in_block++;
+           }
        }
-      
+
       /* If the inc insn was merged with a mem, the inc insn is gone
         and there is noting to update.  */
-      if (DF_INSN_UID_GET(uid))
+      if (df_insn_info *insn_info = DF_INSN_INFO_GET (insn))
        {
-         struct df_ref **def_rec;
-         struct df_ref **use_rec;
+         df_ref def, use;
+
          /* Need to update next use.  */
-         for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+         FOR_EACH_INSN_INFO_DEF (def, insn_info)
            {
-             struct df_ref *def = *def_rec;
+             if (reg_next_debug_use)
+               reg_next_debug_use[DF_REF_REGNO (def)] = NULL;
              reg_next_use[DF_REF_REGNO (def)] = NULL;
              reg_next_inc_use[DF_REF_REGNO (def)] = NULL;
              reg_next_def[DF_REF_REGNO (def)] = insn;
            }
-         
-         for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+
+         FOR_EACH_INSN_INFO_USE (use, insn_info)
            {
-             struct df_ref *use = *use_rec;
+             if (reg_next_debug_use)
+               /* This may seem surprising, but we know we may only
+                  modify the value of a REG between an insn and the
+                  next nondebug use thereof.  Any debug uses after
+                  the next nondebug use can be left alone, the REG
+                  will hold the expected value there.  */
+               reg_next_debug_use[DF_REF_REGNO (use)] = NULL;
              reg_next_use[DF_REF_REGNO (use)] = insn;
              if (insn_is_add_or_inc)
                reg_next_inc_use[DF_REF_REGNO (use)] = insn;
              else
                reg_next_inc_use[DF_REF_REGNO (use)] = NULL;
-           }  
+           }
        }
       else if (dump_file)
-       fprintf (dump_file, "skipping update of deleted insn %d\n", uid);
+       fprintf (dump_file, "skipping update of deleted insn %d\n",
+                INSN_UID (insn));
     }
 
   /* If we were successful, try again.  There may have been several
@@ -1484,20 +1657,60 @@ merge_in_block (int max_reg, basic_block bb)
     {
       /* In this case, we must clear these vectors since the trick of
         testing if the stale insn in the block will not work.  */
-      memset (reg_next_use, 0, max_reg * sizeof(rtx));
-      memset (reg_next_inc_use, 0, max_reg * sizeof(rtx));
-      memset (reg_next_def, 0, max_reg * sizeof(rtx));
+      if (reg_next_debug_use)
+       memset (reg_next_debug_use, 0, max_reg * sizeof (rtx));
+      memset (reg_next_use, 0, max_reg * sizeof (rtx));
+      memset (reg_next_inc_use, 0, max_reg * sizeof (rtx));
+      memset (reg_next_def, 0, max_reg * sizeof (rtx));
       df_recompute_luids (bb);
       merge_in_block (max_reg, bb);
     }
 }
 
-#endif
+/* Discover auto-inc auto-dec instructions.  */
+
+namespace {
+
+const pass_data pass_data_inc_dec =
+{
+  RTL_PASS, /* type */
+  "auto_inc_dec", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_AUTO_INC_DEC, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
+};
+
+class pass_inc_dec : public rtl_opt_pass
+{
+public:
+  pass_inc_dec (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_inc_dec, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      if (!AUTO_INC_DEC)
+       return false;
+
+      return (optimize > 0 && flag_auto_inc_dec);
+    }
+
 
-static unsigned int 
-rest_of_handle_auto_inc_dec (void)
+  unsigned int execute (function *);
+
+}; // class pass_inc_dec
+
+unsigned int
+pass_inc_dec::execute (function *fun ATTRIBUTE_UNUSED)
 {
-#ifdef AUTO_INC_DEC
+  if (!AUTO_INC_DEC)
+    return 0;
+
   basic_block bb;
   int max_reg = max_reg_num ();
 
@@ -1509,50 +1722,31 @@ rest_of_handle_auto_inc_dec (void)
   df_note_add_problem ();
   df_analyze ();
 
-  reg_next_use = XCNEWVEC (rtx, max_reg);
-  reg_next_inc_use = XCNEWVEC (rtx, max_reg);
-  reg_next_def = XCNEWVEC (rtx, max_reg);
-  FOR_EACH_BB (bb)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
+    reg_next_debug_use = XCNEWVEC (rtx_insn *, max_reg);
+  else
+    /* An earlier function may have had debug binds.  */
+    reg_next_debug_use = NULL;
+  reg_next_use = XCNEWVEC (rtx_insn *, max_reg);
+  reg_next_inc_use = XCNEWVEC (rtx_insn *, max_reg);
+  reg_next_def = XCNEWVEC (rtx_insn *, max_reg);
+  FOR_EACH_BB_FN (bb, fun)
     merge_in_block (max_reg, bb);
 
+  free (reg_next_debug_use);
   free (reg_next_use);
   free (reg_next_inc_use);
   free (reg_next_def);
 
   mem_tmp = NULL;
-#endif
+
   return 0;
 }
 
+} // anon namespace
 
-/* Discover auto-inc auto-dec instructions.  */
-
-static bool
-gate_auto_inc_dec (void)
+rtl_opt_pass *
+make_pass_inc_dec (gcc::context *ctxt)
 {
-#ifdef AUTO_INC_DEC
-  return (optimize > 0 && flag_auto_inc_dec);
-#else
-  return false;
-#endif
+  return new pass_inc_dec (ctxt);
 }
-
-
-struct tree_opt_pass pass_inc_dec =
-{
-  "auto-inc-dec",                       /* name */
-  gate_auto_inc_dec,                    /* gate */
-  rest_of_handle_auto_inc_dec,          /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_AUTO_INC_DEC,                      /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_dump_func | 
-  TODO_df_finish,                       /* todo_flags_finish */
-  0                                     /* letter */
-};
-