aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ"orn Rennecke <joern.rennecke@st.com>2005-05-13 18:22:57 +0000
committerJoern Rennecke <amylaar@gcc.gnu.org>2005-05-13 19:22:57 +0100
commit326a31e9513774c3088ed46f4d7b2ee54dd18c5b (patch)
tree244f8f1b9f276ca8684a405ccc5d61cad35ae084
parent223dcf1c00775e2727e599e4d885372490347ed0 (diff)
downloadgcc-326a31e9513774c3088ed46f4d7b2ee54dd18c5b.zip
gcc-326a31e9513774c3088ed46f4d7b2ee54dd18c5b.tar.gz
gcc-326a31e9513774c3088ed46f4d7b2ee54dd18c5b.tar.bz2
re PR middle-end/20714 (emit_no_conflict_block does invalid reordering)
PR middle-end/20714: * optabs.c (no_conflict_data): New struct. (no_conflict_move_test): New function. (emit_no_conflict_block): Use it. From-SVN: r99674
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/optabs.c59
2 files changed, 48 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 755db83..2c4c492 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2005-05-13 J"orn Rennecke <joern.rennecke@st.com>
+
+ PR middle-end/20714:
+ * optabs.c (no_conflict_data): New struct.
+ (no_conflict_move_test): New function.
+ (emit_no_conflict_block): Use it.
+
2005-05-13 Adam Nemet <anemet@lnxw.com>
* doc/invoke.texi (Debugging Options): Option
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 2955f7b..d3c4934 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -2943,6 +2943,39 @@ emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code)
emit_move_insn (target, temp);
}
+struct no_conflict_data
+{
+ rtx target, first, insn;
+ bool must_stay;
+};
+
+/* Called via note_stores by emit_no_conflict_block. Set P->must_stay
+ if the currently examined clobber / store has to stay in the list of
+ insns that constitute the actual no_conflict block. */
+static void
+no_conflict_move_test (rtx dest, rtx set, void *p0)
+{
+ struct no_conflict_data *p= p0;
+
+ /* If this inns directly contributes to setting the target, it must stay. */
+ if (reg_overlap_mentioned_p (p->target, dest))
+ p->must_stay = true;
+ /* If we haven't committed to keeping any other insns in the list yet,
+ there is nothing more to check. */
+ else if (p->insn == p->first)
+ return;
+ /* If this insn sets / clobbers a register that feeds one of the insns
+ already in the list, this insn has to stay too. */
+ else if (reg_mentioned_p (dest, PATTERN (p->first))
+ || reg_used_between_p (dest, p->first, p->insn)
+ /* Likewise if this insn depends on a register set by a previous
+ insn in the list. */
+ || (GET_CODE (set) == SET
+ && (modified_in_p (SET_SRC (set), p->first)
+ || modified_between_p (SET_SRC (set), p->first, p->insn))))
+ p->must_stay = true;
+}
+
/* Emit code to perform a series of operations on a multi-word quantity, one
word at a time.
@@ -2988,8 +3021,8 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
these from the list. */
for (insn = insns; insn; insn = next)
{
- rtx set = 0, note;
- int i;
+ rtx note;
+ struct no_conflict_data data;
next = NEXT_INSN (insn);
@@ -3000,22 +3033,12 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
remove_note (insn, note);
- if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE
- || GET_CODE (PATTERN (insn)) == CLOBBER)
- set = PATTERN (insn);
- else if (GET_CODE (PATTERN (insn)) == PARALLEL)
- {
- for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
- {
- set = XVECEXP (PATTERN (insn), 0, i);
- break;
- }
- }
-
- gcc_assert (set);
-
- if (! reg_overlap_mentioned_p (target, SET_DEST (set)))
+ data.target = target;
+ data.first = insns;
+ data.insn = insn;
+ data.must_stay = 0;
+ note_stores (PATTERN (insn), no_conflict_move_test, &data);
+ if (! data.must_stay)
{
if (PREV_INSN (insn))
NEXT_INSN (PREV_INSN (insn)) = next;