summaryrefslogtreecommitdiff
path: root/gcc/local-alloc.c
diff options
context:
space:
mode:
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>1992-10-09 11:28:53 +0000
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>1992-10-09 11:28:53 +0000
commit048b864a2baa226a4200c5d42284a510bd99ee93 (patch)
treea59d3caf4d7fbf22dfca68da49523f479dbac707 /gcc/local-alloc.c
parentc70132b67a89a17f49a4149dea93e7ff018114a1 (diff)
downloadgcc-048b864a2baa226a4200c5d42284a510bd99ee93.tar.gz
(optimize_reg_copy_1): Tighten up code to properly handle the case
when SRC or DEST is a multi-word hard register and only some parts of the register are set or used. Also, avoid updating register status for DEST if we can't do the optimization. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@2380 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/local-alloc.c')
-rw-r--r--gcc/local-alloc.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/gcc/local-alloc.c b/gcc/local-alloc.c
index 918f13fc982..830f89fd0aa 100644
--- a/gcc/local-alloc.c
+++ b/gcc/local-alloc.c
@@ -686,11 +686,16 @@ optimize_reg_copy_1 (insn, dest, src)
&& reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
break;
- if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0)
+ /* See if all of SRC dies in P. This test is slightly more
+ conservative than it needs to be. */
+ if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0
+ && GET_MODE (XEXP (note, 0)) == GET_MODE (src))
{
int failed = 0;
int length = 0;
+ int d_length = 0;
int n_calls = 0;
+ int d_n_calls = 0;
/* We can do the optimization. Scan forward from INSN again,
replacing regs as we go. Set FAILED if a replacement can't
@@ -702,9 +707,23 @@ optimize_reg_copy_1 (insn, dest, src)
q != next_real_insn (p);
q = next_real_insn (q))
{
- if (reg_mentioned_p (src, PATTERN (q)))
+ if (reg_overlap_mentioned_p (src, PATTERN (q)))
{
- if (validate_replace_rtx (src, dest, q))
+ /* If SRC is a hard register, we might miss some
+ overlapping registers with validate_replace_rtx,
+ so we would have to undo it. We can't if DEST is
+ present in the insn, so fail in that combination
+ of cases. */
+ if (sregno < FIRST_PSEUDO_REGISTER
+ && reg_mentioned_p (dest, PATTERN (q)))
+ failed = 1;
+
+ /* Replace all uses and make sure that the register
+ isn't still present. */
+ else if (validate_replace_rtx (src, dest, q)
+ && (sregno >= FIRST_PSEUDO_REGISTER
+ || ! reg_overlap_mentioned_p (src,
+ PATTERN (q))))
{
/* We assume that a register is used exactly once per
insn in the updates below. If this is not correct,
@@ -715,26 +734,31 @@ optimize_reg_copy_1 (insn, dest, src)
reg_n_refs[dregno] += loop_depth;
}
else
- failed = 1;
+ {
+ validate_replace_rtx (dest, src, q);
+ failed = 1;
+ }
}
/* Count the insns and CALL_INSNs passed. If we passed the
death note of DEST, show increased live length. */
length++;
if (dest_death)
- reg_live_length[dregno]++;
+ d_length++;
if (GET_CODE (q) == CALL_INSN)
{
n_calls++;
if (dest_death)
- reg_n_calls_crossed[dregno]++;
+ d_n_calls++;
}
/* If DEST dies here, remove the death note and save it for
- later. */
+ later. Make sure ALL of DEST dies here; again, this is
+ overly conservative. */
if (dest_death == 0
- && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0)
+ && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0
+ && GET_MODE (XEXP (dest_death, 0)) == GET_MODE (dest))
remove_note (q, dest_death);
}
@@ -746,6 +770,12 @@ optimize_reg_copy_1 (insn, dest, src)
reg_n_calls_crossed[sregno] -= n_calls;
}
+ if (dregno >= FIRST_PSEUDO_REGISTER)
+ {
+ reg_live_length[dregno] += d_length;
+ reg_n_calls_crossed[dregno] += d_n_calls;
+ }
+
/* Move death note of SRC from P to INSN. */
remove_note (p, note);
XEXP (note, 1) = REG_NOTES (insn);
@@ -761,6 +791,12 @@ optimize_reg_copy_1 (insn, dest, src)
return;
}
+
+ /* If SRC is a hard register which is set or killed in some other
+ way, we can't do this optimization. */
+ else if (sregno < FIRST_PSEUDO_REGISTER
+ && dead_or_set_p (p, src))
+ break;
}
}