1
#ifndef _avcall_mips64_c /*-*- C -*-*/
2
#define _avcall_mips64_c
4
Copyright 1993 Bill Triggs, <Bill.Triggs@inrialpes.fr>
5
Copyright 1995-1999 Bruno Haible, <bruno@clisp.org>
7
This is free software distributed under the GNU General Public
8
Licence described in the file COPYING. Contact the author if
9
you don't have this or can't live with it. There is ABSOLUTELY
10
NO WARRANTY, explicit or implied, on this software.
12
/*----------------------------------------------------------------------
13
!!! THIS ROUTINE MUST BE COMPILED gcc -O !!!
15
Foreign function interface for an SGI 64-bit MIPS with sgi-cc.
17
This calls a C function with an argument list built up using macros
20
SGI MIPS 64-bit Argument Passing Conventions
22
- The entire argument list forms a structure with all the appropriate
23
holes & alignments, and space for this is allocated in the stack frame.
24
- Shorter integers are promoted to longword length (sizeof(long)=8).
25
- Doubles are 1 longword.
26
- Structure arguments are copies embedded in the arglist structure.
27
- The first 8 longwords of the structure are passed in registers $4...$11,
28
except that float arguments are passed in registers $f12...$f19, and
29
that double arguments and structure elements of type double are passed
30
in registers $f12...$f19. (But varargs functions may expect them in the
31
integer registers and we can't tell whether the function is varargs so
32
we pass them both ways.)
33
Remaining longwords are passed on the stack. No stack space is allocated
34
for the first 8 longwords of the structure.
35
- Structure returns of structures > 16 bytes: pointers to caller-allocated
36
space are passed in as the first argument of the list.
37
- Structure returns of structures <= 16 bytes: in the registers $2 (for the
38
first 8 bytes) and $3 (for the next 8 bytes).
39
A structure of 1 or 2 floats or doubles is returned in $f0 and $f2:
40
the first float or double in $f0, the second float or double in $f2.
41
- Integer/pointer returns are in $2, float/double returns in $f0.
42
- The called function expects to see its own address in $25.
44
This file needs to be compiled with gcc for the asm extensions, but the
45
assembly version of it and the header file seem to work with SGI cc.
46
----------------------------------------------------------------------*/
47
#include "avcall.h.in"
49
#define RETURN(TYPE,VAL) (*(TYPE*)l->raddr = (TYPE)(VAL))
50
#define OFFSETOF(struct,member) ((int)&(((struct*)0)->member))
52
typedef __avword (*func_pointer)();
53
register func_pointer t9 __asm__("$25");
56
__builtin_avcall(av_alist* l)
58
register __avword* sp __asm__("$sp"); /* C names for registers */
59
register float fret __asm__("$f0");
60
register double dret __asm__("$f0");
61
/*register __avword iret1 __asm__("$2"); */
62
register __avword iret2 __asm__("$3");
63
__avword space[__AV_ALIST_WORDS]; /* big space for child's stack frame */
64
__avword *argframe = (__avword*)sp; /* stack offset for argument list is 0 */
65
int arglen = l->aptr - l->args;
69
{ /* push leading float args */
70
if (l->farg_mask & (1<<0))
71
__asm__("lwc1 $f12,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[0]));
72
if (l->farg_mask & (1<<1))
73
__asm__("lwc1 $f13,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[1]));
74
if (l->farg_mask & (1<<2))
75
__asm__("lwc1 $f14,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[2]));
76
if (l->farg_mask & (1<<3))
77
__asm__("lwc1 $f15,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[3]));
78
if (l->farg_mask & (1<<4))
79
__asm__("lwc1 $f16,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[4]));
80
if (l->farg_mask & (1<<5))
81
__asm__("lwc1 $f17,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[5]));
82
if (l->farg_mask & (1<<6))
83
__asm__("lwc1 $f18,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[6]));
84
if (l->farg_mask & (1<<7))
85
__asm__("lwc1 $f19,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[7]));
88
{ /* push leading double args */
89
if (l->darg_mask & (1<<0))
90
__asm__("ldc1 $f12,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[0]));
91
if (l->darg_mask & (1<<1))
92
__asm__("ldc1 $f13,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[1]));
93
if (l->darg_mask & (1<<2))
94
__asm__("ldc1 $f14,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[2]));
95
if (l->darg_mask & (1<<3))
96
__asm__("ldc1 $f15,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[3]));
97
if (l->darg_mask & (1<<4))
98
__asm__("ldc1 $f16,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[4]));
99
if (l->darg_mask & (1<<5))
100
__asm__("ldc1 $f17,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[5]));
101
if (l->darg_mask & (1<<6))
102
__asm__("ldc1 $f18,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[6]));
103
if (l->darg_mask & (1<<7))
104
__asm__("ldc1 $f19,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[7]));
107
for (i = 8; i < arglen; i++) /* push excess function args */
108
argframe[i-8] = l->args[i];
110
/* call function with 1st 8 args */
111
__asm__ __volatile__ ("ld $4,%0" : : "m" (l->args[0]) : "$4"); /* arg1 = l->args[0]; */
112
__asm__ __volatile__ ("ld $5,%0" : : "m" (l->args[1]) : "$5"); /* arg1 = l->args[1]; */
113
__asm__ __volatile__ ("ld $6,%0" : : "m" (l->args[2]) : "$6"); /* arg1 = l->args[2]; */
114
__asm__ __volatile__ ("ld $7,%0" : : "m" (l->args[3]) : "$7"); /* arg1 = l->args[3]; */
115
__asm__ __volatile__ ("ld $8,%0" : : "m" (l->args[4]) : "$8"); /* arg1 = l->args[4]; */
116
__asm__ __volatile__ ("ld $9,%0" : : "m" (l->args[5]) : "$9"); /* arg1 = l->args[5]; */
117
__asm__ __volatile__ ("ld $10,%0" : : "m" (l->args[6]) : "$10"); /* arg1 = l->args[6]; */
118
__asm__ __volatile__ ("ld $11,%0" : : "m" (l->args[7]) : "$11"); /* arg1 = l->args[7]; */
119
i = (*(t9 = l->func))();
121
/* save return value */
122
if (l->rtype == __AVvoid) {
124
if (l->rtype == __AVword) {
127
if (l->rtype == __AVchar) {
130
if (l->rtype == __AVschar) {
131
RETURN(signed char, i);
133
if (l->rtype == __AVuchar) {
134
RETURN(unsigned char, i);
136
if (l->rtype == __AVshort) {
139
if (l->rtype == __AVushort) {
140
RETURN(unsigned short, i);
142
if (l->rtype == __AVint) {
145
if (l->rtype == __AVuint) {
146
RETURN(unsigned int, i);
148
if (l->rtype == __AVlong) {
151
if (l->rtype == __AVulong) {
152
RETURN(unsigned long, i);
154
if (l->rtype == __AVlonglong) {
155
RETURN(long long, i);
157
if (l->rtype == __AVulonglong) {
158
RETURN(unsigned long long, i);
160
if (l->rtype == __AVfloat) {
163
if (l->rtype == __AVdouble) {
164
RETURN(double, dret);
166
if (l->rtype == __AVvoidp) {
169
if (l->rtype == __AVstruct) {
170
if (l->flags & __AV_PCC_STRUCT_RETURN) {
171
/* pcc struct return convention: need a *(TYPE*)l->raddr = *(TYPE*)i; */
172
if (l->rsize == sizeof(char)) {
173
RETURN(char, *(char*)i);
175
if (l->rsize == sizeof(short)) {
176
RETURN(short, *(short*)i);
178
if (l->rsize == sizeof(int)) {
179
RETURN(int, *(int*)i);
181
if (l->rsize == sizeof(long)) {
182
RETURN(long, *(long*)i);
184
int n = (l->rsize + sizeof(__avword)-1)/sizeof(__avword);
186
((__avword*)l->raddr)[n] = ((__avword*)i)[n];
189
/* normal struct return convention */
190
if (l->flags & __AV_REGISTER_STRUCT_RETURN) {
191
if (l->flags & __AV_GCC_STRUCT_RETURN) {
192
/* gcc returns structs of size 1,2,4,8 in registers. */
193
if (l->rsize == sizeof(char)) {
196
if (l->rsize == sizeof(short)) {
199
if (l->rsize == sizeof(int)) {
202
if (l->rsize == sizeof(long)) {
206
/* cc returns structs of size <= 16 in registers. */
207
if (l->rsize > 0 && l->rsize <= 16) {
209
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
212
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
213
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
216
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
217
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
218
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
221
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
222
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
223
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
224
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
227
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
228
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
229
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
230
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
231
((unsigned char *)l->raddr)[4] = (unsigned char)(i>>24);
234
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
235
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
236
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
237
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
238
((unsigned char *)l->raddr)[4] = (unsigned char)(i>>24);
239
((unsigned char *)l->raddr)[5] = (unsigned char)(i>>16);
242
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
243
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
244
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
245
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
246
((unsigned char *)l->raddr)[4] = (unsigned char)(i>>24);
247
((unsigned char *)l->raddr)[5] = (unsigned char)(i>>16);
248
((unsigned char *)l->raddr)[6] = (unsigned char)(i>>8);
250
if (l->rsize >= 8 && l->rsize <= 16) {
251
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
252
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
253
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
254
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
255
((unsigned char *)l->raddr)[4] = (unsigned char)(i>>24);
256
((unsigned char *)l->raddr)[5] = (unsigned char)(i>>16);
257
((unsigned char *)l->raddr)[6] = (unsigned char)(i>>8);
258
((unsigned char *)l->raddr)[7] = (unsigned char)(i);
262
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
264
if (l->rsize == 10) {
265
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
266
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
268
if (l->rsize == 11) {
269
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
270
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
271
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
273
if (l->rsize == 12) {
274
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
275
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
276
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
277
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
279
if (l->rsize == 13) {
280
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
281
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
282
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
283
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
284
((unsigned char *)l->raddr)[8+4] = (unsigned char)(iret2>>24);
286
if (l->rsize == 14) {
287
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
288
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
289
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
290
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
291
((unsigned char *)l->raddr)[8+4] = (unsigned char)(iret2>>24);
292
((unsigned char *)l->raddr)[8+5] = (unsigned char)(iret2>>16);
294
if (l->rsize == 15) {
295
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
296
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
297
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
298
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
299
((unsigned char *)l->raddr)[8+4] = (unsigned char)(iret2>>24);
300
((unsigned char *)l->raddr)[8+5] = (unsigned char)(iret2>>16);
301
((unsigned char *)l->raddr)[8+6] = (unsigned char)(iret2>>8);
303
if (l->rsize == 16) {
304
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
305
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
306
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
307
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
308
((unsigned char *)l->raddr)[8+4] = (unsigned char)(iret2>>24);
309
((unsigned char *)l->raddr)[8+5] = (unsigned char)(iret2>>16);
310
((unsigned char *)l->raddr)[8+6] = (unsigned char)(iret2>>8);
311
((unsigned char *)l->raddr)[8+7] = (unsigned char)(iret2);
322
#endif /*_avcall_mips64_c */