diff options
author | J"orn Rennecke <joern.rennecke@st.com> | 2005-05-13 18:22:57 +0000 |
---|---|---|
committer | J"orn Rennecke <joern.rennecke@st.com> | 2005-05-13 18:22:57 +0000 |
commit | 993020bd68db7d6e162ab99b56c5d5fa5f5e0f43 (patch) | |
tree | 244f8f1b9f276ca8684a405ccc5d61cad35ae084 /gcc/optabs.c | |
parent | 9f83e1ced4799a1b502067769d496dd3315fd639 (diff) |
PR middle-end/20714:
* optabs.c (no_conflict_data): New struct.
(no_conflict_move_test): New function.
(emit_no_conflict_block): Use it.
git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@99674 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r-- | gcc/optabs.c | 59 |
1 files changed, 41 insertions, 18 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c index 2955f7b3ad9..d3c4934c544 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; |