1
#ifndef _avcall_powerpc_c /*-*- C -*-*/
2
#define _avcall_powerpc_c
4
Copyright 1993 Bill Triggs, <Bill.Triggs@inrialpes.fr>
5
Copyright 1995-2006 Bruno Haible, <bruno@clisp.org>
6
Copyright 2000 Adam Fedor, <fedor@gnu.org>
7
Copyright 2004 Paul Guyot, <pguyot@kallisys.net>
9
This is free software distributed under the GNU General Public
10
Licence described in the file COPYING. Contact the author if
11
you don't have this or can't live with it. There is ABSOLUTELY
12
NO WARRANTY, explicit or implied, on this software.
14
/*----------------------------------------------------------------------
15
!!! THIS ROUTINE MUST BE COMPILED gcc -O !!!
17
Foreign function interface for an IBM RS/6000 with gcc
19
This calls a C function with an argument list built up using macros
22
RS6000 Argument Passing Conventions:
24
All arguments, except the first 8 words, are passed on the stack with
25
word alignment. Doubles take two words. The first 13 doubles and floats
26
are also passed in floating-point-registers.
27
To return a structure, the called function copies the value to space
28
pointed to by its first argument, and all other arguments are shifted
31
Differences between AIX and SysV.4 argument passing conventions:
32
- AIX: the first 13 doubles and floats are passed in FP registers,
33
and when they do, there is still room allocated for them in the
34
argument sequence (integer regs or stack).
35
SysV.4: the first 8 doubles and floats are passed in FP registers,
36
and no room is allocated for them in the argument sequence.
37
- AIX: Structures are passed in the argument sequence.
38
SysV.4: Structures are passed by reference: only a pointer appears in
39
the argument sequence.
40
- AIX: Long longs are only word aligned.
41
SysV.4: Long longs are two-word aligned, both when passed in registers
42
(pairs: 3/4, 5/6, 7/8, 9/10) and when passed on the stack. (Recall
43
that the stack is always 8-byte aligned).
45
Compile this routine with gcc -O (or -O2 -fno-omit-frame-pointer or -g -O)
46
to get the right register variables. For other compilers use the
47
pre-compiled assembler version.
48
----------------------------------------------------------------------*/
49
#include "avcall.h.in"
52
#define STACK_OFFSET 2
54
#define STACK_OFFSET 14
57
#define RETURN(TYPE,VAL) (*(TYPE*)l->raddr = (TYPE)(VAL))
59
register double farg1 __asm__("fr1");
60
register double farg2 __asm__("fr2");
61
register double farg3 __asm__("fr3");
62
register double farg4 __asm__("fr4");
63
register double farg5 __asm__("fr5");
64
register double farg6 __asm__("fr6");
65
register double farg7 __asm__("fr7");
66
register double farg8 __asm__("fr8");
67
register double farg9 __asm__("fr9");
68
register double farg10 __asm__("fr10");
69
register double farg11 __asm__("fr11");
70
register double farg12 __asm__("fr12");
71
register double farg13 __asm__("fr13");
74
__builtin_avcall(av_alist* l)
76
register __avword* sp __asm__("r1"); /* C names for registers */
77
/*register __avword iret __asm__("r3"); */
78
register __avword iret2 __asm__("r4");
79
register float fret __asm__("fr1");
80
register double dret __asm__("fr1");
82
__avword space[__AV_ALIST_WORDS]; /* space for callee's stack frame */
83
__avword* argframe = sp + STACK_OFFSET;/* stack offset for argument list */
84
int arglen = l->aptr - l->args;
85
#if defined(_AIX) || (defined(__MACH__) && defined(__APPLE__))
88
int farglen = l->faptr - l->fargs;
92
for (i = (8-farglen); i < arglen; i++) /* push function args onto stack */
93
argframe[i-8+farglen] = l->args[i];
95
/* pass first 13 floating-point args in registers */
96
arglen = l->faptr - l->fargs;
97
if (arglen == 0) goto fargs0;
98
else if (arglen == 1) goto fargs1;
99
else if (arglen == 2) goto fargs2;
100
else if (arglen == 3) goto fargs3;
101
else if (arglen == 4) goto fargs4;
102
else if (arglen == 5) goto fargs5;
103
else if (arglen == 6) goto fargs6;
104
else if (arglen == 7) goto fargs7;
105
else if (arglen == 8) goto fargs8;
106
else if (arglen == 9) goto fargs9;
107
else if (arglen == 10) goto fargs10;
108
else if (arglen == 11) goto fargs11;
109
else if (arglen == 12) goto fargs12;
110
else if (arglen == 13) goto fargs13;
111
fargs13: farg13 = l->fargs[12];
112
fargs12: farg12 = l->fargs[11];
113
fargs11: farg11 = l->fargs[10];
114
fargs10: farg10 = l->fargs[9];
115
fargs9: farg9 = l->fargs[8];
116
fargs8: farg8 = l->fargs[7];
117
fargs7: farg7 = l->fargs[6];
118
fargs6: farg6 = l->fargs[5];
119
fargs5: farg5 = l->fargs[4];
120
fargs4: farg4 = l->fargs[3];
121
fargs3: farg3 = l->fargs[2];
122
fargs2: farg2 = l->fargs[1];
123
fargs1: farg1 = l->fargs[0];
125
/* call function, pass 8 args in registers */
126
i = (*l->func)(l->args[0], l->args[1], l->args[2], l->args[3],
127
l->args[4], l->args[5], l->args[6], l->args[7]);
129
/* save return value */
130
if (l->rtype == __AVvoid) {
132
if (l->rtype == __AVword) {
135
if (l->rtype == __AVchar) {
138
if (l->rtype == __AVschar) {
139
RETURN(signed char, i);
141
if (l->rtype == __AVuchar) {
142
RETURN(unsigned char, i);
144
if (l->rtype == __AVshort) {
147
if (l->rtype == __AVushort) {
148
RETURN(unsigned short, i);
150
if (l->rtype == __AVint) {
153
if (l->rtype == __AVuint) {
154
RETURN(unsigned int, i);
156
if (l->rtype == __AVlong) {
159
if (l->rtype == __AVulong) {
160
RETURN(unsigned long, i);
162
if (l->rtype == __AVlonglong || l->rtype == __AVulonglong) {
163
((__avword*)l->raddr)[0] = i;
164
((__avword*)l->raddr)[1] = iret2;
166
if (l->rtype == __AVfloat) {
169
if (l->rtype == __AVdouble) {
170
RETURN(double, dret);
172
if (l->rtype == __AVvoidp) {
175
if (l->rtype == __AVstruct) {
176
if (l->flags & __AV_PCC_STRUCT_RETURN) {
177
/* pcc struct return convention: need a *(TYPE*)l->raddr = *(TYPE*)i; */
178
if (l->rsize == sizeof(char)) {
179
RETURN(char, *(char*)i);
181
if (l->rsize == sizeof(short)) {
182
RETURN(short, *(short*)i);
184
if (l->rsize == sizeof(int)) {
185
RETURN(int, *(int*)i);
187
if (l->rsize == sizeof(double)) {
188
((int*)l->raddr)[0] = ((int*)i)[0];
189
((int*)l->raddr)[1] = ((int*)i)[1];
191
int n = (l->rsize + sizeof(__avword)-1)/sizeof(__avword);
193
((__avword*)l->raddr)[n] = ((__avword*)i)[n];
196
/* normal struct return convention */
197
if (l->flags & __AV_REGISTER_STRUCT_RETURN) {
198
if (l->rsize == sizeof(char)) {
201
if (l->rsize == sizeof(short)) {
204
if (l->rsize == sizeof(int)) {
207
if (l->rsize == 2*sizeof(__avword)) {
208
((__avword*)l->raddr)[0] = i;
209
((__avword*)l->raddr)[1] = iret2;
217
#endif /*_avcall_powerpc_c */