re PR rtl-optimization/46315 (-O2 -fno-strict-overflow causes wrong code generation)

PR rtl-optimization/46315
	* rtl.h (remove_reg_equal_equiv_notes_for_regno): Declare.
	* rtlanal.c (remove_reg_equal_equiv_notes_for_regno): New function
	extracted from...
	* dce.c (delete_corresponding_reg_eq_notes): ...here.  Rename into...
	(remove_reg_equal_equiv_notes_for_defs): ...this.
	(delete_unmarked_insns): Adjust to above renaming.
	* ifcvt.c (dead_or_predicable): Remove REG_EQUAL and REG_EQUIV notes
	referring to registers set in the insns being moved, if any.

	* df-core.c (df_ref_dump): New function extracted from...
	(df_refs_chain_dump): ...here.  Call it.
	(df_regs_chain_dump): Likewise.
	* df-problems.c (df_chain_dump): Print 'e' for uses in notes.
	* df-scan.c (df_scan_start_dump): Likewise.  Fix long line.

From-SVN: r166827
This commit is contained in:
Eric Botcazou 2010-11-16 22:13:52 +00:00 committed by Eric Botcazou
parent 2b12962772
commit 885c9b5d3a
10 changed files with 155 additions and 59 deletions

View File

@ -1,3 +1,21 @@
2010-11-16 Eric Botcazou <ebotcazou@adacore.com>
PR rtl-optimization/46315
* rtl.h (remove_reg_equal_equiv_notes_for_regno): Declare.
* rtlanal.c (remove_reg_equal_equiv_notes_for_regno): New function
extracted from...
* dce.c (delete_corresponding_reg_eq_notes): ...here. Rename into...
(remove_reg_equal_equiv_notes_for_defs): ...this.
(delete_unmarked_insns): Adjust to above renaming.
* ifcvt.c (dead_or_predicable): Remove REG_EQUAL and REG_EQUIV notes
referring to registers set in the insns being moved, if any.
* df-core.c (df_ref_dump): New function extracted from...
(df_refs_chain_dump): ...here. Call it.
(df_regs_chain_dump): Likewise.
* df-problems.c (df_chain_dump): Print 'e' for uses in notes.
* df-scan.c (df_scan_start_dump): Likewise. Fix long line.
2010-11-16 Andreas Schwab <schwab@linux-m68k.org>
PR rtl-optimization/46395

View File

