1
#ifndef _avcall_sparc_c /*-*- C -*-*/
2
#define _avcall_sparc_c
4
Copyright 1993 Bill Triggs, <Bill.Triggs@inrialpes.fr>
5
Copyright 1995-1999, 2005 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 a Sun4 Sparc with gcc/sun-cc.
17
This calls a C function with an argument list built up using macros
20
Sparc Argument Passing Conventions
22
The first 6 words of arguments are passed in integer registers o0-o5
23
regardless of type or alignment. (Registers are windowed: o0-o5 become
24
i0-i5 if the called function executes a `save' instruction.) Remaining
25
arguments are pushed onto the stack starting at a fixed offset
26
("argframe"). Space is left on the stack frame for temporary storage of
27
the register arguments as well.
29
Doubles may be cut in half and misaligned. Shorter integers are
30
always promoted to word-length. Functions with K&R-style declarations
31
and float args pass them as doubles and truncate them on function entry.
32
Structures are passed as pointers to a local copy of the structure made
35
Integers and pointers are returned in o0, floats in f0, doubles in
36
f0/f1. If the function returns a structure a pointer to space
37
allocated by the caller is pushed onto the stack immediately
38
before the function arguments. Gcc without -fpcc-struct-return returns
39
<= 4 byte structures as integers.
41
Sun cc allocates temporary space for a returned structure just below
42
the current frame pointer $fp (the $sp of the caller), and the caller
43
must copy them from there. It also returns the temp address in $o0, but
44
that gets nuked in the return in the code below so we can't use it.
45
**The Sun cc struct return stuff below is a kludge**, but seems to work
48
Compile this routine with gcc for the __asm__ extensions and with
49
optimisation on (-O or -O2 or -g -O) so that argframe is set to the
50
correct offset. (%sp is used differently in non-optimized code).
51
For Sun cc, use the pre-compiled assembler version of this routine.
52
----------------------------------------------------------------------*/
53
#include "avcall.h.in"
55
#define RETURN(TYPE,VAL) (*(TYPE*)l->raddr = (TYPE)(VAL))
57
register void* callee __asm__("%g2"); /* any global or local register */
58
register __avword o0 __asm__("%o0");
59
register __avword o1 __asm__("%o1");
60
register __avword o2 __asm__("%o2");
61
register __avword o3 __asm__("%o3");
62
register __avword o4 __asm__("%o4");
63
register __avword o5 __asm__("%o5");
66
__builtin_avcall(av_alist* l)
68
/*?? We probably need to make space for Sun cc
69
struct return somewhere here. */
70
register __avword* sp __asm__("%sp"); /* C names for registers */
71
register float fret __asm__("%f0"); /* %f0 */
72
register double dret __asm__("%f0"); /* %f0,%f1 */
74
__avword trampoline[6]; /* room for a trampoline */
75
__avword space[__AV_ALIST_WORDS]; /* space for callee's stack frame */
76
__avword *argframe = sp + 17; /* stack offset for argument list */
77
int arglen = l->aptr - l->args;
80
if (l->rtype == __AVstruct)
81
argframe[-1] = (__avword)l->raddr; /* push struct return address */
85
for (i = 6; i < arglen; i++) /* push excess function args */
86
argframe[i] = l->args[i];
89
if ((l->rtype == __AVstruct) && (l->flags & __AV_SUNPROCC_STRUCT_RETURN))
90
/* SUNWspro cc compiled functions don't copy the structure to the area
91
* pointed to by argframe[-1] unless the caller has a proper "unimp n"
92
* instruction. We generate the calling instructions on the stack. */
94
trampoline[0] = 0x9FC08000; /* call %g2 */
95
trampoline[1] = 0x01000000; /* nop */
96
trampoline[2] = l->rsize & 0xFFF; /* unimp n */
97
trampoline[3] = 0xB0102000; /* mov 0,%i0 */
98
trampoline[4] = 0x81C7E008; /* ret */
99
trampoline[5] = 0x81E80000; /* restore */
100
__asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[0]));
101
__asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[2]));
102
__asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[4]));
103
__asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[5]));
104
o0 = l->args[0]; o1 = l->args[1]; o2 = l->args[2];
105
o3 = l->args[3]; o4 = l->args[4]; o5 = l->args[5];
107
goto *(void*)trampoline;
110
/* call function with 1st 6 args */
111
i = ({ register __avword iret __asm__("%o0");
112
iret = (*l->func)(l->args[0], l->args[1], l->args[2],
113
l->args[3], l->args[4], l->args[5]);
114
asm ("nop"); /* struct returning functions skip this instruction */
118
/* save return value */
119
if (l->rtype == __AVvoid) {
121
if (l->rtype == __AVword) {
124
if (l->rtype == __AVchar) {
127
if (l->rtype == __AVschar) {
128
RETURN(signed char, i);
130
if (l->rtype == __AVuchar) {
131
RETURN(unsigned char, i);
133
if (l->rtype == __AVshort) {
136
if (l->rtype == __AVushort) {
137
RETURN(unsigned short, i);
139
if (l->rtype == __AVint) {
142
if (l->rtype == __AVuint) {
143
RETURN(unsigned int, i);
145
if (l->rtype == __AVlong) {
148
if (l->rtype == __AVulong) {
149
RETURN(unsigned long, i);
151
if (l->rtype == __AVlonglong || l->rtype == __AVulonglong) {
152
((__avword*)l->raddr)[0] = i;
153
((__avword*)l->raddr)[1] = o1;
155
if (l->rtype == __AVfloat) {
156
/* old Sun cc returns floats as doubles */
157
if (l->flags & __AV_SUNCC_FLOAT_RETURN) {
158
RETURN(float, (float)dret);
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(double)) {
182
((int*)l->raddr)[0] = ((int*)i)[0];
183
((int*)l->raddr)[1] = ((int*)i)[1];
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_SMALL_STRUCT_RETURN) {
192
if (l->rsize == sizeof(char)) {
195
if (l->rsize == sizeof(short)) {
198
if (l->rsize == sizeof(int)) {
207
#endif /*_avcall_sparc_c */