1
#ifndef _avcall_mipsn32_c /*-*- C -*-*/
2
#define _avcall_mipsn32_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 32-bit MIPS III with "cc -n32",
16
or gcc configured as mips-sgi-irix6.
18
This calls a C function with an argument list built up using macros
21
SGI MIPS new 32-bit Argument Passing Conventions
23
- The entire argument list forms a structure with all the appropriate
24
holes & alignments, and space for this is allocated in the stack frame.
25
- Shorter integers are promoted to long long length (sizeof(long long)=8).
26
- Doubles are 1 longword.
27
- Structure arguments are copies embedded in the arglist structure.
28
- The first 8 longwords of the structure are passed in registers $4...$11,
29
except that float arguments are passed in registers $f12...$f19, and
30
that double arguments and structure elements of type double are passed
31
in registers $f12...$f19. (But varargs functions may expect them in the
32
integer registers and we can't tell whether the function is varargs so
33
we pass them both ways.)
34
Remaining longwords are passed on the stack. No stack space is allocated
35
for the first 8 longwords of the structure.
36
- Structure returns of structures > 16 bytes: pointers to caller-allocated
37
space are passed in as the first argument of the list.
38
- Structure returns of structures <= 16 bytes: in the registers $2 (for the
39
first 8 bytes) and $3 (for the next 8 bytes).
40
A structure of 1 or 2 floats or doubles is returned in $f0 and $f2:
41
the first float or double in $f0, the second float or double in $f2.
42
- Integer/pointer returns are in $2, float/double returns in $f0.
43
- The called function expects to see its own address in $25.
45
This file needs to be compiled with gcc for the asm extensions, but the
46
assembly version of it and the header file seem to work with SGI cc.
47
----------------------------------------------------------------------*/
48
#include "avcall.h.in"
50
#define RETURN(TYPE,VAL) (*(TYPE*)l->raddr = (TYPE)(VAL))
51
#define OFFSETOF(struct,member) ((int)&(((struct*)0)->member))
53
typedef __avword (*func_pointer)();
54
register func_pointer t9 __asm__("$25");
57
__builtin_avcall(av_alist* l)
59
register __avword* sp __asm__("$sp"); /* C names for registers */
60
register float fret __asm__("$f0");
61
register double dret __asm__("$f0");
62
/*register __avword iret1 __asm__("$2"); */
63
register __avword iret2 __asm__("$3");
64
__avword space[__AV_ALIST_WORDS]; /* big space for child's stack frame */
65
__avword *argframe = (__avword*)sp; /* stack offset for argument list is 0 */
66
int arglen = l->aptr - l->args;
70
{ /* push leading float args */
71
if (l->farg_mask & (1<<0))
72
__asm__("lwc1 $f12,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[0]));
73
if (l->farg_mask & (1<<1))
74
__asm__("lwc1 $f13,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[1]));
75
if (l->farg_mask & (1<<2))
76
__asm__("lwc1 $f14,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[2]));
77
if (l->farg_mask & (1<<3))
78
__asm__("lwc1 $f15,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[3]));
79
if (l->farg_mask & (1<<4))
80
__asm__("lwc1 $f16,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[4]));
81
if (l->farg_mask & (1<<5))
82
__asm__("lwc1 $f17,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[5]));
83
if (l->farg_mask & (1<<6))
84
__asm__("lwc1 $f18,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[6]));
85
if (l->farg_mask & (1<<7))
86
__asm__("lwc1 $f19,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,farg[7]));
89
{ /* push leading double args */
90
if (l->darg_mask & (1<<0))
91
__asm__("ldc1 $f12,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[0]));
92
if (l->darg_mask & (1<<1))
93
__asm__("ldc1 $f13,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[1]));
94
if (l->darg_mask & (1<<2))
95
__asm__("ldc1 $f14,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[2]));
96
if (l->darg_mask & (1<<3))
97
__asm__("ldc1 $f15,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[3]));
98
if (l->darg_mask & (1<<4))
99
__asm__("ldc1 $f16,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[4]));
100
if (l->darg_mask & (1<<5))
101
__asm__("ldc1 $f17,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[5]));
102
if (l->darg_mask & (1<<6))
103
__asm__("ldc1 $f18,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[6]));
104
if (l->darg_mask & (1<<7))
105
__asm__("ldc1 $f19,%1(%0)" : : "p" (l), "i" OFFSETOF(av_alist,args[7]));
108
for (i = 8; i < arglen; i++) /* push excess function args */
109
argframe[i-8] = l->args[i];
111
/* call function with 1st 8 args */
112
__asm__ __volatile__ ("ld $4,%0" : : "m" (l->args[0]) : "$4"); /* arg1 = l->args[0]; */
113
__asm__ __volatile__ ("ld $5,%0" : : "m" (l->args[1]) : "$5"); /* arg1 = l->args[1]; */
114
__asm__ __volatile__ ("ld $6,%0" : : "m" (l->args[2]) : "$6"); /* arg1 = l->args[2]; */
115
__asm__ __volatile__ ("ld $7,%0" : : "m" (l->args[3]) : "$7"); /* arg1 = l->args[3]; */
116
__asm__ __volatile__ ("ld $8,%0" : : "m" (l->args[4]) : "$8"); /* arg1 = l->args[4]; */
117
__asm__ __volatile__ ("ld $9,%0" : : "m" (l->args[5]) : "$9"); /* arg1 = l->args[5]; */
118
__asm__ __volatile__ ("ld $10,%0" : : "m" (l->args[6]) : "$10"); /* arg1 = l->args[6]; */
119
__asm__ __volatile__ ("ld $11,%0" : : "m" (l->args[7]) : "$11"); /* arg1 = l->args[7]; */
120
i = (*(t9 = l->func))();
122
/* save return value */
123
if (l->rtype == __AVvoid) {
125
if (l->rtype == __AVword) {
128
if (l->rtype == __AVchar) {
131
if (l->rtype == __AVschar) {
132
RETURN(signed char, i);
134
if (l->rtype == __AVuchar) {
135
RETURN(unsigned char, i);
137
if (l->rtype == __AVshort) {
140
if (l->rtype == __AVushort) {
141
RETURN(unsigned short, i);
143
if (l->rtype == __AVint) {
146
if (l->rtype == __AVuint) {
147
RETURN(unsigned int, i);
149
if (l->rtype == __AVlong) {
152
if (l->rtype == __AVulong) {
153
RETURN(unsigned long, i);
155
if (l->rtype == __AVlonglong) {
156
RETURN(long long, i);
158
if (l->rtype == __AVulonglong) {
159
RETURN(unsigned long long, i);
161
if (l->rtype == __AVfloat) {
164
if (l->rtype == __AVdouble) {
165
RETURN(double, dret);
167
if (l->rtype == __AVvoidp) {
170
if (l->rtype == __AVstruct) {
171
if (l->flags & __AV_PCC_STRUCT_RETURN) {
172
/* pcc struct return convention: need a *(TYPE*)l->raddr = *(TYPE*)i; */
173
if (l->rsize == sizeof(char)) {
174
RETURN(char, *(char*)i);
176
if (l->rsize == sizeof(short)) {
177
RETURN(short, *(short*)i);
179
if (l->rsize == sizeof(int)) {
180
RETURN(int, *(int*)i);
182
if (l->rsize == sizeof(long long)) {
183
RETURN(long, *(long long*)i);
185
int n = (l->rsize + sizeof(__avword)-1)/sizeof(__avword);
187
((__avword*)l->raddr)[n] = ((__avword*)i)[n];
190
/* normal struct return convention */
191
if (l->flags & __AV_REGISTER_STRUCT_RETURN) {
192
if (l->flags & __AV_GCC_STRUCT_RETURN) {
193
/* gcc returns structs of size 1,2,4,8 in registers. */
194
if (l->rsize == sizeof(char)) {
197
if (l->rsize == sizeof(short)) {
200
if (l->rsize == sizeof(int)) {
203
if (l->rsize == sizeof(long long)) {
204
RETURN(long long, i);
207
/* cc returns structs of size <= 16 in registers. */
208
if (l->rsize > 0 && l->rsize <= 16) {
210
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
213
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
214
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
217
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
218
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
219
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
222
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
223
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
224
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
225
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
228
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
229
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
230
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
231
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
232
((unsigned char *)l->raddr)[4] = (unsigned char)(i>>24);
235
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
236
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
237
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
238
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
239
((unsigned char *)l->raddr)[4] = (unsigned char)(i>>24);
240
((unsigned char *)l->raddr)[5] = (unsigned char)(i>>16);
243
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
244
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
245
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
246
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
247
((unsigned char *)l->raddr)[4] = (unsigned char)(i>>24);
248
((unsigned char *)l->raddr)[5] = (unsigned char)(i>>16);
249
((unsigned char *)l->raddr)[6] = (unsigned char)(i>>8);
251
if (l->rsize >= 8 && l->rsize <= 16) {
252
((unsigned char *)l->raddr)[0] = (unsigned char)(i>>56);
253
((unsigned char *)l->raddr)[1] = (unsigned char)(i>>48);
254
((unsigned char *)l->raddr)[2] = (unsigned char)(i>>40);
255
((unsigned char *)l->raddr)[3] = (unsigned char)(i>>32);
256
((unsigned char *)l->raddr)[4] = (unsigned char)(i>>24);
257
((unsigned char *)l->raddr)[5] = (unsigned char)(i>>16);
258
((unsigned char *)l->raddr)[6] = (unsigned char)(i>>8);
259
((unsigned char *)l->raddr)[7] = (unsigned char)(i);
263
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
265
if (l->rsize == 10) {
266
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
267
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
269
if (l->rsize == 11) {
270
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
271
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
272
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
274
if (l->rsize == 12) {
275
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
276
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
277
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
278
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
280
if (l->rsize == 13) {
281
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
282
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
283
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
284
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
285
((unsigned char *)l->raddr)[8+4] = (unsigned char)(iret2>>24);
287
if (l->rsize == 14) {
288
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
289
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
290
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
291
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
292
((unsigned char *)l->raddr)[8+4] = (unsigned char)(iret2>>24);
293
((unsigned char *)l->raddr)[8+5] = (unsigned char)(iret2>>16);
295
if (l->rsize == 15) {
296
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
297
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
298
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
299
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
300
((unsigned char *)l->raddr)[8+4] = (unsigned char)(iret2>>24);
301
((unsigned char *)l->raddr)[8+5] = (unsigned char)(iret2>>16);
302
((unsigned char *)l->raddr)[8+6] = (unsigned char)(iret2>>8);
304
if (l->rsize == 16) {
305
((unsigned char *)l->raddr)[8+0] = (unsigned char)(iret2>>56);
306
((unsigned char *)l->raddr)[8+1] = (unsigned char)(iret2>>48);
307
((unsigned char *)l->raddr)[8+2] = (unsigned char)(iret2>>40);
308
((unsigned char *)l->raddr)[8+3] = (unsigned char)(iret2>>32);
309
((unsigned char *)l->raddr)[8+4] = (unsigned char)(iret2>>24);
310
((unsigned char *)l->raddr)[8+5] = (unsigned char)(iret2>>16);
311
((unsigned char *)l->raddr)[8+6] = (unsigned char)(iret2>>8);
312
((unsigned char *)l->raddr)[8+7] = (unsigned char)(iret2);
323
#endif /*_avcall_mipsn32_c */