]> git.ipfire.org Git - thirdparty/gcc.git/blame - libffi/src/alpha/ffi.c
ffi.h.in (ffi_closure_alloc, [...]): New.
[thirdparty/gcc.git] / libffi / src / alpha / ffi.c
CommitLineData
63e5e3e0 1/* -----------------------------------------------------------------------
18fa3240 2 ffi.c - Copyright (c) 1998, 2001, 2007 Red Hat, Inc.
63e5e3e0
AG
3
4 Alpha Foreign Function Interface
5
63e5e3e0
AG
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 ``Software''), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------- */
25
26#include <ffi.h>
27#include <ffi_common.h>
28
29#include <stdlib.h>
30
29fe0479
RH
31extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
32extern void ffi_closure_osf(void);
63e5e3e0 33
29fe0479
RH
34
35ffi_status
36ffi_prep_cif_machdep(ffi_cif *cif)
63e5e3e0 37{
29fe0479
RH
38 /* Adjust cif->bytes to represent a minimum 6 words for the temporary
39 register argument loading area. */
1450eb7a
AT
40 if (cif->bytes < 6*FFI_SIZEOF_ARG)
41 cif->bytes = 6*FFI_SIZEOF_ARG;
29fe0479
RH
42
43 /* Set the return type flag */
44 switch (cif->rtype->type)
63e5e3e0 45 {
29fe0479
RH
46 case FFI_TYPE_STRUCT:
47 case FFI_TYPE_FLOAT:
48 case FFI_TYPE_DOUBLE:
49 cif->flags = cif->rtype->type;
50 break;
51
52 default:
53 cif->flags = FFI_TYPE_INT;
54 break;
63e5e3e0 55 }
29fe0479
RH
56
57 return FFI_OK;
58}
59
60void
61ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
62{
63 unsigned long *stack, *argp;
64 long i, avn;
65 ffi_type **arg_types;
66
67 FFI_ASSERT (cif->abi == FFI_OSF);
68
69 /* If the return value is a struct and we don't have a return
70 value address then we need to make one. */
3f67ba6e 71 if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT)
29fe0479
RH
72 rvalue = alloca(cif->rtype->size);
73
74 /* Allocate the space for the arguments, plus 4 words of temp
75 space for ffi_call_osf. */
1450eb7a 76 argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
29fe0479
RH
77
78 if (cif->flags == FFI_TYPE_STRUCT)
79 *(void **) argp++ = rvalue;
63e5e3e0
AG
80
81 i = 0;
29fe0479
RH
82 avn = cif->nargs;
83 arg_types = cif->arg_types;
84
63e5e3e0
AG
85 while (i < avn)
86 {
29fe0479 87 switch ((*arg_types)->type)
63e5e3e0
AG
88 {
89 case FFI_TYPE_SINT8:
29fe0479 90 *(SINT64 *) argp = *(SINT8 *)(* avalue);
63e5e3e0
AG
91 break;
92
93 case FFI_TYPE_UINT8:
29fe0479 94 *(SINT64 *) argp = *(UINT8 *)(* avalue);
63e5e3e0
AG
95 break;
96
97 case FFI_TYPE_SINT16:
29fe0479 98 *(SINT64 *) argp = *(SINT16 *)(* avalue);
63e5e3e0
AG
99 break;
100
101 case FFI_TYPE_UINT16:
29fe0479 102 *(SINT64 *) argp = *(UINT16 *)(* avalue);
63e5e3e0
AG
103 break;
104
105 case FFI_TYPE_SINT32:
63e5e3e0 106 case FFI_TYPE_UINT32:
29fe0479
RH
107 /* Note that unsigned 32-bit quantities are sign extended. */
108 *(SINT64 *) argp = *(SINT32 *)(* avalue);
63e5e3e0 109 break;
29fe0479 110
63e5e3e0
AG
111 case FFI_TYPE_SINT64:
112 case FFI_TYPE_UINT64:
113 case FFI_TYPE_POINTER:
29fe0479 114 *(UINT64 *) argp = *(UINT64 *)(* avalue);
63e5e3e0
AG
115 break;
116
117 case FFI_TYPE_FLOAT:
29fe0479 118 if (argp - stack < 6)
63e5e3e0
AG
119 {
120 /* Note the conversion -- all the fp regs are loaded as
121 doubles. The in-register format is the same. */
29fe0479 122 *(double *) argp = *(float *)(* avalue);
63e5e3e0
AG
123 }
124 else
29fe0479 125 *(float *) argp = *(float *)(* avalue);
63e5e3e0
AG
126 break;
127
128 case FFI_TYPE_DOUBLE:
29fe0479 129 *(double *) argp = *(double *)(* avalue);
63e5e3e0
AG
130 break;
131
132 case FFI_TYPE_STRUCT:
29fe0479 133 memcpy(argp, *avalue, (*arg_types)->size);
63e5e3e0
AG
134 break;
135
136 default:
137 FFI_ASSERT(0);
138 }
139
1450eb7a 140 argp += ALIGN((*arg_types)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
29fe0479 141 i++, arg_types++, avalue++;
63e5e3e0 142 }
29fe0479
RH
143
144 ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
63e5e3e0
AG
145}
146
29fe0479 147
63e5e3e0 148ffi_status
18fa3240
AO
149ffi_prep_closure_loc (ffi_closure* closure,
150 ffi_cif* cif,
151 void (*fun)(ffi_cif*, void*, void**, void*),
152 void *user_data,
153 void *codeloc)
63e5e3e0 154{
29fe0479 155 unsigned int *tramp;
63e5e3e0 156
29fe0479 157 FFI_ASSERT (cif->abi == FFI_OSF);
63e5e3e0 158
29fe0479
RH
159 tramp = (unsigned int *) &closure->tramp[0];
160 tramp[0] = 0x47fb0401; /* mov $27,$1 */
161 tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
162 tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
163 tramp[3] = 0x47ff041f; /* nop */
164 *(void **) &tramp[4] = ffi_closure_osf;
63e5e3e0 165
29fe0479
RH
166 closure->cif = cif;
167 closure->fun = fun;
168 closure->user_data = user_data;
63e5e3e0 169
92a0e6c6
RO
170 /* Flush the Icache.
171
172 Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
173 instead, since both Compaq as and gas can handle it.
174
175 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */
176 asm volatile ("call_pal 0x86" : : : "memory");
63e5e3e0 177
63e5e3e0
AG
178 return FFI_OK;
179}
180
29fe0479
RH
181int
182ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
63e5e3e0 183{
29fe0479
RH
184 ffi_cif *cif;
185 void **avalue;
186 ffi_type **arg_types;
187 long i, avn, argn;
63e5e3e0 188
29fe0479
RH
189 cif = closure->cif;
190 avalue = alloca(cif->nargs * sizeof(void *));
191
192 argn = 0;
193
194 /* Copy the caller's structure return address to that the closure
195 returns the data directly to the caller. */
196 if (cif->flags == FFI_TYPE_STRUCT)
197 {
198 rvalue = (void *) argp[0];
199 argn = 1;
200 }
201
202 i = 0;
203 avn = cif->nargs;
204 arg_types = cif->arg_types;
63e5e3e0 205
29fe0479
RH
206 /* Grab the addresses of the arguments from the stack frame. */
207 while (i < avn)
63e5e3e0 208 {
3f67ba6e 209 switch (arg_types[i]->type)
29fe0479
RH
210 {
211 case FFI_TYPE_SINT8:
212 case FFI_TYPE_UINT8:
213 case FFI_TYPE_SINT16:
214 case FFI_TYPE_UINT16:
215 case FFI_TYPE_SINT32:
216 case FFI_TYPE_UINT32:
217 case FFI_TYPE_SINT64:
218 case FFI_TYPE_UINT64:
219 case FFI_TYPE_POINTER:
220 case FFI_TYPE_STRUCT:
3f67ba6e 221 avalue[i] = &argp[argn];
29fe0479 222 break;
63e5e3e0 223
29fe0479
RH
224 case FFI_TYPE_FLOAT:
225 if (argn < 6)
226 {
227 /* Floats coming from registers need conversion from double
228 back to float format. */
229 *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
3f67ba6e 230 avalue[i] = &argp[argn - 6];
29fe0479
RH
231 }
232 else
3f67ba6e 233 avalue[i] = &argp[argn];
29fe0479
RH
234 break;
235
236 case FFI_TYPE_DOUBLE:
3f67ba6e 237 avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
29fe0479
RH
238 break;
239
240 default:
241 FFI_ASSERT(0);
242 }
243
1450eb7a 244 argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
3f67ba6e 245 i++;
63e5e3e0 246 }
29fe0479
RH
247
248 /* Invoke the closure. */
249 (closure->fun) (cif, rvalue, avalue, closure->user_data);
250
3f67ba6e
RH
251 /* Tell ffi_closure_osf how to perform return type promotions. */
252 return cif->rtype->type;
63e5e3e0 253}