summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.target/sparc/globalreg-1.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/gcc.target/sparc/globalreg-1.c')
-rw-r--r--gcc/testsuite/gcc.target/sparc/globalreg-1.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.target/sparc/globalreg-1.c b/gcc/testsuite/gcc.target/sparc/globalreg-1.c
new file mode 100644
index 000000000..3839d9f13
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/globalreg-1.c
@@ -0,0 +1,54 @@
+/* { dg-do run } */
+/* { 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);
+}