loop-invariant: Fix -fcompare-debug failure [PR103837]

In the following testcase we have a -fcompare-debug failure, because
can_move_invariant_reg doesn't ignore DEBUG_INSNs in its decisions.
In the testcase we have due to uninitialized variable:
  loop_header
    debug_insn using pseudo84
    pseudo84 = invariant
    insn using pseudo84
  end loop
and with -g decide not to move the pseudo84 = invariant before the
loop header; in this case not resetting the debug insns might be fine.
But, we could have also:
  pseudo84 = whatever
  loop_header
    debug_insn using pseudo84
    pseudo84 = invariant
    insn using pseudo84
  end loop
and in that case not resetting the debug insns would result in wrong-debug.
And, we don't really have generally a good substitution on what pseudo84
contains, it could inherit various values from different paths.
So, the following patch ignores DEBUG_INSNs in the decisions, and if there
are any that previously prevented the optimization, resets them before
return true.

2021-12-28  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/103837
	* loop-invariant.c (can_move_invariant_reg): Ignore DEBUG_INSNs in
	the decisions whether to return false or continue and right before
	returning true reset those debug insns that previously caused
	returning false.

	* gcc.dg/pr103837.c: New test.
This commit is contained in:
Jakub Jelinek 2021-12-28 17:40:17 +01:00
parent 78ee8381bf
commit 3c5fd3616f
2 changed files with 34 additions and 4 deletions

View File

@ -1691,6 +1691,7 @@ can_move_invariant_reg (class loop *loop, struct invariant *inv, rtx reg)
unsigned int dest_regno, defs_in_loop_count = 0;
rtx_insn *insn = inv->insn;
basic_block bb = BLOCK_FOR_INSN (inv->insn);
auto_vec <rtx_insn *, 16> debug_insns_to_reset;
/* We ignore hard register and memory access for cost and complexity reasons.
Hard register are few at this stage and expensive to consider as they
@ -1725,10 +1726,13 @@ can_move_invariant_reg (class loop *loop, struct invariant *inv, rtx reg)
continue;
/* Don't move if a use is not dominated by def in insn. */
if (use_bb == bb && DF_INSN_LUID (insn) >= DF_INSN_LUID (use_insn))
return false;
if (!dominated_by_p (CDI_DOMINATORS, use_bb, bb))
return false;
if ((use_bb == bb && DF_INSN_LUID (insn) >= DF_INSN_LUID (use_insn))
|| !dominated_by_p (CDI_DOMINATORS, use_bb, bb))
{
if (!DEBUG_INSN_P (use_insn))
return false;
debug_insns_to_reset.safe_push (use_insn);
}
}
/* Check for other defs. Any other def in the loop might reach a use
@ -1751,6 +1755,13 @@ can_move_invariant_reg (class loop *loop, struct invariant *inv, rtx reg)
return false;
}
/* Reset debug uses if a use is not dominated by def in insn. */
for (auto use_insn : debug_insns_to_reset)
{
INSN_VAR_LOCATION_LOC (use_insn) = gen_rtx_UNKNOWN_VAR_LOC ();
df_insn_rescan (use_insn);
}
return true;
}

View File

@ -0,0 +1,19 @@
/* PR rtl-optimization/103837 */
/* { dg-do compile } */
/* { dg-options "-Og -fcompare-debug -fmove-loop-invariants -fnon-call-exceptions -fexceptions -fdelete-dead-exceptions -fno-tree-dce -w" } */
unsigned long int
foo (int x)
{
double a;
int b;
unsigned long int ret = a;
for (;;)
{
b = !!((int) a);
a = x;
}
return ret;
}