1/* { dg-do run { target { powerpc*-*-* && lp64 } } } */
2/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
3/* { dg-options "-O2" } */
4
5typedef __builtin_va_list va_list;
6#define va_start(ap, arg) __builtin_va_start (ap, arg)
7#define va_arg(ap, type)  __builtin_va_arg (ap, type)
8
9/* Testcase to check for ABI compliance of parameter passing
10   for the PowerPC64 ABI.
11   Parameter passing of integral and floating point is tested.  */
12
13extern void abort (void);
14
15typedef struct
16{
17  unsigned long gprs[8];
18  double fprs[13];
19} reg_parms_t;
20
21volatile reg_parms_t gparms;
22
23
24/* Testcase could break on future gcc's, if parameter regs are changed
25   before this asm.  To minimize the risk of that happening the test
26   consists of two sets of functions wih identical signatures:
27   foo, which does nothing except save function argument registers
28       to prevent them from getting clobbered (see PR65109),
29   foo_check, which verifies that the values of function registers
30       saved by foo match those passed to foo_check by the caller.  */
31
32#ifndef __MACH__
33#define save_parms()					 \
34  asm volatile ("ld 11,gparms@got(2)\n\t"                \
35                  "std 3,0(11)\n\t"                     \
36                  "std 4,8(11)\n\t"                     \
37                  "std 5,16(11)\n\t"                    \
38                  "std 6,24(11)\n\t"                    \
39                  "std 7,32(11)\n\t"                    \
40                  "std 8,40(11)\n\t"                    \
41                  "std 9,48(11)\n\t"                    \
42                  "std 10,56(11)\n\t"                 \
43                  "stfd 1,64(11)\n\t"                   \
44                  "stfd 2,72(11)\n\t"                   \
45                  "stfd 3,80(11)\n\t"                   \
46                  "stfd 4,88(11)\n\t"                   \
47                  "stfd 5,96(11)\n\t"                   \
48                  "stfd 6,104(11)\n\t"                  \
49                  "stfd 7,112(11)\n\t"                  \
50                  "stfd 8,120(11)\n\t"                  \
51                  "stfd 9,128(11)\n\t"                  \
52                  "stfd 10,136(11)\n\t"                 \
53                  "stfd 11,144(11)\n\t"                 \
54                  "stfd 12,152(11)\n\t"                 \
55                  "stfd 13,160(11)\n\t":::"11", "memory")
56#else
57#define save_parms()				      \
58  asm volatile ("ld r11,gparms@got(r2)\n\t"           \
59                  "std r3,0(r11)\n\t"                   \
60                  "std r4,8(r11)\n\t"                   \
61                  "std r5,16(r11)\n\t"                  \
62                  "std r6,24(r11)\n\t"                  \
63                  "std r7,32(r11)\n\t"                  \
64                  "std r8,40(r11)\n\t"                  \
65                  "std r9,48(r11)\n\t"                  \
66                  "std r10,56(r11)\n\t"                 \
67                  "stfd f1,64(r11)\n\t"                 \
68                  "stfd f2,72(r11)\n\t"                 \
69                  "stfd f3,80(r11)\n\t"                 \
70                  "stfd f4,88(r11)\n\t"                 \
71                  "stfd f5,96(r11)\n\t"                 \
72                  "stfd f6,104(r11)\n\t"                \
73                  "stfd f7,112(r11)\n\t"                \
74                  "stfd f8,120(r11)\n\t"                \
75                  "stfd f9,128(r11)\n\t"                \
76                  "stfd f10,136(r11)\n\t"               \
77                  "stfd f11,144(r11)\n\t"               \
78                  "stfd f12,152(r11)\n\t"               \
79		  "stfd f13,160(r11)\n\t":::"r11", "memory")
80#endif
81
82
83/* Stackframe structure relevant for parameter passing.  */
84typedef union
85{
86  double d;
87  unsigned long l;
88  unsigned int i[2];
89} parm_t;
90
91typedef struct sf
92{
93  struct sf *backchain;
94  long a1;
95  long a2;
96  long a3;
97#if _CALL_ELF != 2
98  long a4;
99  long a5;
100#endif
101  parm_t slot[100];
102} stack_frame_t;
103
104
105/* Paramter passing.
106   s : gpr 3
107   l : gpr 4
108   d : fpr 1
109*/
110void __attribute__ ((noinline)) fcld (char *s, long l, double d)
111{
112  save_parms ();
113
114}
115void __attribute__ ((noinline)) fcld_check (char *s, long l, double d)
116{
117  if (s != (char *) gparms.gprs[0])
118    abort ();
119
120  if (l != gparms.gprs[1])
121    abort ();
122
123  if (d != gparms.fprs[0])
124    abort ();
125}
126
127/* Paramter passing.
128   s : gpr 3
129   l : gpr 4
130   d : fpr 2
131   i : gpr 5
132*/
133void __attribute__ ((noinline))
134fcldi (char *s, long l, double d, signed int i)
135{
136  save_parms ();
137}
138
139void __attribute__ ((noinline))
140fcldi_check (char *s, long l, double d, signed int i)
141{
142  if (s != (char *) gparms.gprs[0])
143    abort ();
144
145  if (l != gparms.gprs[1])
146    abort ();
147
148  if (d != gparms.fprs[0])
149    abort ();
150
151  if ((signed long) i != gparms.gprs[3])
152    abort ();
153}
154
155/* Paramter passing.
156   s : gpr 3
157   l : gpr 4
158   d : fpr 2
159   i : gpr 5
160*/
161void __attribute__ ((noinline))
162fcldu (char *s, long l, float d, unsigned int i)
163{
164  save_parms ();
165}
166
167void __attribute__ ((noinline))
168fcldu_check (char *s, long l, float d, unsigned int i)
169{
170  if (s != (char *) gparms.gprs[0])
171    abort ();
172
173  if (l != gparms.gprs[1])
174    abort ();
175
176  if ((double) d != gparms.fprs[0])
177    abort ();
178
179  if ((unsigned long) i != gparms.gprs[3])
180    abort ();
181}
182
183/* Paramter passing.
184   s : gpr 3
185   l : slot 1
186   d : slot 2
187*/
188void __attribute__ ((noinline)) fceld (char *s, ...)
189{
190  save_parms ();
191}
192
193void __attribute__ ((noinline)) fceld_check (char *s, ...)
194{
195  stack_frame_t *sp;
196  va_list arg;
197  double d;
198  long l;
199
200  va_start (arg, s);
201
202  if (s != (char *) gparms.gprs[0])
203    abort ();
204
205  l = va_arg (arg, long);
206  d = va_arg (arg, double);
207
208  /* Go back one frame.  */
209  sp = __builtin_frame_address (0);
210  sp = sp->backchain;
211
212  if (sp->slot[1].l != l)
213    abort ();
214
215  if (sp->slot[2].d != d)
216    abort ();
217}
218
219/* Paramter passing.
220   s : gpr 3
221   i : gpr 4
222   j : gpr 5
223   d : slot 3
224   l : slot 4
225*/
226void __attribute__ ((noinline)) fciiedl (char *s, int i, int j, ...)
227{
228  save_parms ();
229}
230
231void __attribute__ ((noinline)) fciiedl_check (char *s, int i, int j, ...)
232{
233  stack_frame_t *sp;
234  va_list arg;
235  double d;
236  long l;
237
238  va_start (arg, j);
239
240  if (s != (char *) gparms.gprs[0])
241    abort ();
242
243  if ((long) i != gparms.gprs[1])
244    abort ();
245
246  if ((long) j != gparms.gprs[2])
247    abort ();
248
249  d = va_arg (arg, double);
250  l = va_arg (arg, long);
251
252  sp = __builtin_frame_address (0);
253  sp = sp->backchain;
254
255  if (sp->slot[3].d != d)
256    abort ();
257
258  if (sp->slot[4].l != l)
259    abort ();
260}
261
262/*
263Parameter     Register     Offset in parameter save area
264c             r3           0-7    (not stored in parameter save area)
265ff            f1           8-15   (not stored)
266d             r5           16-23  (not stored)
267ld            f2           24-31  (not stored)
268f             r7           32-39  (not stored)
269s             r8,r9        40-55  (not stored)
270gg            f3           56-63  (not stored)
271t             (none)       64-79  (stored in parameter save area)
272e             (none)       80-87  (stored)
273hh            f4           88-95  (stored)
274
275*/
276
277typedef struct
278{
279  int a;
280  double dd;
281} sparm;
282
283typedef union
284{
285  int i[2];
286  long l;
287  double d;
288} double_t;
289
290/* Example from ABI documentation with slight changes.
291   Paramter passing.
292   c  : gpr 3
293   ff : fpr 1
294   d  : gpr 5
295   ld : fpr 2
296   f  : gpr 7
297   s  : gpr 8 - 9
298   gg : fpr 3
299   t  : save area offset 64 - 79
300   e  : save area offset 80 - 88
301   hh : fpr 4
302*/
303
304void __attribute__ ((noinline))
305fididisdsid (int c, double ff, int d, double ld, int f,
306	     sparm s, double gg, sparm t, int e, double hh)
307{
308  save_parms ();
309}
310
311void
312fididisdsid_check (int c, double ff, int d, double ld, int f,
313		   sparm s, double gg, sparm t, int e, double hh)
314{
315  stack_frame_t *sp;
316  double_t dx, dy;
317
318  /* Parm 0: int.  */
319  if ((long) c != gparms.gprs[0])
320    abort ();
321
322  /* Parm 1: double.  */
323  if (ff != gparms.fprs[0])
324    abort ();
325
326  /* Parm 2: int.  */
327  if ((long) d != gparms.gprs[2])
328    abort ();
329
330  /* Parm 3: double.  */
331  if (ld != gparms.fprs[1])
332    abort ();
333
334  /* Parm 4: int.  */
335  if ((long) f != gparms.gprs[4])
336    abort ();
337
338  /* Parm 5: struct sparm.  */
339  dx.l = gparms.gprs[5];
340  dy.l = gparms.gprs[6];
341
342  if (s.a != dx.i[0])
343    abort ();
344  if (s.dd != dy.d)
345    abort ();
346
347  /* Parm 6: double.  */
348  if (gg != gparms.fprs[2])
349    abort ();
350
351  sp = ((stack_frame_t*)__builtin_frame_address (0))->backchain;
352
353  /* Parm 7: struct sparm.  */
354  dx.l = sp->slot[8].l;
355  dy.l = sp->slot[9].l;
356  if (t.a != dx.i[0])
357    abort ();
358  if (t.dd != dy.d)
359    abort ();
360
361  /* Parm 8: int.  */
362  if (e != sp->slot[10].l)
363    abort ();
364
365  /* Parm 9: double.  */
366
367  if (hh != gparms.fprs[3])
368    abort ();
369}
370
371int
372main ()
373{
374  char *s = "ii";
375
376#define ABI_CHECK(func, args) \
377  func args, func ## _check args
378
379  ABI_CHECK (fcld, (s, 1, 1.0));
380  ABI_CHECK (fcldi, (s, 1, 1.0, -2));
381  ABI_CHECK (fcldu, (s, 1, 1.0, 2));
382  ABI_CHECK (fceld, (s, 1, 1.0));
383  ABI_CHECK (fciiedl, (s, 1, 2, 1.0, 3));
384  ABI_CHECK (fididisdsid, (1, 1.0, 2, 2.0, -1,
385			   (sparm){3, 3.0}, 4.0, (sparm){5, 5.0},
386			   6, 7.0));
387
388  return 0;
389}
390