aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/dce.c34
-rw-r--r--gcc/df-core.c21
-rw-r--r--gcc/df-problems.c7
-rw-r--r--gcc/df-scan.c8
-rw-r--r--gcc/ifcvt.c57
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/rtlanal.c27
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/pr46315.c37
10 files changed, 155 insertions, 59 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a572780..4e4f64a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/dce.c b/gcc/dce.c
index 2d4f3a6..a7697f5 100644
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -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);
- }
- }
+ 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
diff --git a/gcc/df-core.c b/gcc/df-core.c
index 86ed239..dacefc7 100644
--- a/gcc/df-core.c
+++ b/gcc/df-core.c
@@ -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, "}");
diff --git a/gcc/df-problems.c b/gcc/df-problems.c
index 3f5627f..559af91 100644
--- a/gcc/df-problems.c
+++ b/gcc/df-problems.c
@@ -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, "}");
}
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 850f067..5cda897 100644
--- a/gcc/df-scan.c
+++ b/gcc/df-scan.c
@@ -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. */
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 58ee90c..c91bbbf 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -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;
}
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 66751a6..745d6f4 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -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);
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 930828a..eb4d3ab 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -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. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f6f9671..afb99ff 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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>
diff --git a/gcc/testsuite/gcc.dg/pr46315.c b/gcc/testsuite/gcc.dg/pr46315.c
new file mode 100644
index 0000000..2349284
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr46315.c
@@ -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;
+}