1
#ifndef _avcall_alpha_c /*-*- C -*-*/
2
#define _avcall_alpha_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 a DEC Alpha with gcc.
17
This calls a C function with an argument list built up using macros
20
Alpha Argument Passing Conventions
22
The first 6 arguments are passed in registers $16-$21 for integers,
23
in registers $f16-$f21 for floats. From then on, everything is passed
26
Everything on the stack is word-aligned.
28
Integers and pointers are returned in $0, floats and doubles in $f0.
29
To return a structure, the called function copies the value to space
30
pointed to by its first argument, and all other arguments are shifted
33
Compile this routine with gcc for the __asm__ extensions and with
34
optimisation on (-O or -O2 or -g -O) so that argframe is set to the
36
----------------------------------------------------------------------*/
37
#include "avcall.h.in"
39
#define RETURN(TYPE,VAL) (*(TYPE*)l->raddr = (TYPE)(VAL))
42
__builtin_avcall(av_alist* l)
44
register __avword* sp __asm__("$30"); /* C names for registers */
45
register long arg1 __asm__("$16");
46
register long arg2 __asm__("$17");
47
register long arg3 __asm__("$18");
48
register long arg4 __asm__("$19");
49
register long arg5 __asm__("$20");
50
register long arg6 __asm__("$21");
51
register double fret __asm__("$f0");
52
register double farg1 __asm__("$f16");
53
register double farg2 __asm__("$f17");
54
register double farg3 __asm__("$f18");
55
register double farg4 __asm__("$f19");
56
register double farg5 __asm__("$f20");
57
register double farg6 __asm__("$f21");
58
/*register __avword iret __asm__("$0"); */
59
register __avword iret2 __asm__("$1");
61
__avword* argframe = (sp -= __AV_ALIST_WORDS); /* make room for argument list */
62
int arglen = ((unsigned long) l->aptr - (unsigned long) l->args) >> 3;
65
for (i = 6; i < arglen; i++) /* push excess function args */
66
argframe[i-6] = l->args[i];
68
/* call function with 1st 6 args */
69
/* we pass the args both in the integer registers and the floating point
70
registers, so we don't have to store the argument types. */
71
__asm__ __volatile__ ("ldq $16,%0" : : "m" (l->args[0])); /* arg1 = l->args[0]; */
72
__asm__ __volatile__ ("ldt $f16,%0" : : "m" (l->args[0])); /* farg1 = *(double*) &l->args[0]; */
73
__asm__ __volatile__ ("ldq $17,%0" : : "m" (l->args[1])); /* arg2 = l->args[1]; */
74
__asm__ __volatile__ ("ldt $f17,%0" : : "m" (l->args[1])); /* farg2 = *(double*) &l->args[1]; */
75
__asm__ __volatile__ ("ldq $18,%0" : : "m" (l->args[2])); /* arg3 = l->args[2]; */
76
__asm__ __volatile__ ("ldt $f18,%0" : : "m" (l->args[2])); /* farg3 = *(double*) &l->args[2]; */
77
__asm__ __volatile__ ("ldq $19,%0" : : "m" (l->args[3])); /* arg4 = l->args[3]; */
78
__asm__ __volatile__ ("ldt $f19,%0" : : "m" (l->args[3])); /* farg4 = *(double*) &l->args[3]; */
79
__asm__ __volatile__ ("ldq $20,%0" : : "m" (l->args[4])); /* arg5 = l->args[4]; */
80
__asm__ __volatile__ ("ldt $f20,%0" : : "m" (l->args[4])); /* farg5 = *(double*) &l->args[4]; */
81
__asm__ __volatile__ ("ldq $21,%0" : : "m" (l->args[5])); /* arg6 = l->args[5]; */
82
__asm__ __volatile__ ("ldt $f21,%0" : : "m" (l->args[5])); /* farg6 = *(double*) &l->args[5]; */
85
sp += __AV_ALIST_WORDS; /* remove argument list from the stack */
86
/* this is apparently not needed, but better safe than sorry... */
87
__asm__ __volatile__ ("" : : :
88
/* clobber */ "$16", "$17", "$18", "$19", "$20", "$21",
89
"$f16","$f17","$f18","$f19","$f20","$f21");
91
/* save return value */
92
if (l->rtype == __AVvoid) {
94
if (l->rtype == __AVword) {
97
if (l->rtype == __AVchar) {
100
if (l->rtype == __AVschar) {
101
RETURN(signed char, i);
103
if (l->rtype == __AVuchar) {
104
RETURN(unsigned char, i);
106
if (l->rtype == __AVshort) {
109
if (l->rtype == __AVushort) {
110
RETURN(unsigned short, i);
112
if (l->rtype == __AVint) {
115
if (l->rtype == __AVuint) {
116
RETURN(unsigned int, i);
118
if (l->rtype == __AVlong) {
121
if (l->rtype == __AVulong) {
122
RETURN(unsigned long, i);
124
if (l->rtype == __AVlonglong) {
125
RETURN(long long, i);
127
if (l->rtype == __AVulonglong) {
128
RETURN(unsigned long long, i);
130
if (l->rtype == __AVfloat) {
133
if (l->rtype == __AVdouble) {
134
RETURN(double, fret);
136
if (l->rtype == __AVvoidp) {
139
if (l->rtype == __AVstruct) {
140
if (l->flags & __AV_PCC_STRUCT_RETURN) {
141
/* pcc struct return convention: need a *(TYPE*)l->raddr = *(TYPE*)i; */
142
if (l->rsize == sizeof(char)) {
143
RETURN(char, *(char*)i);
145
if (l->rsize == sizeof(short)) {
146
RETURN(short, *(short*)i);
148
if (l->rsize == sizeof(int)) {
149
RETURN(int, *(int*)i);
151
if (l->rsize == sizeof(long)) {
152
RETURN(long, *(long*)i);
154
int n = (l->rsize + sizeof(__avword)-1)/sizeof(__avword);
156
((__avword*)l->raddr)[n] = ((__avword*)i)[n];
159
/* normal struct return convention */
160
if (l->flags & __AV_REGISTER_STRUCT_RETURN) {
161
if (l->rsize == sizeof(char)) {
164
if (l->rsize == sizeof(short)) {
167
if (l->rsize == sizeof(int)) {
170
if (l->rsize == sizeof(long)) {
173
if (l->rsize == 2*sizeof(__avword)) {
174
((__avword*)l->raddr)[0] = i;
175
((__avword*)l->raddr)[1] = i2;
183
#endif /*_avcall_alpha_c */