summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/df-scan.c12
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/globalreg-1.c54
4 files changed, 72 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 390ed0db2e6..f6f8a862a6f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2007-10-22 Seongbae Park <seongbae.park@gmail.com>
+ David S. Miller <davem@davemloft.net>
+
+ * df-scan.c (df_get_call_refs): Mark global registers as both a
+ DF_REF_REG_USE and a non-clobber DF_REF_REG_DEF.
+
2007-10-22 Dorit Nuzman <dorit@il.ibm.com>
PR tree-optimization/33834
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index f4ced0d34c9..cc6866b6b78 100644
--- a/gcc/df-scan.c
+++ b/gcc/df-scan.c
@@ -3109,18 +3109,22 @@ df_get_call_refs (struct df_collection_rec * collection_rec,
so they are recorded as used. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i])
- df_ref_record (collection_rec, regno_reg_rtx[i],
- NULL, bb, insn, DF_REF_REG_USE, flags);
+ {
+ df_ref_record (collection_rec, regno_reg_rtx[i],
+ NULL, bb, insn, DF_REF_REG_USE, flags);
+ df_ref_record (collection_rec, regno_reg_rtx[i],
+ NULL, bb, insn, DF_REF_REG_DEF, flags);
+ }
is_sibling_call = SIBLING_CALL_P (insn);
EXECUTE_IF_SET_IN_BITMAP (df_invalidated_by_call, 0, ui, bi)
{
- if ((!bitmap_bit_p (defs_generated, ui))
+ if (!global_regs[ui]
+ && (!bitmap_bit_p (defs_generated, ui))
&& (!is_sibling_call
|| !bitmap_bit_p (df->exit_block_uses, ui)
|| refers_to_regno_p (ui, ui+1,
current_function_return_rtx, NULL)))
-
df_ref_record (collection_rec, regno_reg_rtx[ui],
NULL, bb, insn, DF_REF_REG_DEF, DF_REF_MAY_CLOBBER | flags);
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ecc4e8010a0..39758307a1b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2007-10-22 David S. Miller <davem@davemloft.net>
+
+ * gcc.dg/globalreg-1.c: New test.
+
2007-10-22 Martin Michlmayr <tbm@cyrius.com>
Dorit Nuzman <dorit@il.ibm.com>
diff --git a/gcc/testsuite/gcc.dg/globalreg-1.c b/gcc/testsuite/gcc.dg/globalreg-1.c
new file mode 100644
index 00000000000..f54976dce1d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/globalreg-1.c
@@ -0,0 +1,54 @@
+/* { dg-do run { target sparc*-*-* } } */
+/* { dg-options "-std=gnu99 -Os" } */
+
+/* This is a massively distilled test case based upon
+ mm/memory.c:unmap_vmas() in the Linux kernel when compiled
+ on sparc64 for SMP which uses a global register as the
+ base of the per-cpu variable area.
+
+ Because of a bug in global register handling in the dataflow
+ code, the loop-invariant pass would move 'expression(regval)'
+ outside of the loop. */
+
+extern void exit(int);
+extern void abort(void);
+
+register unsigned long regval __asm__("g6");
+
+extern void cond_resched(void);
+
+unsigned int var;
+
+static unsigned long expression(unsigned long v)
+{
+ unsigned long ret;
+
+ __asm__("" : "=r" (ret) : "0" (0));
+ return ret + v;
+}
+
+void func(unsigned long *pp)
+{
+ int i;
+
+ for (i = 0; i < 56; i++) {
+ cond_resched();
+ *pp = expression(regval);
+ }
+}
+
+void __attribute__((noinline)) cond_resched(void)
+{
+ regval++;
+}
+
+int main(void)
+{
+ unsigned long val;
+
+ regval = 100;
+ func(&val);
+ if (val != 156)
+ abort();
+ exit(0);
+}