aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeffrey A Law <law@cygnus.com>1998-12-12 23:03:54 +0000
committerJeff Law <law@gcc.gnu.org>1998-12-12 16:03:54 -0700
commit941c63ac30be855420bc79b702355594712cff90 (patch)
tree8cb9f662656a67c7745f1ade226aa8d33838a4e0
parent8d4c79be50f79381b6306600b304ea3182a8d63c (diff)
downloadgcc-941c63ac30be855420bc79b702355594712cff90.zip
gcc-941c63ac30be855420bc79b702355594712cff90.tar.gz
gcc-941c63ac30be855420bc79b702355594712cff90.tar.bz2
rtlanal.c (multiple_sets): New function.
* rtlanal.c (multiple_sets): New function. * rtl.h (multiple_sets): Declare it. * local-alloc.c (wipe_dead_reg): Use it. * global.c (global_conflicts): Likewise. Should fix the m68k bootstrap problems. From-SVN: r24283
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/global.c13
-rw-r--r--gcc/local-alloc.c11
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/rtlanal.c32
5 files changed, 59 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f2a101b..b0e12f6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+Sat Dec 12 23:39:10 1998 Jeffrey A Law (law@cygnus.com)
+
+ * rtlanal.c (multiple_sets): New function.
+ * rtl.h (multiple_sets): Declare it.
+ * local-alloc.c (wipe_dead_reg): Use it.
+ * global.c (global_conflicts): Likewise.
+
Sat Dec 12 22:13:02 1998 Mark Mitchell <mark@markmitchell.com>
* global.c (record_conflicts): Don't use an array of shorts to
diff --git a/gcc/global.c b/gcc/global.c
index 6720172..06277ee 100644
--- a/gcc/global.c
+++ b/gcc/global.c
@@ -739,9 +739,16 @@ global_conflicts ()
/* If INSN has multiple outputs, then any reg that dies here
and is used inside of an output
- must conflict with the other outputs. */
-
- if (GET_CODE (PATTERN (insn)) == PARALLEL && !single_set (insn))
+ must conflict with the other outputs.
+
+ It is unsafe to use !single_set here since it will ignore an
+ unused output. Just because an output is unused does not mean
+ the compiler can assume the side effect will not occur.
+ Consider if REG appears in the address of an output and we
+ reload the output. If we allocate REG to the same hard
+ register as an unused output we could set the hard register
+ before the output reload insn. */
+ if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_DEAD)
{
diff --git a/gcc/local-alloc.c b/gcc/local-alloc.c
index f7d12d2..85cb8af 100644
--- a/gcc/local-alloc.c
+++ b/gcc/local-alloc.c
@@ -1876,9 +1876,16 @@ wipe_dead_reg (reg, output_p)
/* If this insn has multiple results,
and the dead reg is used in one of the results,
extend its life to after this insn,
- so it won't get allocated together with any other result of this insn. */
+ so it won't get allocated together with any other result of this insn.
+
+ It is unsafe to use !single_set here since it will ignore an unused
+ output. Just because an output is unused does not mean the compiler
+ can assume the side effect will not occur. Consider if REG appears
+ in the address of an output and we reload the output. If we allocate
+ REG to the same hard register as an unused output we could set the hard
+ register before the output reload insn. */
if (GET_CODE (PATTERN (this_insn)) == PARALLEL
- && !single_set (this_insn))
+ && multiple_sets (this_insn))
{
int i;
for (i = XVECLEN (PATTERN (this_insn), 0) - 1; i >= 0; i--)
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 940de73..95ddbd1 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -988,6 +988,7 @@ extern int no_labels_between_p PROTO((rtx, rtx));
extern int modified_in_p PROTO((rtx, rtx));
extern int reg_set_p PROTO((rtx, rtx));
extern rtx single_set PROTO((rtx));
+extern rtx multiple_sets PROTO((rtx));
extern rtx find_last_value PROTO((rtx, rtx *, rtx));
extern int refers_to_regno_p PROTO((int, int, rtx, rtx *));
extern int reg_overlap_mentioned_p PROTO((rtx, rtx));
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 0abe244..f298ab2 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -690,6 +690,38 @@ single_set (insn)
return 0;
}
+
+/* Given an INSN, return nonzero if it has more than one SET, else return
+ zero. */
+
+rtx
+multiple_sets (insn)
+ rtx insn;
+{
+ rtx found;
+ int i;
+
+ /* INSN must be an insn. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ return 0;
+
+ /* Only a PARALLEL can have multiple SETs. */
+ if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ for (i = 0, found = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+ if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
+ {
+ /* If we have already found a SET, then return now. */
+ if (found)
+ return 1;
+ else
+ found = 1;
+ }
+ }
+
+ /* Either zero or one SET. */
+ return 0;
+}
/* Return the last thing that X was assigned from before *PINSN. Verify that
the object is not modified up to VALID_TO. If it was, if we hit