@ -466,36 +466,16 @@ find_call_stack_args (rtx call_insn, bool do_mark, bool fast,
}
/* Delete all REG_EQUAL notes of the registers INSN writes, to prevent
bad dangling REG_EQUAL notes. */
/* Remove all REG_EQUAL and REG_EQUIV notes referring to the registers INSN
writes to. */
static void
delete_corresponding_reg_eq_notes (rtx insn)
remove_reg_equal_equiv_notes_for_defs (rtx insn)
{
df_ref *def_rec;
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
{
df_ref def = *def_rec;
unsigned int regno = DF_REF_REGNO (def);
/* This loop is a little tricky. We cannot just go down the
chain because it is being modified by the actions in the
loop. So we just get the head. We plan to drain the list
anyway. */
while (DF_REG_EQ_USE_CHAIN (regno))
{
df_ref eq_use = DF_REG_EQ_USE_CHAIN (regno);
rtx noted_insn = DF_REF_INSN (eq_use);
rtx note = find_reg_note (noted_insn, REG_EQUAL, NULL_RTX);
if (!note)
note = find_reg_note (noted_insn, REG_EQUIV, NULL_RTX);
/* This assert is generally triggered when someone deletes a
REG_EQUAL or REG_EQUIV note by hacking the list manually
rather than calling remove_note. */
gcc_assert (note);
remove_note (noted_insn, note);
}
}
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
remove_reg_equal_equiv_notes_for_regno (DF_REF_REGNO (*def_rec));
}
@ -544,9 +524,9 @@ delete_unmarked_insns (void)
if (dump_file)
fprintf (dump_file, "DCE: Deleting insn %d\n", INSN_UID (insn));
/* Before we delete the insn we have to delete REG_EQUAL notes
/* Before we delete the insn we have to remove the REG_EQUAL notes
for the destination regs in order to avoid dangling notes. */
delete_corresponding_reg_eq_notes (insn);
remove_reg_equal_equiv_notes_for_defs (insn);
/* If a pure or const call is deleted, this may make the cfg
have unreachable blocks. We rememeber this and call

View File

@ -2051,6 +2051,17 @@ df_dump_bottom (basic_block bb, FILE *file)
}
static void
df_ref_dump (df_ref ref, FILE *file)
{
fprintf (file, "%c%d(%d)",
DF_REF_REG_DEF_P (ref)
? 'd'
: (DF_REF_FLAGS (ref) & DF_REF_IN_NOTE) ? 'e' : 'u',
DF_REF_ID (ref),
DF_REF_REGNO (ref));
}
void
df_refs_chain_dump (df_ref *ref_rec, bool follow_chain, FILE *file)
{
@ -2058,10 +2069,7 @@ df_refs_chain_dump (df_ref *ref_rec, bool follow_chain, FILE *file)
while (*ref_rec)
{
df_ref ref = *ref_rec;
fprintf (file, "%c%d(%d)",
DF_REF_REG_DEF_P (ref) ? 'd' : (DF_REF_FLAGS (ref) & DF_REF_IN_NOTE) ? 'e' : 'u',
DF_REF_ID (ref),
DF_REF_REGNO (ref));
df_ref_dump (ref, file);
if (follow_chain)
df_chain_dump (DF_REF_CHAIN (ref), file);
ref_rec++;
@ -2078,10 +2086,7 @@ df_regs_chain_dump (df_ref ref, FILE *file)
fprintf (file, "{ ");
while (ref)
{
fprintf (file, "%c%d(%d) ",
DF_REF_REG_DEF_P (ref) ? 'd' : 'u',
DF_REF_ID (ref),
DF_REF_REGNO (ref));
df_ref_dump (ref, file);
ref = DF_REF_NEXT_REG (ref);
}
fprintf (file, "}");

View File

@ -109,10 +109,13 @@ df_chain_dump (struct df_link *link, FILE *file)
for (; link; link = link->next)
{
fprintf (file, "%c%d(bb %d insn %d) ",
DF_REF_REG_DEF_P (link->ref) ? 'd' : 'u',
DF_REF_REG_DEF_P (link->ref)
? 'd'
: (DF_REF_FLAGS (link->ref) & DF_REF_IN_NOTE) ? 'e' : 'u',
DF_REF_ID (link->ref),
DF_REF_BBNO (link->ref),
DF_REF_IS_ARTIFICIAL (link->ref) ? -1 : DF_REF_INSN_UID (link->ref));
DF_REF_IS_ARTIFICIAL (link->ref)
? -1 : DF_REF_INSN_UID (link->ref));
}
fprintf (file, "}");
}

View File

@ -445,7 +445,7 @@ df_scan_start_dump (FILE *file ATTRIBUTE_UNUSED)
}
if (DF_REG_EQ_USE_COUNT (i))
{
fprintf (file, "%s%dd", sep, DF_REG_EQ_USE_COUNT (i));
fprintf (file, "%s%de", sep, DF_REG_EQ_USE_COUNT (i));
ecount += DF_REG_EQ_USE_COUNT (i);
}
fprintf (file, "} ");
@ -461,8 +461,10 @@ df_scan_start_dump (FILE *file ATTRIBUTE_UNUSED)
icount++;
}
fprintf (file, "\n;; total ref usage %d{%dd,%du,%de} in %d{%d regular + %d call} insns.\n",
dcount + ucount + ecount, dcount, ucount, ecount, icount + ccount, icount, ccount);
fprintf (file, "\n;; total ref usage %d{%dd,%du,%de}"
" in %d{%d regular + %d call} insns.\n",
dcount + ucount + ecount, dcount, ucount, ecount,
icount + ccount, icount, ccount);
}
/* Dump the bb_info for a given basic block. */

View File

