annotate libffi/src/sparc/ffi64.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) 2011, 2013 Anthony Green
kono
parents:
diff changeset
3 Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 SPARC 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 FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
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 #ifdef SPARC64
kono
parents:
diff changeset
45
kono
parents:
diff changeset
46 /* Flatten the contents of a structure to the parts that are passed in
kono
parents:
diff changeset
47 floating point registers. The return is a bit mask wherein bit N
kono
parents:
diff changeset
48 set means bytes [4*n, 4*n+3] are passed in %fN.
kono
parents:
diff changeset
49
kono
parents:
diff changeset
50 We encode both the (running) size (maximum 32) and mask (maxumum 255)
kono
parents:
diff changeset
51 into one integer. The size is placed in the low byte, so that align
kono
parents:
diff changeset
52 and addition work correctly. The mask is placed in the second byte. */
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 static int
kono
parents:
diff changeset
55 ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
kono
parents:
diff changeset
56 {
kono
parents:
diff changeset
57 ffi_type **elts;
kono
parents:
diff changeset
58 ffi_type *t;
kono
parents:
diff changeset
59
kono
parents:
diff changeset
60 if (outer_type->type == FFI_TYPE_COMPLEX)
kono
parents:
diff changeset
61 {
kono
parents:
diff changeset
62 int m = 0, tt = outer_type->elements[0]->type;
kono
parents:
diff changeset
63 size_t z = outer_type->size;
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 if (tt == FFI_TYPE_FLOAT
kono
parents:
diff changeset
66 || tt == FFI_TYPE_DOUBLE
kono
parents:
diff changeset
67 || tt == FFI_TYPE_LONGDOUBLE)
kono
parents:
diff changeset
68 m = (1 << (z / 4)) - 1;
kono
parents:
diff changeset
69 return (m << 8) | z;
kono
parents:
diff changeset
70 }
kono
parents:
diff changeset
71 FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT);
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 for (elts = outer_type->elements; (t = *elts) != NULL; elts++)
kono
parents:
diff changeset
74 {
kono
parents:
diff changeset
75 size_t z = t->size;
kono
parents:
diff changeset
76 int o, m, tt;
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 size_mask = ALIGN(size_mask, t->alignment);
kono
parents:
diff changeset
79 switch (t->type)
kono
parents:
diff changeset
80 {
kono
parents:
diff changeset
81 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
82 size_mask = ffi_struct_float_mask (t, size_mask);
kono
parents:
diff changeset
83 continue;
kono
parents:
diff changeset
84 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
85 tt = t->elements[0]->type;
kono
parents:
diff changeset
86 if (tt != FFI_TYPE_FLOAT
kono
parents:
diff changeset
87 && tt != FFI_TYPE_DOUBLE
kono
parents:
diff changeset
88 && tt != FFI_TYPE_LONGDOUBLE)
kono
parents:
diff changeset
89 break;
kono
parents:
diff changeset
90 /* FALLTHRU */
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 m = (1 << (z / 4)) - 1; /* compute mask for type */
kono
parents:
diff changeset
95 o = (size_mask >> 2) & 0x3f; /* extract word offset */
kono
parents:
diff changeset
96 size_mask |= m << (o + 8); /* insert mask into place */
kono
parents:
diff changeset
97 break;
kono
parents:
diff changeset
98 }
kono
parents:
diff changeset
99 size_mask += z;
kono
parents:
diff changeset
100 }
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 size_mask = ALIGN(size_mask, outer_type->alignment);
kono
parents:
diff changeset
103 FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 return size_mask;
kono
parents:
diff changeset
106 }
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 /* Merge floating point data into integer data. If the structure is
kono
parents:
diff changeset
109 entirely floating point, simply return a pointer to the fp data. */
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 static void *
kono
parents:
diff changeset
112 ffi_struct_float_merge (int size_mask, void *vi, void *vf)
kono
parents:
diff changeset
113 {
kono
parents:
diff changeset
114 int size = size_mask & 0xff;
kono
parents:
diff changeset
115 int mask = size_mask >> 8;
kono
parents:
diff changeset
116 int n = size >> 2;
kono
parents:
diff changeset
117
kono
parents:
diff changeset
118 if (mask == 0)
kono
parents:
diff changeset
119 return vi;
kono
parents:
diff changeset
120 else if (mask == (1 << n) - 1)
kono
parents:
diff changeset
121 return vf;
kono
parents:
diff changeset
122 else
kono
parents:
diff changeset
123 {
kono
parents:
diff changeset
124 unsigned int *wi = vi, *wf = vf;
kono
parents:
diff changeset
125 int i;
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 for (i = 0; i < n; ++i)
kono
parents:
diff changeset
128 if ((mask >> i) & 1)
kono
parents:
diff changeset
129 wi[i] = wf[i];
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 return vi;
kono
parents:
diff changeset
132 }
kono
parents:
diff changeset
133 }
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 /* Similar, but place the data into VD in the end. */
kono
parents:
diff changeset
136
kono
parents:
diff changeset
137 void FFI_HIDDEN
kono
parents:
diff changeset
138 ffi_struct_float_copy (int size_mask, void *vd, void *vi, void *vf)
kono
parents:
diff changeset
139 {
kono
parents:
diff changeset
140 int size = size_mask & 0xff;
kono
parents:
diff changeset
141 int mask = size_mask >> 8;
kono
parents:
diff changeset
142 int n = size >> 2;
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 if (mask == 0)
kono
parents:
diff changeset
145 ;
kono
parents:
diff changeset
146 else if (mask == (1 << n) - 1)
kono
parents:
diff changeset
147 vi = vf;
kono
parents:
diff changeset
148 else
kono
parents:
diff changeset
149 {
kono
parents:
diff changeset
150 unsigned int *wd = vd, *wi = vi, *wf = vf;
kono
parents:
diff changeset
151 int i;
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 for (i = 0; i < n; ++i)
kono
parents:
diff changeset
154 wd[i] = ((mask >> i) & 1 ? wf : wi)[i];
kono
parents:
diff changeset
155 return;
kono
parents:
diff changeset
156 }
kono
parents:
diff changeset
157 memcpy (vd, vi, size);
kono
parents:
diff changeset
158 }
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 /* Perform machine dependent cif processing */
kono
parents:
diff changeset
161
kono
parents:
diff changeset
162 static ffi_status
kono
parents:
diff changeset
163 ffi_prep_cif_machdep_core(ffi_cif *cif)
kono
parents:
diff changeset
164 {
kono
parents:
diff changeset
165 ffi_type *rtype = cif->rtype;
kono
parents:
diff changeset
166 int rtt = rtype->type;
kono
parents:
diff changeset
167 size_t bytes = 0;
kono
parents:
diff changeset
168 int i, n, flags;
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 /* Set the return type flag */
kono
parents:
diff changeset
171 switch (rtt)
kono
parents:
diff changeset
172 {
kono
parents:
diff changeset
173 case FFI_TYPE_VOID:
kono
parents:
diff changeset
174 flags = SPARC_RET_VOID;
kono
parents:
diff changeset
175 break;
kono
parents:
diff changeset
176 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
177 flags = SPARC_RET_F_1;
kono
parents:
diff changeset
178 break;
kono
parents:
diff changeset
179 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
180 flags = SPARC_RET_F_2;
kono
parents:
diff changeset
181 break;
kono
parents:
diff changeset
182 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
183 flags = SPARC_RET_F_4;
kono
parents:
diff changeset
184 break;
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
187 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
188 if (rtype->size > 32)
kono
parents:
diff changeset
189 {
kono
parents:
diff changeset
190 flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM;
kono
parents:
diff changeset
191 bytes = 8;
kono
parents:
diff changeset
192 }
kono
parents:
diff changeset
193 else
kono
parents:
diff changeset
194 {
kono
parents:
diff changeset
195 int size_mask = ffi_struct_float_mask (rtype, 0);
kono
parents:
diff changeset
196 int word_size = (size_mask >> 2) & 0x3f;
kono
parents:
diff changeset
197 int all_mask = (1 << word_size) - 1;
kono
parents:
diff changeset
198 int fp_mask = size_mask >> 8;
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT;
kono
parents:
diff changeset
201
kono
parents:
diff changeset
202 /* For special cases of all-int or all-fp, we can return
kono
parents:
diff changeset
203 the value directly without popping through a struct copy. */
kono
parents:
diff changeset
204 if (fp_mask == 0)
kono
parents:
diff changeset
205 {
kono
parents:
diff changeset
206 if (rtype->alignment >= 8)
kono
parents:
diff changeset
207 {
kono
parents:
diff changeset
208 if (rtype->size == 8)
kono
parents:
diff changeset
209 flags = SPARC_RET_INT64;
kono
parents:
diff changeset
210 else if (rtype->size == 16)
kono
parents:
diff changeset
211 flags = SPARC_RET_INT128;
kono
parents:
diff changeset
212 }
kono
parents:
diff changeset
213 }
kono
parents:
diff changeset
214 else if (fp_mask == all_mask)
kono
parents:
diff changeset
215 switch (word_size)
kono
parents:
diff changeset
216 {
kono
parents:
diff changeset
217 case 1: flags = SPARC_RET_F_1; break;
kono
parents:
diff changeset
218 case 2: flags = SPARC_RET_F_2; break;
kono
parents:
diff changeset
219 case 3: flags = SP_V9_RET_F_3; break;
kono
parents:
diff changeset
220 case 4: flags = SPARC_RET_F_4; break;
kono
parents:
diff changeset
221 /* 5 word structures skipped; handled via RET_STRUCT. */
kono
parents:
diff changeset
222 case 6: flags = SPARC_RET_F_6; break;
kono
parents:
diff changeset
223 /* 7 word structures skipped; handled via RET_STRUCT. */
kono
parents:
diff changeset
224 case 8: flags = SPARC_RET_F_8; break;
kono
parents:
diff changeset
225 }
kono
parents:
diff changeset
226 }
kono
parents:
diff changeset
227 break;
kono
parents:
diff changeset
228
kono
parents:
diff changeset
229 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
230 flags = SPARC_RET_SINT8;
kono
parents:
diff changeset
231 break;
kono
parents:
diff changeset
232 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
233 flags = SPARC_RET_UINT8;
kono
parents:
diff changeset
234 break;
kono
parents:
diff changeset
235 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
236 flags = SPARC_RET_SINT16;
kono
parents:
diff changeset
237 break;
kono
parents:
diff changeset
238 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
239 flags = SPARC_RET_UINT16;
kono
parents:
diff changeset
240 break;
kono
parents:
diff changeset
241 case FFI_TYPE_INT:
kono
parents:
diff changeset
242 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
243 flags = SP_V9_RET_SINT32;
kono
parents:
diff changeset
244 break;
kono
parents:
diff changeset
245 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
246 flags = SPARC_RET_UINT32;
kono
parents:
diff changeset
247 break;
kono
parents:
diff changeset
248 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
249 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
250 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
251 flags = SPARC_RET_INT64;
kono
parents:
diff changeset
252 break;
kono
parents:
diff changeset
253
kono
parents:
diff changeset
254 default:
kono
parents:
diff changeset
255 abort();
kono
parents:
diff changeset
256 }
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 bytes = 0;
kono
parents:
diff changeset
259 for (i = 0, n = cif->nargs; i < n; ++i)
kono
parents:
diff changeset
260 {
kono
parents:
diff changeset
261 ffi_type *ty = cif->arg_types[i];
kono
parents:
diff changeset
262 size_t z = ty->size;
kono
parents:
diff changeset
263 size_t a = ty->alignment;
kono
parents:
diff changeset
264
kono
parents:
diff changeset
265 switch (ty->type)
kono
parents:
diff changeset
266 {
kono
parents:
diff changeset
267 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
268 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
269 /* Large structs passed by reference. */
kono
parents:
diff changeset
270 if (z > 16)
kono
parents:
diff changeset
271 {
kono
parents:
diff changeset
272 a = z = 8;
kono
parents:
diff changeset
273 break;
kono
parents:
diff changeset
274 }
kono
parents:
diff changeset
275 /* Small structs may be passed in integer or fp regs or both. */
kono
parents:
diff changeset
276 if (bytes >= 16*8)
kono
parents:
diff changeset
277 break;
kono
parents:
diff changeset
278 if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0)
kono
parents:
diff changeset
279 break;
kono
parents:
diff changeset
280 /* FALLTHRU */
kono
parents:
diff changeset
281 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
282 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
283 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
284 flags |= SPARC_FLAG_FP_ARGS;
kono
parents:
diff changeset
285 break;
kono
parents:
diff changeset
286 }
kono
parents:
diff changeset
287 bytes = ALIGN(bytes, a);
kono
parents:
diff changeset
288 bytes += ALIGN(z, 8);
kono
parents:
diff changeset
289 }
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 /* Sparc call frames require that space is allocated for 6 args,
kono
parents:
diff changeset
292 even if they aren't used. Make that space if necessary. */
kono
parents:
diff changeset
293 if (bytes < 6 * 8)
kono
parents:
diff changeset
294 bytes = 6 * 8;
kono
parents:
diff changeset
295
kono
parents:
diff changeset
296 /* The stack must be 2 word aligned, so round bytes up appropriately. */
kono
parents:
diff changeset
297 bytes = ALIGN(bytes, 16);
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 /* Include the call frame to prep_args. */
kono
parents:
diff changeset
300 bytes += 8*16 + 8*8;
kono
parents:
diff changeset
301
kono
parents:
diff changeset
302 cif->bytes = bytes;
kono
parents:
diff changeset
303 cif->flags = flags;
kono
parents:
diff changeset
304 return FFI_OK;
kono
parents:
diff changeset
305 }
kono
parents:
diff changeset
306
kono
parents:
diff changeset
307 ffi_status FFI_HIDDEN
kono
parents:
diff changeset
308 ffi_prep_cif_machdep(ffi_cif *cif)
kono
parents:
diff changeset
309 {
kono
parents:
diff changeset
310 cif->nfixedargs = cif->nargs;
kono
parents:
diff changeset
311 return ffi_prep_cif_machdep_core(cif);
kono
parents:
diff changeset
312 }
kono
parents:
diff changeset
313
kono
parents:
diff changeset
314 ffi_status FFI_HIDDEN
kono
parents:
diff changeset
315 ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs)
kono
parents:
diff changeset
316 {
kono
parents:
diff changeset
317 cif->nfixedargs = nfixedargs;
kono
parents:
diff changeset
318 return ffi_prep_cif_machdep_core(cif);
kono
parents:
diff changeset
319 }
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321 extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue,
kono
parents:
diff changeset
322 void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
kono
parents:
diff changeset
323
kono
parents:
diff changeset
324 /* ffi_prep_args is called by the assembly routine once stack space
kono
parents:
diff changeset
325 has been allocated for the function's arguments */
kono
parents:
diff changeset
326
kono
parents:
diff changeset
327 int FFI_HIDDEN
kono
parents:
diff changeset
328 ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
kono
parents:
diff changeset
329 {
kono
parents:
diff changeset
330 ffi_type **p_arg;
kono
parents:
diff changeset
331 int flags = cif->flags;
kono
parents:
diff changeset
332 int i, nargs;
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 if (rvalue == NULL)
kono
parents:
diff changeset
335 {
kono
parents:
diff changeset
336 if (flags & SPARC_FLAG_RET_IN_MEM)
kono
parents:
diff changeset
337 {
kono
parents:
diff changeset
338 /* Since we pass the pointer to the callee, we need a value.
kono
parents:
diff changeset
339 We allowed for this space in ffi_call, before ffi_call_v8
kono
parents:
diff changeset
340 alloca'd the space. */
kono
parents:
diff changeset
341 rvalue = (char *)argp + cif->bytes;
kono
parents:
diff changeset
342 }
kono
parents:
diff changeset
343 else
kono
parents:
diff changeset
344 {
kono
parents:
diff changeset
345 /* Otherwise, we can ignore the return value. */
kono
parents:
diff changeset
346 flags = SPARC_RET_VOID;
kono
parents:
diff changeset
347 }
kono
parents:
diff changeset
348 }
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 #ifdef USING_PURIFY
kono
parents:
diff changeset
351 /* Purify will probably complain in our assembly routine,
kono
parents:
diff changeset
352 unless we zero out this memory. */
kono
parents:
diff changeset
353 memset(argp, 0, 6*8);
kono
parents:
diff changeset
354 #endif
kono
parents:
diff changeset
355
kono
parents:
diff changeset
356 if (flags & SPARC_FLAG_RET_IN_MEM)
kono
parents:
diff changeset
357 *argp++ = (unsigned long)rvalue;
kono
parents:
diff changeset
358
kono
parents:
diff changeset
359 p_arg = cif->arg_types;
kono
parents:
diff changeset
360 for (i = 0, nargs = cif->nargs; i < nargs; i++)
kono
parents:
diff changeset
361 {
kono
parents:
diff changeset
362 ffi_type *ty = p_arg[i];
kono
parents:
diff changeset
363 void *a = avalue[i];
kono
parents:
diff changeset
364 size_t z;
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366 switch (ty->type)
kono
parents:
diff changeset
367 {
kono
parents:
diff changeset
368 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
369 *argp++ = *(SINT8 *)a;
kono
parents:
diff changeset
370 break;
kono
parents:
diff changeset
371 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
372 *argp++ = *(UINT8 *)a;
kono
parents:
diff changeset
373 break;
kono
parents:
diff changeset
374 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
375 *argp++ = *(SINT16 *)a;
kono
parents:
diff changeset
376 break;
kono
parents:
diff changeset
377 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
378 *argp++ = *(UINT16 *)a;
kono
parents:
diff changeset
379 break;
kono
parents:
diff changeset
380 case FFI_TYPE_INT:
kono
parents:
diff changeset
381 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
382 *argp++ = *(SINT32 *)a;
kono
parents:
diff changeset
383 break;
kono
parents:
diff changeset
384 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
385 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
386 *argp++ = *(UINT32 *)a;
kono
parents:
diff changeset
387 break;
kono
parents:
diff changeset
388 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
389 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
390 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
391 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
392 *argp++ = *(UINT64 *)a;
kono
parents:
diff changeset
393 break;
kono
parents:
diff changeset
394
kono
parents:
diff changeset
395 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
396 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
397 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
398 z = ty->size;
kono
parents:
diff changeset
399 if (z > 16)
kono
parents:
diff changeset
400 {
kono
parents:
diff changeset
401 /* For structures larger than 16 bytes we pass reference. */
kono
parents:
diff changeset
402 *argp++ = (unsigned long)a;
kono
parents:
diff changeset
403 break;
kono
parents:
diff changeset
404 }
kono
parents:
diff changeset
405 if (((unsigned long)argp & 15) && ty->alignment > 8)
kono
parents:
diff changeset
406 argp++;
kono
parents:
diff changeset
407 memcpy(argp, a, z);
kono
parents:
diff changeset
408 argp += ALIGN(z, 8) / 8;
kono
parents:
diff changeset
409 break;
kono
parents:
diff changeset
410
kono
parents:
diff changeset
411 default:
kono
parents:
diff changeset
412 abort();
kono
parents:
diff changeset
413 }
kono
parents:
diff changeset
414 }
kono
parents:
diff changeset
415
kono
parents:
diff changeset
416 return flags;
kono
parents:
diff changeset
417 }
kono
parents:
diff changeset
418
kono
parents:
diff changeset
419 static void
kono
parents:
diff changeset
420 ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
kono
parents:
diff changeset
421 void **avalue, void *closure)
kono
parents:
diff changeset
422 {
kono
parents:
diff changeset
423 size_t bytes = cif->bytes;
kono
parents:
diff changeset
424
kono
parents:
diff changeset
425 FFI_ASSERT (cif->abi == FFI_V9);
kono
parents:
diff changeset
426
kono
parents:
diff changeset
427 if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
kono
parents:
diff changeset
428 bytes += ALIGN (cif->rtype->size, 16);
kono
parents:
diff changeset
429
kono
parents:
diff changeset
430 ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
kono
parents:
diff changeset
431 }
kono
parents:
diff changeset
432
kono
parents:
diff changeset
433 void
kono
parents:
diff changeset
434 ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
kono
parents:
diff changeset
435 {
kono
parents:
diff changeset
436 ffi_call_int(cif, fn, rvalue, avalue, NULL);
kono
parents:
diff changeset
437 }
kono
parents:
diff changeset
438
kono
parents:
diff changeset
439 void
kono
parents:
diff changeset
440 ffi_call_go(ffi_cif *cif, void (*fn)(void), void *rvalue,
kono
parents:
diff changeset
441 void **avalue, void *closure)
kono
parents:
diff changeset
442 {
kono
parents:
diff changeset
443 ffi_call_int(cif, fn, rvalue, avalue, closure);
kono
parents:
diff changeset
444 }
kono
parents:
diff changeset
445
kono
parents:
diff changeset
446 #ifdef __GNUC__
kono
parents:
diff changeset
447 static inline void
kono
parents:
diff changeset
448 ffi_flush_icache (void *p)
kono
parents:
diff changeset
449 {
kono
parents:
diff changeset
450 asm volatile ("flush %0; flush %0+8" : : "r" (p) : "memory");
kono
parents:
diff changeset
451 }
kono
parents:
diff changeset
452 #else
kono
parents:
diff changeset
453 extern void ffi_flush_icache (void *) FFI_HIDDEN;
kono
parents:
diff changeset
454 #endif
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 extern void ffi_closure_v9(void) FFI_HIDDEN;
kono
parents:
diff changeset
457 extern void ffi_go_closure_v9(void) FFI_HIDDEN;
kono
parents:
diff changeset
458
kono
parents:
diff changeset
459 ffi_status
kono
parents:
diff changeset
460 ffi_prep_closure_loc (ffi_closure* closure,
kono
parents:
diff changeset
461 ffi_cif* cif,
kono
parents:
diff changeset
462 void (*fun)(ffi_cif*, void*, void**, void*),
kono
parents:
diff changeset
463 void *user_data,
kono
parents:
diff changeset
464 void *codeloc)
kono
parents:
diff changeset
465 {
kono
parents:
diff changeset
466 unsigned int *tramp = (unsigned int *) &closure->tramp[0];
kono
parents:
diff changeset
467 unsigned long fn;
kono
parents:
diff changeset
468
kono
parents:
diff changeset
469 if (cif->abi != FFI_V9)
kono
parents:
diff changeset
470 return FFI_BAD_ABI;
kono
parents:
diff changeset
471
kono
parents:
diff changeset
472 /* Trampoline address is equal to the closure address. We take advantage
kono
parents:
diff changeset
473 of that to reduce the trampoline size by 8 bytes. */
kono
parents:
diff changeset
474 fn = (unsigned long) ffi_closure_v9;
kono
parents:
diff changeset
475 tramp[0] = 0x83414000; /* rd %pc, %g1 */
kono
parents:
diff changeset
476 tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
kono
parents:
diff changeset
477 tramp[2] = 0x81c14000; /* jmp %g5 */
kono
parents:
diff changeset
478 tramp[3] = 0x01000000; /* nop */
kono
parents:
diff changeset
479 *((unsigned long *) &tramp[4]) = fn;
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 closure->cif = cif;
kono
parents:
diff changeset
482 closure->fun = fun;
kono
parents:
diff changeset
483 closure->user_data = user_data;
kono
parents:
diff changeset
484
kono
parents:
diff changeset
485 ffi_flush_icache (closure);
kono
parents:
diff changeset
486
kono
parents:
diff changeset
487 return FFI_OK;
kono
parents:
diff changeset
488 }
kono
parents:
diff changeset
489
kono
parents:
diff changeset
490 ffi_status
kono
parents:
diff changeset
491 ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
kono
parents:
diff changeset
492 void (*fun)(ffi_cif*, void*, void**, void*))
kono
parents:
diff changeset
493 {
kono
parents:
diff changeset
494 if (cif->abi != FFI_V9)
kono
parents:
diff changeset
495 return FFI_BAD_ABI;
kono
parents:
diff changeset
496
kono
parents:
diff changeset
497 closure->tramp = ffi_go_closure_v9;
kono
parents:
diff changeset
498 closure->cif = cif;
kono
parents:
diff changeset
499 closure->fun = fun;
kono
parents:
diff changeset
500
kono
parents:
diff changeset
501 return FFI_OK;
kono
parents:
diff changeset
502 }
kono
parents:
diff changeset
503
kono
parents:
diff changeset
504 int FFI_HIDDEN
kono
parents:
diff changeset
505 ffi_closure_sparc_inner_v9(ffi_cif *cif,
kono
parents:
diff changeset
506 void (*fun)(ffi_cif*, void*, void**, void*),
kono
parents:
diff changeset
507 void *user_data, void *rvalue,
kono
parents:
diff changeset
508 unsigned long *gpr, unsigned long *fpr)
kono
parents:
diff changeset
509 {
kono
parents:
diff changeset
510 ffi_type **arg_types;
kono
parents:
diff changeset
511 void **avalue;
kono
parents:
diff changeset
512 int i, argn, argx, nargs, flags, nfixedargs;
kono
parents:
diff changeset
513
kono
parents:
diff changeset
514 arg_types = cif->arg_types;
kono
parents:
diff changeset
515 nargs = cif->nargs;
kono
parents:
diff changeset
516 flags = cif->flags;
kono
parents:
diff changeset
517 nfixedargs = cif->nfixedargs;
kono
parents:
diff changeset
518
kono
parents:
diff changeset
519 avalue = alloca(nargs * sizeof(void *));
kono
parents:
diff changeset
520
kono
parents:
diff changeset
521 /* Copy the caller's structure return address so that the closure
kono
parents:
diff changeset
522 returns the data directly to the caller. */
kono
parents:
diff changeset
523 if (flags & SPARC_FLAG_RET_IN_MEM)
kono
parents:
diff changeset
524 {
kono
parents:
diff changeset
525 rvalue = (void *) gpr[0];
kono
parents:
diff changeset
526 /* Skip the structure return address. */
kono
parents:
diff changeset
527 argn = 1;
kono
parents:
diff changeset
528 }
kono
parents:
diff changeset
529 else
kono
parents:
diff changeset
530 argn = 0;
kono
parents:
diff changeset
531
kono
parents:
diff changeset
532 /* Grab the addresses of the arguments from the stack frame. */
kono
parents:
diff changeset
533 for (i = 0; i < nargs; i++, argn = argx)
kono
parents:
diff changeset
534 {
kono
parents:
diff changeset
535 int named = i < nfixedargs;
kono
parents:
diff changeset
536 ffi_type *ty = arg_types[i];
kono
parents:
diff changeset
537 void *a = &gpr[argn];
kono
parents:
diff changeset
538 size_t z;
kono
parents:
diff changeset
539
kono
parents:
diff changeset
540 argx = argn + 1;
kono
parents:
diff changeset
541 switch (ty->type)
kono
parents:
diff changeset
542 {
kono
parents:
diff changeset
543 case FFI_TYPE_COMPLEX:
kono
parents:
diff changeset
544 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
545 z = ty->size;
kono
parents:
diff changeset
546 if (z > 16)
kono
parents:
diff changeset
547 a = *(void **)a;
kono
parents:
diff changeset
548 else
kono
parents:
diff changeset
549 {
kono
parents:
diff changeset
550 argx = argn + ALIGN (z, 8) / 8;
kono
parents:
diff changeset
551 if (named && argn < 16)
kono
parents:
diff changeset
552 {
kono
parents:
diff changeset
553 int size_mask = ffi_struct_float_mask (ty, 0);
kono
parents:
diff changeset
554 int argn_mask = (0xffff00 >> argn) & 0xff00;
kono
parents:
diff changeset
555
kono
parents:
diff changeset
556 /* Eliminate fp registers off the end. */
kono
parents:
diff changeset
557 size_mask = (size_mask & 0xff) | (size_mask & argn_mask);
kono
parents:
diff changeset
558 a = ffi_struct_float_merge (size_mask, gpr+argn, fpr+argn);
kono
parents:
diff changeset
559 }
kono
parents:
diff changeset
560 }
kono
parents:
diff changeset
561 break;
kono
parents:
diff changeset
562
kono
parents:
diff changeset
563 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
564 argn = ALIGN (argn, 2);
kono
parents:
diff changeset
565 a = (named && argn < 16 ? fpr : gpr) + argn;
kono
parents:
diff changeset
566 argx = argn + 2;
kono
parents:
diff changeset
567 break;
kono
parents:
diff changeset
568 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
569 if (named && argn < 16)
kono
parents:
diff changeset
570 a = fpr + argn;
kono
parents:
diff changeset
571 break;
kono
parents:
diff changeset
572 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
573 if (named && argn < 16)
kono
parents:
diff changeset
574 a = fpr + argn;
kono
parents:
diff changeset
575 a += 4;
kono
parents:
diff changeset
576 break;
kono
parents:
diff changeset
577
kono
parents:
diff changeset
578 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
579 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
580 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
581 break;
kono
parents:
diff changeset
582 case FFI_TYPE_INT:
kono
parents:
diff changeset
583 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
584 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
585 a += 4;
kono
parents:
diff changeset
586 break;
kono
parents:
diff changeset
587 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
588 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
589 a += 6;
kono
parents:
diff changeset
590 break;
kono
parents:
diff changeset
591 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
592 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
593 a += 7;
kono
parents:
diff changeset
594 break;
kono
parents:
diff changeset
595
kono
parents:
diff changeset
596 default:
kono
parents:
diff changeset
597 abort();
kono
parents:
diff changeset
598 }
kono
parents:
diff changeset
599 avalue[i] = a;
kono
parents:
diff changeset
600 }
kono
parents:
diff changeset
601
kono
parents:
diff changeset
602 /* Invoke the closure. */
kono
parents:
diff changeset
603 fun (cif, rvalue, avalue, user_data);
kono
parents:
diff changeset
604
kono
parents:
diff changeset
605 /* Tell ffi_closure_sparc how to perform return type promotions. */
kono
parents:
diff changeset
606 return flags;
kono
parents:
diff changeset
607 }
kono
parents:
diff changeset
608 #endif /* SPARC64 */