1/* Test for reload failing to eliminate from argp to sp.  */
2/* { dg-do run } */
3/* { dg-require-effective-target ilp32 } */
4/* { dg-require-effective-target nonpic } */
5/* { dg-options "-O2 -fomit-frame-pointer" } */
6
7static int ustrsize (const char *s);
8static int (*ucwidth) (int c);
9static int (*ugetxc) (const char **s);
10static int (*usetc) (char *s, int c);
11
12char *ustrzcat(char *dest, int size, const char *src)
13{
14   int pos = ustrsize(dest);
15   int c;
16
17   size -= pos + ucwidth(0);
18
19   while ((c = ugetxc(&src)) != 0) {
20      size -= ucwidth(c);
21      if (size < 0)
22         break;
23
24      pos += usetc(dest+pos, c);
25   }
26
27   usetc(dest+pos, 0);
28
29   return dest;
30}
31
32static int __attribute__((noinline))
33ustrsize (const char *s)
34{
35  return 0;
36}
37
38static int
39ucwidth_ (int c)
40{
41  return 1;
42}
43
44static int
45ugetxc_ (const char **s)
46{
47  return '\0';
48}
49
50static int
51usetc_ (char *s, int c)
52{
53  return 1;
54}
55
56int
57main()
58{
59  ucwidth = ucwidth_;
60  ugetxc = ugetxc_;
61  usetc = usetc_;
62
63  /* ??? It is impossible to explicitly modify the hard frame pointer.
64     This will run afoul of code in flow.c that declines to mark regs
65     in eliminate_regs in regs_ever_used.  Apparently, we have to wait
66     for reload to decide that it won't need a frame pointer before a
67     variable can be allocated to %ebp.
68
69     So save, restore, and clobber %ebp by hand.  */
70
71  asm ("pushl %%ebp\n\t"
72       "movl $-1, %%ebp\n\t"
73       "pushl $0\n\t"
74       "pushl $0\n\t"
75       "pushl $0\n\t"
76       "call %P0\n\t"
77       "addl $12, %%esp\n\t"
78       "popl %%ebp"
79       : : "i"(ustrzcat) : "memory" );
80
81  return 0;
82}
83