@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.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.
@@ -53,6 +54,21 @@ along with GCC; see the file COPYING3. If not see
...
*(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
@@ -61,6 +77,7 @@ along with GCC; see the file COPYING3. If not see
becomes
+ ...
*(a += c) pre
@@ -75,8 +92,8 @@ along with GCC; see the file COPYING3. If not see
becomes
b <- a
- ...
*(b += c) post
+ ...
(4) FORM_POST_INC
@@ -87,6 +104,8 @@ along with GCC; see the file COPYING3. If not see
becomes
*(a += c) post
+ ...
+
There are three types of values of c.
@@ -393,6 +412,7 @@ dump_mem_insn (FILE *file)
must be compared with the current block.
*/
+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;
@@ -509,27 +529,83 @@ attempt_change (rtx new_addr, rtx inc_reg)
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;
@@ -544,10 +620,26 @@ attempt_change (rtx new_addr, rtx inc_reg)
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))
@@ -1332,7 +1424,20 @@ merge_in_block (int max_reg, basic_block bb)
bool insn_is_add_or_inc = true;
if (!NONDEBUG_INSN_P (insn))
- continue;
+ {
+ 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
@@ -1410,7 +1515,7 @@ merge_in_block (int max_reg, basic_block bb)
where reg1 is a constant (*).
- The next use of reg_res was not idenfied by
+ 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
@@ -1510,6 +1615,8 @@ merge_in_block (int max_reg, basic_block bb)
/* Need to update next use. */
FOR_EACH_INSN_INFO_DEF (def, insn_info)
{
+ 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;
@@ -1517,6 +1624,13 @@ merge_in_block (int max_reg, basic_block bb)
FOR_EACH_INSN_INFO_USE (use, insn_info)
{
+ 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;
@@ -1536,6 +1650,8 @@ 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. */
+ 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));
@@ -1599,12 +1715,18 @@ pass_inc_dec::execute (function *fun ATTRIBUTE_UNUSED)
df_note_add_problem ();
df_analyze ();
+ 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);