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