@ -3998,6 +3998,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
basic_block other_bb, basic_block new_dest, int reversep)
{
rtx head, end, jump, earliest = NULL_RTX, old_dest, new_label = NULL_RTX;
bitmap merge_set = NULL, merge_set_noclobber = NULL;
/* Number of pending changes. */
int n_validated_changes = 0;
@ -4086,6 +4087,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
earliest = jump;
}
#endif
/* Try the NCE path if the CE path did not result in any changes. */
if (n_validated_changes == 0)
{
@ -4094,9 +4096,8 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
that any registers modified are dead at the branch site. */
rtx insn, cond, prev;
bitmap merge_set, merge_set_noclobber, test_live, test_set;
unsigned i, fail = 0;
bitmap_iterator bi;
bitmap test_live, test_set;
bool intersect = false;
/* Check for no calls or trapping operations. */
for (insn = head; ; insn = NEXT_INSN (insn))
@ -4138,12 +4139,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
merge_set = BITMAP_ALLOC (&reg_obstack);
merge_set_noclobber = BITMAP_ALLOC (&reg_obstack);
test_live = BITMAP_ALLOC (&reg_obstack);
test_set = BITMAP_ALLOC (&reg_obstack);
/* ??? bb->local_set is only valid during calculate_global_regs_live,
so we must recompute usage for MERGE_BB. Not so bad, I suppose,
since we've already asserted that MERGE_BB is small. */
/* If we allocated new pseudos (e.g. in the conditional move
expander called from noce_emit_cmove), we must resize the
array first. */
@ -4164,17 +4160,22 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
if (! reload_completed
&& targetm.small_register_classes_for_mode_p (VOIDmode))
{
unsigned i;
bitmap_iterator bi;
EXECUTE_IF_SET_IN_BITMAP (merge_set_noclobber, 0, i, bi)
{
if (i < FIRST_PSEUDO_REGISTER
&& ! fixed_regs[i]
&& ! global_regs[i])
fail = 1;
goto fail;
}
}
/* For TEST, we're interested in a range of insns, not a whole block.
Moreover, we're interested in the insns live from OTHER_BB. */
test_live = BITMAP_ALLOC (&reg_obstack);
test_set = BITMAP_ALLOC (&reg_obstack);
/* The loop below takes the set of live registers
after JUMP, and calculates the live set before EARLIEST. */
@ -4195,23 +4196,21 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
/* We can perform the transformation if
MERGE_SET_NOCLOBBER & TEST_SET
and
MERGE_SET & TEST_LIVE)
MERGE_SET & TEST_LIVE
and
TEST_SET & DF_LIVE_IN (merge_bb)
are empty. */
if (bitmap_intersect_p (test_set, merge_set_noclobber)
|| bitmap_intersect_p (test_live, merge_set)
if (bitmap_intersect_p (merge_set_noclobber, test_set)
|| bitmap_intersect_p (merge_set, test_live)
|| bitmap_intersect_p (test_set, df_get_live_in (merge_bb)))
fail = 1;
intersect = true;
BITMAP_FREE (merge_set_noclobber);
BITMAP_FREE (merge_set);
BITMAP_FREE (test_live);
BITMAP_FREE (test_set);
if (fail)
return FALSE;
if (intersect)
goto fail;
}
no_body:
@ -4261,8 +4260,8 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
if (end == BB_END (merge_bb))
BB_END (merge_bb) = PREV_INSN (head);
/* PR 21767: When moving insns above a conditional branch, REG_EQUAL
notes might become invalid. */
/* PR 21767: when moving insns above a conditional branch, the REG_EQUAL
notes being moved might become invalid. */
insn = head;
do
{
@ -4279,6 +4278,20 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
remove_note (insn, note);
} while (insn != end && (insn = NEXT_INSN (insn)));
/* PR46315: when moving insns above a conditional branch, the REG_EQUAL
notes referring to the registers being set might become invalid. */
if (merge_set)
{
unsigned i;
bitmap_iterator bi;
EXECUTE_IF_SET_IN_BITMAP (merge_set_noclobber, 0, i, bi)
remove_reg_equal_equiv_notes_for_regno (i);
BITMAP_FREE (merge_set);
BITMAP_FREE (merge_set_noclobber);
}
reorder_insns (head, end, PREV_INSN (earliest));
}
@ -4295,6 +4308,12 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
cancel:
cancel_changes (0);
fail:
if (merge_set)
{
BITMAP_FREE (merge_set);
BITMAP_FREE (merge_set_noclobber);
}
return FALSE;
}

View File

@ -1892,6 +1892,7 @@ extern rtx alloc_reg_note (enum reg_note, rtx, rtx);
extern void add_reg_note (rtx, enum reg_note, rtx);
extern void remove_note (rtx, const_rtx);
extern void remove_reg_equal_equiv_notes (rtx);
extern void remove_reg_equal_equiv_notes_for_regno (unsigned int);
extern int side_effects_p (const_rtx);
extern int volatile_refs_p (const_rtx);
extern int volatile_insn_p (const_rtx);

View File

@ -1941,6 +1941,33 @@ remove_reg_equal_equiv_notes (rtx insn)
}
}
/* Remove all REG_EQUAL and REG_EQUIV notes referring to REGNO. */
void
remove_reg_equal_equiv_notes_for_regno (unsigned int regno)
{
df_ref eq_use;
if (!df)
return;
/* This loop is a little tricky. We cannot just go down the chain because
it is being modified by some actions in the loop. So we just iterate
over the head. We plan to drain the list anyway. */
while ((eq_use = DF_REG_EQ_USE_CHAIN (regno)) != NULL)
{
rtx insn = DF_REF_INSN (eq_use);
rtx note = find_reg_equal_equiv_note (insn);
/* This assert is generally triggered when someone deletes a REG_EQUAL
or REG_EQUIV note by hacking the list manually rather than calling
remove_note. */
gcc_assert (note);
remove_note (insn, note);
}
}
/* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
return 1 if it is found. A simple equality test is used to determine if
NODE matches. */

View File

@ -1,3 +1,7 @@
2010-11-16 Eric Botcazou <ebotcazou@adacore.com>
* gcc.target/rx/pack.c: New test.
2010-11-16 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
Tobias Burnus <burnus@net-b.de>

View File

@ -0,0 +1,37 @@
/* PR rtl-optimization/46315 */
/* Reported by Magnus Granberg <zorry@gentoo.org> */
/* { dg-do run } */
/* { dg-options "-O2 -fno-strict-overflow" } */
extern void abort (void);
static char const *
parse_ranged (char const *s, int digits)
{
int n = 0;
char const *lim = s + digits;
while (s < lim)
{
unsigned d = *s++ - '0';
if (9 < d)
return 0;
n = 10 * n + d;
}
return s && 0 <= n && n <= 59 ? s : 0;
}
int main(void)
{
const char *s = "10092240";
s = parse_ranged (s, 2);
s = parse_ranged (s, 2);
s = parse_ranged (s, 2);
s = parse_ranged (s, 2);
if (!s || *s != '\0')
abort();
return 0;
}