annotate libffi/src/alpha/ffi.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 04ced10e8804
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* -----------------------------------------------------------------------
kono
parents:
diff changeset
2 ffi.c - Copyright (c) 2012 Anthony Green
kono
parents:
diff changeset
3 Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 Alpha Foreign Function Interface
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 Permission is hereby granted, free of charge, to any person obtaining
kono
parents:
diff changeset
8 a copy of this software and associated documentation files (the
kono
parents:
diff changeset
9 ``Software''), to deal in the Software without restriction, including
kono
parents:
diff changeset
10 without limitation the rights to use, copy, modify, merge, publish,
kono
parents:
diff changeset
11 distribute, sublicense, and/or sell copies of the Software, and to
kono
parents:
diff changeset
12 permit persons to whom the Software is furnished to do so, subject to
kono
parents:
diff changeset
13 the following conditions:
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 The above copyright notice and this permission notice shall be included
kono
parents:
diff changeset
16 in all copies or substantial portions of the Software.
kono
parents:
diff changeset
17
kono
parents:
diff changeset
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
kono
parents:
diff changeset
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
kono
parents:
diff changeset
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
kono
parents:
diff changeset
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
kono
parents:
diff changeset
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
kono
parents:
diff changeset
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
kono
parents:
diff changeset
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
kono
parents:
diff changeset
25 DEALINGS IN THE SOFTWARE.
kono
parents:
diff changeset
26 ----------------------------------------------------------------------- */
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28 #include <ffi.h>
kono
parents:
diff changeset
29 #include <ffi_common.h>
kono
parents:
diff changeset
30 #include <stdlib.h>
kono
parents:
diff changeset
31 #include "internal.h"
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
kono
parents:
diff changeset
34 all further uses in this file will refer to the 128-bit type. */
kono
parents:
diff changeset
35 #if defined(__LONG_DOUBLE_128__)
kono
parents:
diff changeset
36 # if FFI_TYPE_LONGDOUBLE != 4
kono
parents:
diff changeset
37 # error FFI_TYPE_LONGDOUBLE out of date
kono
parents:
diff changeset
38 # endif
kono
parents:
diff changeset
39 #else
kono
parents:
diff changeset
40 # undef FFI_TYPE_LONGDOUBLE
kono
parents:
diff changeset
41 # define FFI_TYPE_LONGDOUBLE 4
kono
parents:
diff changeset
42 #endif
kono
parents:
diff changeset
43
kono
parents:
diff changeset
44 extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
kono
parents:
diff changeset
45 void *raddr, void (*fn)(void), void *closure)
kono
parents:
diff changeset
46 FFI_HIDDEN;
kono
parents:
diff changeset
47 extern void ffi_closure_osf(void) FFI_HIDDEN;
kono
parents:
diff changeset
48 extern void ffi_go_closure_osf(void) FFI_HIDDEN;
kono
parents:
diff changeset
49
kono
parents:
diff changeset
50 /* Promote a float value to its in-register double representation.
kono
parents:
diff changeset
51 Unlike actually casting to double, this does not trap on NaN. */
kono
parents:
diff changeset
52 static inline UINT64 lds(void *ptr)
kono
parents:
diff changeset
53 {
kono
parents:
diff changeset
54 UINT64 ret;
kono
parents:
diff changeset
55 asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
kono
parents:
diff changeset
56 return ret;
kono
parents:
diff changeset
57 }
kono
parents:
diff changeset
58
kono
parents:
diff changeset
59 /* And the reverse. */
kono
parents:
diff changeset
60 static inline void sts(void *ptr, UINT64 val)
kono
parents:
diff changeset
61 {
kono
parents:
diff changeset
62 asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
kono
parents:
diff changeset
63 }
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 ffi_status FFI_HIDDEN
kono
parents:
diff changeset
66 ffi_prep_cif_machdep(ffi_cif *cif)
kono
parents:
diff changeset
67 {
kono
parents:
diff changeset
68 size_t bytes = 0;
kono
parents:
diff changeset
69 int flags, i, avn;
kono
parents:
diff changeset
70 ffi_type *rtype, *itype;
kono
parents:
diff changeset
71
kono
parents:
diff changeset
72 if (cif->abi != FFI_OSF)
kono
parents:
diff changeset
73 return FFI_BAD_ABI;
kono
parents:
diff changeset
74
kono
parents:
diff changeset
75 /* Compute the size of the argument area. */
kono
parents:
diff changeset
76 for (i = 0, avn = cif->nargs; i < avn; i++)
kono
parents:
diff changeset
77 {
kono
parents:
diff changeset
78 itype = cif->arg_types[i];
kono
parents:
diff changeset
79 switch (itype->type)
kono
parents:
diff changeset
80 {
kono
parents:
diff changeset
81 case FFI_TYPE_INT:
kono
parents:
diff changeset
82 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
83 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
84 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
85 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
86 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
87 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
88 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
89 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
90 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
91 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
92 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
93 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
94 /* All take one 8 byte slot. */
kono
parents:
diff changeset
95 bytes += 8;
kono
parents:
diff changeset
96 break;
kono
parents:
diff changeset
97
kono
parents:
diff changeset
98 case FFI_TYPE_VOID:
kono
parents:
diff changeset
99 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
100 /* Passed by value in N slots. */
kono
parents:
diff changeset
101 bytes += ALIGN(itype->size, FFI_SIZEOF_ARG);
kono
parents:
diff changeset
102 break;
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
105 /* _Complex long double passed by reference; others in 2 slots. */
kono
parents:
diff changeset
106 if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
kono
parents:
diff changeset
107 bytes += 8;
kono
parents:
diff changeset
108 else
kono
parents:
diff changeset
109 bytes += 16;
kono
parents:
diff changeset
110 break;
kono
parents:
diff changeset
111
kono
parents:
diff changeset
112 default:
kono
parents:
diff changeset
113 abort();
kono
parents:
diff changeset
114 }
kono
parents:
diff changeset
115 }
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 /* Set the return type flag */
kono
parents:
diff changeset
118 rtype = cif->rtype;
kono
parents:
diff changeset
119 switch (rtype->type)
kono
parents:
diff changeset
120 {
kono
parents:
diff changeset
121 case FFI_TYPE_VOID:
kono
parents:
diff changeset
122 flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
kono
parents:
diff changeset
123 break;
kono
parents:
diff changeset
124 case FFI_TYPE_INT:
kono
parents:
diff changeset
125 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
126 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
127 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
kono
parents:
diff changeset
128 break;
kono
parents:
diff changeset
129 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
130 flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
kono
parents:
diff changeset
131 break;
kono
parents:
diff changeset
132 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
133 flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
kono
parents:
diff changeset
134 break;
kono
parents:
diff changeset
135 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
136 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
kono
parents:
diff changeset
137 break;
kono
parents:
diff changeset
138 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
139 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
kono
parents:
diff changeset
140 break;
kono
parents:
diff changeset
141 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
142 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
kono
parents:
diff changeset
143 break;
kono
parents:
diff changeset
144 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
145 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
kono
parents:
diff changeset
146 break;
kono
parents:
diff changeset
147 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
148 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
149 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
150 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
kono
parents:
diff changeset
151 break;
kono
parents:
diff changeset
152 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
153 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
154 /* Passed in memory, with a hidden pointer. */
kono
parents:
diff changeset
155 flags = ALPHA_RET_IN_MEM;
kono
parents:
diff changeset
156 break;
kono
parents:
diff changeset
157 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
158 itype = rtype->elements[0];
kono
parents:
diff changeset
159 switch (itype->type)
kono
parents:
diff changeset
160 {
kono
parents:
diff changeset
161 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
162 flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
kono
parents:
diff changeset
163 break;
kono
parents:
diff changeset
164 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
165 flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
kono
parents:
diff changeset
166 break;
kono
parents:
diff changeset
167 default:
kono
parents:
diff changeset
168 if (rtype->size <= 8)
kono
parents:
diff changeset
169 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
kono
parents:
diff changeset
170 else
kono
parents:
diff changeset
171 flags = ALPHA_RET_IN_MEM;
kono
parents:
diff changeset
172 break;
kono
parents:
diff changeset
173 }
kono
parents:
diff changeset
174 break;
kono
parents:
diff changeset
175 default:
kono
parents:
diff changeset
176 abort();
kono
parents:
diff changeset
177 }
kono
parents:
diff changeset
178 cif->flags = flags;
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 /* Include the hidden structure pointer in args requirement. */
kono
parents:
diff changeset
181 if (flags == ALPHA_RET_IN_MEM)
kono
parents:
diff changeset
182 bytes += 8;
kono
parents:
diff changeset
183 /* Minimum size is 6 slots, so that ffi_call_osf can pop them. */
kono
parents:
diff changeset
184 if (bytes < 6*8)
kono
parents:
diff changeset
185 bytes = 6*8;
kono
parents:
diff changeset
186 cif->bytes = bytes;
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 return FFI_OK;
kono
parents:
diff changeset
189 }
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 static unsigned long
kono
parents:
diff changeset
192 extend_basic_type(void *valp, int type, int argn)
kono
parents:
diff changeset
193 {
kono
parents:
diff changeset
194 switch (type)
kono
parents:
diff changeset
195 {
kono
parents:
diff changeset
196 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
197 return *(SINT8 *)valp;
kono
parents:
diff changeset
198 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
199 return *(UINT8 *)valp;
kono
parents:
diff changeset
200 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
201 return *(SINT16 *)valp;
kono
parents:
diff changeset
202 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
203 return *(UINT16 *)valp;
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
206 if (argn < 6)
kono
parents:
diff changeset
207 return lds(valp);
kono
parents:
diff changeset
208 /* FALLTHRU */
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 case FFI_TYPE_INT:
kono
parents:
diff changeset
211 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
212 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
213 /* Note that unsigned 32-bit quantities are sign extended. */
kono
parents:
diff changeset
214 return *(SINT32 *)valp;
kono
parents:
diff changeset
215
kono
parents:
diff changeset
216 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
217 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
218 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
219 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
220 return *(UINT64 *)valp;
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 default:
kono
parents:
diff changeset
223 abort();
kono
parents:
diff changeset
224 }
kono
parents:
diff changeset
225 }
kono
parents:
diff changeset
226
kono
parents:
diff changeset
227 static void
kono
parents:
diff changeset
228 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
kono
parents:
diff changeset
229 void **avalue, void *closure)
kono
parents:
diff changeset
230 {
kono
parents:
diff changeset
231 unsigned long *argp;
kono
parents:
diff changeset
232 long i, avn, argn, flags = cif->flags;
kono
parents:
diff changeset
233 ffi_type **arg_types;
kono
parents:
diff changeset
234 void *frame;
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 /* If the return value is a struct and we don't have a return
kono
parents:
diff changeset
237 value address then we need to make one. */
kono
parents:
diff changeset
238 if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
kono
parents:
diff changeset
239 rvalue = alloca(cif->rtype->size);
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 /* Allocate the space for the arguments, plus 4 words of temp
kono
parents:
diff changeset
242 space for ffi_call_osf. */
kono
parents:
diff changeset
243 argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
kono
parents:
diff changeset
244 frame += cif->bytes;
kono
parents:
diff changeset
245
kono
parents:
diff changeset
246 argn = 0;
kono
parents:
diff changeset
247 if (flags == ALPHA_RET_IN_MEM)
kono
parents:
diff changeset
248 argp[argn++] = (unsigned long)rvalue;
kono
parents:
diff changeset
249
kono
parents:
diff changeset
250 avn = cif->nargs;
kono
parents:
diff changeset
251 arg_types = cif->arg_types;
kono
parents:
diff changeset
252
kono
parents:
diff changeset
253 for (i = 0, avn = cif->nargs; i < avn; i++)
kono
parents:
diff changeset
254 {
kono
parents:
diff changeset
255 ffi_type *ty = arg_types[i];
kono
parents:
diff changeset
256 void *valp = avalue[i];
kono
parents:
diff changeset
257 int type = ty->type;
kono
parents:
diff changeset
258 size_t size;
kono
parents:
diff changeset
259
kono
parents:
diff changeset
260 switch (type)
kono
parents:
diff changeset
261 {
kono
parents:
diff changeset
262 case FFI_TYPE_INT:
kono
parents:
diff changeset
263 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
264 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
265 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
266 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
267 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
268 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
269 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
270 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
271 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
272 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
273 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
274 argp[argn] = extend_basic_type(valp, type, argn);
kono
parents:
diff changeset
275 argn++;
kono
parents:
diff changeset
276 break;
kono
parents:
diff changeset
277
kono
parents:
diff changeset
278 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
279 by_reference:
kono
parents:
diff changeset
280 /* Note that 128-bit long double is passed by reference. */
kono
parents:
diff changeset
281 argp[argn++] = (unsigned long)valp;
kono
parents:
diff changeset
282 break;
kono
parents:
diff changeset
283
kono
parents:
diff changeset
284 case FFI_TYPE_VOID:
kono
parents:
diff changeset
285 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
286 size = ty->size;
kono
parents:
diff changeset
287 memcpy(argp + argn, valp, size);
kono
parents:
diff changeset
288 argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
kono
parents:
diff changeset
289 break;
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
292 type = ty->elements[0]->type;
kono
parents:
diff changeset
293 if (type == FFI_TYPE_LONGDOUBLE)
kono
parents:
diff changeset
294 goto by_reference;
kono
parents:
diff changeset
295
kono
parents:
diff changeset
296 /* Most complex types passed as two separate arguments. */
kono
parents:
diff changeset
297 size = ty->elements[0]->size;
kono
parents:
diff changeset
298 argp[argn] = extend_basic_type(valp, type, argn);
kono
parents:
diff changeset
299 argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1);
kono
parents:
diff changeset
300 argn += 2;
kono
parents:
diff changeset
301 break;
kono
parents:
diff changeset
302
kono
parents:
diff changeset
303 default:
kono
parents:
diff changeset
304 abort();
kono
parents:
diff changeset
305 }
kono
parents:
diff changeset
306 }
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
kono
parents:
diff changeset
309 ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
kono
parents:
diff changeset
310 }
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 void
kono
parents:
diff changeset
313 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
kono
parents:
diff changeset
314 {
kono
parents:
diff changeset
315 ffi_call_int(cif, fn, rvalue, avalue, NULL);
kono
parents:
diff changeset
316 }
kono
parents:
diff changeset
317
kono
parents:
diff changeset
318 void
kono
parents:
diff changeset
319 ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
kono
parents:
diff changeset
320 void **avalue, void *closure)
kono
parents:
diff changeset
321 {
kono
parents:
diff changeset
322 ffi_call_int(cif, fn, rvalue, avalue, closure);
kono
parents:
diff changeset
323 }
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 ffi_status
kono
parents:
diff changeset
326 ffi_prep_closure_loc (ffi_closure* closure,
kono
parents:
diff changeset
327 ffi_cif* cif,
kono
parents:
diff changeset
328 void (*fun)(ffi_cif*, void*, void**, void*),
kono
parents:
diff changeset
329 void *user_data,
kono
parents:
diff changeset
330 void *codeloc)
kono
parents:
diff changeset
331 {
kono
parents:
diff changeset
332 unsigned int *tramp;
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 if (cif->abi != FFI_OSF)
kono
parents:
diff changeset
335 return FFI_BAD_ABI;
kono
parents:
diff changeset
336
kono
parents:
diff changeset
337 tramp = (unsigned int *) &closure->tramp[0];
kono
parents:
diff changeset
338 tramp[0] = 0x47fb0401; /* mov $27,$1 */
kono
parents:
diff changeset
339 tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
kono
parents:
diff changeset
340 tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
kono
parents:
diff changeset
341 tramp[3] = 0x47ff041f; /* nop */
kono
parents:
diff changeset
342 *(void **) &tramp[4] = ffi_closure_osf;
kono
parents:
diff changeset
343
kono
parents:
diff changeset
344 closure->cif = cif;
kono
parents:
diff changeset
345 closure->fun = fun;
kono
parents:
diff changeset
346 closure->user_data = user_data;
kono
parents:
diff changeset
347
kono
parents:
diff changeset
348 /* Flush the Icache.
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
kono
parents:
diff changeset
351 instead, since both Compaq as and gas can handle it.
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */
kono
parents:
diff changeset
354 asm volatile ("call_pal 0x86" : : : "memory");
kono
parents:
diff changeset
355
kono
parents:
diff changeset
356 return FFI_OK;
kono
parents:
diff changeset
357 }
kono
parents:
diff changeset
358
kono
parents:
diff changeset
359 ffi_status
kono
parents:
diff changeset
360 ffi_prep_go_closure (ffi_go_closure* closure,
kono
parents:
diff changeset
361 ffi_cif* cif,
kono
parents:
diff changeset
362 void (*fun)(ffi_cif*, void*, void**, void*))
kono
parents:
diff changeset
363 {
kono
parents:
diff changeset
364 if (cif->abi != FFI_OSF)
kono
parents:
diff changeset
365 return FFI_BAD_ABI;
kono
parents:
diff changeset
366
kono
parents:
diff changeset
367 closure->tramp = (void *)ffi_go_closure_osf;
kono
parents:
diff changeset
368 closure->cif = cif;
kono
parents:
diff changeset
369 closure->fun = fun;
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 return FFI_OK;
kono
parents:
diff changeset
372 }
kono
parents:
diff changeset
373
kono
parents:
diff changeset
374 long FFI_HIDDEN
kono
parents:
diff changeset
375 ffi_closure_osf_inner (ffi_cif *cif,
kono
parents:
diff changeset
376 void (*fun)(ffi_cif*, void*, void**, void*),
kono
parents:
diff changeset
377 void *user_data,
kono
parents:
diff changeset
378 void *rvalue, unsigned long *argp)
kono
parents:
diff changeset
379 {
kono
parents:
diff changeset
380 void **avalue;
kono
parents:
diff changeset
381 ffi_type **arg_types;
kono
parents:
diff changeset
382 long i, avn, argn, flags;
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 avalue = alloca(cif->nargs * sizeof(void *));
kono
parents:
diff changeset
385 flags = cif->flags;
kono
parents:
diff changeset
386 argn = 0;
kono
parents:
diff changeset
387
kono
parents:
diff changeset
388 /* Copy the caller's structure return address to that the closure
kono
parents:
diff changeset
389 returns the data directly to the caller. */
kono
parents:
diff changeset
390 if (flags == ALPHA_RET_IN_MEM)
kono
parents:
diff changeset
391 {
kono
parents:
diff changeset
392 rvalue = (void *) argp[0];
kono
parents:
diff changeset
393 argn = 1;
kono
parents:
diff changeset
394 }
kono
parents:
diff changeset
395
kono
parents:
diff changeset
396 arg_types = cif->arg_types;
kono
parents:
diff changeset
397
kono
parents:
diff changeset
398 /* Grab the addresses of the arguments from the stack frame. */
kono
parents:
diff changeset
399 for (i = 0, avn = cif->nargs; i < avn; i++)
kono
parents:
diff changeset
400 {
kono
parents:
diff changeset
401 ffi_type *ty = arg_types[i];
kono
parents:
diff changeset
402 int type = ty->type;
kono
parents:
diff changeset
403 void *valp = &argp[argn];
kono
parents:
diff changeset
404 size_t size;
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 switch (type)
kono
parents:
diff changeset
407 {
kono
parents:
diff changeset
408 case FFI_TYPE_INT:
kono
parents:
diff changeset
409 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
410 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
411 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
412 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
413 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
414 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
415 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
416 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
417 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
418 argn += 1;
kono
parents:
diff changeset
419 break;
kono
parents:
diff changeset
420
kono
parents:
diff changeset
421 case FFI_TYPE_VOID:
kono
parents:
diff changeset
422 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
423 size = ty->size;
kono
parents:
diff changeset
424 argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
kono
parents:
diff changeset
425 break;
kono
parents:
diff changeset
426
kono
parents:
diff changeset
427 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
428 /* Floats coming from registers need conversion from double
kono
parents:
diff changeset
429 back to float format. */
kono
parents:
diff changeset
430 if (argn < 6)
kono
parents:
diff changeset
431 {
kono
parents:
diff changeset
432 valp = &argp[argn - 6];
kono
parents:
diff changeset
433 sts(valp, argp[argn - 6]);
kono
parents:
diff changeset
434 }
kono
parents:
diff changeset
435 argn += 1;
kono
parents:
diff changeset
436 break;
kono
parents:
diff changeset
437
kono
parents:
diff changeset
438 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
439 if (argn < 6)
kono
parents:
diff changeset
440 valp = &argp[argn - 6];
kono
parents:
diff changeset
441 argn += 1;
kono
parents:
diff changeset
442 break;
kono
parents:
diff changeset
443
kono
parents:
diff changeset
444 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
445 by_reference:
kono
parents:
diff changeset
446 /* 128-bit long double is passed by reference. */
kono
parents:
diff changeset
447 valp = (void *)argp[argn];
kono
parents:
diff changeset
448 argn += 1;
kono
parents:
diff changeset
449 break;
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
452 type = ty->elements[0]->type;
kono
parents:
diff changeset
453 switch (type)
kono
parents:
diff changeset
454 {
kono
parents:
diff changeset
455 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
456 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
457 /* Passed as separate arguments, but they wind up sequential. */
kono
parents:
diff changeset
458 break;
kono
parents:
diff changeset
459
kono
parents:
diff changeset
460 case FFI_TYPE_INT:
kono
parents:
diff changeset
461 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
462 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
463 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
464 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
465 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
466 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
467 /* Passed as separate arguments. Disjoint, but there's room
kono
parents:
diff changeset
468 enough in one slot to hold the pair. */
kono
parents:
diff changeset
469 size = ty->elements[0]->size;
kono
parents:
diff changeset
470 memcpy(valp + size, valp + 8, size);
kono
parents:
diff changeset
471 break;
kono
parents:
diff changeset
472
kono
parents:
diff changeset
473 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
474 /* Passed as separate arguments. Disjoint, and each piece
kono
parents:
diff changeset
475 may need conversion back to float. */
kono
parents:
diff changeset
476 if (argn < 6)
kono
parents:
diff changeset
477 {
kono
parents:
diff changeset
478 valp = &argp[argn - 6];
kono
parents:
diff changeset
479 sts(valp, argp[argn - 6]);
kono
parents:
diff changeset
480 }
kono
parents:
diff changeset
481 if (argn + 1 < 6)
kono
parents:
diff changeset
482 sts(valp + 4, argp[argn + 1 - 6]);
kono
parents:
diff changeset
483 else
kono
parents:
diff changeset
484 *(UINT32 *)(valp + 4) = argp[argn + 1];
kono
parents:
diff changeset
485 break;
kono
parents:
diff changeset
486
kono
parents:
diff changeset
487 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
488 /* Passed as separate arguments. Only disjoint if one part
kono
parents:
diff changeset
489 is in fp regs and the other is on the stack. */
kono
parents:
diff changeset
490 if (argn < 5)
kono
parents:
diff changeset
491 valp = &argp[argn - 6];
kono
parents:
diff changeset
492 else if (argn == 5)
kono
parents:
diff changeset
493 {
kono
parents:
diff changeset
494 valp = alloca(16);
kono
parents:
diff changeset
495 ((UINT64 *)valp)[0] = argp[5 - 6];
kono
parents:
diff changeset
496 ((UINT64 *)valp)[1] = argp[6];
kono
parents:
diff changeset
497 }
kono
parents:
diff changeset
498 break;
kono
parents:
diff changeset
499
kono
parents:
diff changeset
500 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
501 goto by_reference;
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 default:
kono
parents:
diff changeset
504 abort();
kono
parents:
diff changeset
505 }
kono
parents:
diff changeset
506 argn += 2;
kono
parents:
diff changeset
507 break;
kono
parents:
diff changeset
508
kono
parents:
diff changeset
509 default:
kono
parents:
diff changeset
510 abort ();
kono
parents:
diff changeset
511 }
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 avalue[i] = valp;
kono
parents:
diff changeset
514 }
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 /* Invoke the closure. */
kono
parents:
diff changeset
517 fun (cif, rvalue, avalue, user_data);
kono
parents:
diff changeset
518
kono
parents:
diff changeset
519 /* Tell ffi_closure_osf how to perform return type promotions. */
kono
parents:
diff changeset
520 return (flags >> ALPHA_LD_SHIFT) & 0xff;
kono
parents:
diff changeset
521 }