LWG 3075 basic_string needs deduction guides from basic_string_view
[official-gcc.git] / libffi / src / xtensa / ffi.c
blobfd94dafbe30349e7e557e3a870333656288ba234
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2013 Tensilica, Inc.
4 XTENSA Foreign Function Interface
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:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 DEALINGS IN THE SOFTWARE.
25 ----------------------------------------------------------------------- */
27 #include <ffi.h>
28 #include <ffi_common.h>
31 |----------------------------------------|
32 | |
33 on entry to ffi_call ----> |----------------------------------------|
34 | caller stack frame for registers a0-a3 |
35 |----------------------------------------|
36 | |
37 | additional arguments |
38 entry of the function ---> |----------------------------------------|
39 | copy of function arguments a2-a7 |
40 | - - - - - - - - - - - - - |
41 | |
43 The area below the entry line becomes the new stack frame for the function.
48 #define FFI_TYPE_STRUCT_REGS FFI_TYPE_LAST
51 extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags,
52 void(*fn)(void), unsigned nbytes, extended_cif*);
53 extern void ffi_closure_SYSV(void) FFI_HIDDEN;
55 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
57 switch(cif->rtype->type) {
58 case FFI_TYPE_SINT8:
59 case FFI_TYPE_UINT8:
60 case FFI_TYPE_SINT16:
61 case FFI_TYPE_UINT16:
62 cif->flags = cif->rtype->type;
63 break;
64 case FFI_TYPE_VOID:
65 case FFI_TYPE_FLOAT:
66 cif->flags = FFI_TYPE_UINT32;
67 break;
68 case FFI_TYPE_DOUBLE:
69 case FFI_TYPE_UINT64:
70 case FFI_TYPE_SINT64:
71 cif->flags = FFI_TYPE_UINT64; // cif->rtype->type;
72 break;
73 case FFI_TYPE_STRUCT:
74 cif->flags = FFI_TYPE_STRUCT; //_REGS;
75 /* Up to 16 bytes are returned in registers */
76 if (cif->rtype->size > 4 * 4) {
77 /* returned structure is referenced by a register; use 8 bytes
78 (including 4 bytes for potential additional alignment) */
79 cif->flags = FFI_TYPE_STRUCT;
80 cif->bytes += 8;
82 break;
84 default:
85 cif->flags = FFI_TYPE_UINT32;
86 break;
89 /* Round the stack up to a full 4 register frame, just in case
90 (we use this size in movsp). This way, it's also a multiple of
91 8 bytes for 64-bit arguments. */
92 cif->bytes = ALIGN(cif->bytes, 16);
94 return FFI_OK;
97 void ffi_prep_args(extended_cif *ecif, unsigned char* stack)
99 unsigned int i;
100 unsigned long *addr;
101 ffi_type **ptr;
103 union {
104 void **v;
105 char **c;
106 signed char **sc;
107 unsigned char **uc;
108 signed short **ss;
109 unsigned short **us;
110 unsigned int **i;
111 long long **ll;
112 float **f;
113 double **d;
114 } p_argv;
116 /* Verify that everything is aligned up properly */
117 FFI_ASSERT (((unsigned long) stack & 0x7) == 0);
119 p_argv.v = ecif->avalue;
120 addr = (unsigned long*)stack;
122 /* structures with a size greater than 16 bytes are passed in memory */
123 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 16)
125 *addr++ = (unsigned long)ecif->rvalue;
128 for (i = ecif->cif->nargs, ptr = ecif->cif->arg_types;
129 i > 0;
130 i--, ptr++, p_argv.v++)
132 switch ((*ptr)->type)
134 case FFI_TYPE_SINT8:
135 *addr++ = **p_argv.sc;
136 break;
137 case FFI_TYPE_UINT8:
138 *addr++ = **p_argv.uc;
139 break;
140 case FFI_TYPE_SINT16:
141 *addr++ = **p_argv.ss;
142 break;
143 case FFI_TYPE_UINT16:
144 *addr++ = **p_argv.us;
145 break;
146 case FFI_TYPE_FLOAT:
147 case FFI_TYPE_INT:
148 case FFI_TYPE_UINT32:
149 case FFI_TYPE_SINT32:
150 case FFI_TYPE_POINTER:
151 *addr++ = **p_argv.i;
152 break;
153 case FFI_TYPE_DOUBLE:
154 case FFI_TYPE_UINT64:
155 case FFI_TYPE_SINT64:
156 if (((unsigned long)addr & 4) != 0)
157 addr++;
158 *(unsigned long long*)addr = **p_argv.ll;
159 addr += sizeof(unsigned long long) / sizeof (addr);
160 break;
162 case FFI_TYPE_STRUCT:
164 unsigned long offs;
165 unsigned long size;
167 if (((unsigned long)addr & 4) != 0 && (*ptr)->alignment > 4)
168 addr++;
170 offs = (unsigned long) addr - (unsigned long) stack;
171 size = (*ptr)->size;
173 /* Entire structure must fit the argument registers or referenced */
174 if (offs < FFI_REGISTER_NARGS * 4
175 && offs + size > FFI_REGISTER_NARGS * 4)
176 addr = (unsigned long*) (stack + FFI_REGISTER_NARGS * 4);
178 memcpy((char*) addr, *p_argv.c, size);
179 addr += (size + 3) / 4;
180 break;
183 default:
184 FFI_ASSERT(0);
190 void ffi_call(ffi_cif* cif, void(*fn)(void), void *rvalue, void **avalue)
192 extended_cif ecif;
193 unsigned long rsize = cif->rtype->size;
194 int flags = cif->flags;
195 void *alloc = NULL;
197 ecif.cif = cif;
198 ecif.avalue = avalue;
200 /* Note that for structures that are returned in registers (size <= 16 bytes)
201 we allocate a temporary buffer and use memcpy to copy it to the final
202 destination. The reason is that the target address might be misaligned or
203 the length not a multiple of 4 bytes. Handling all those cases would be
204 very complex. */
206 if (flags == FFI_TYPE_STRUCT && (rsize <= 16 || rvalue == NULL))
208 alloc = alloca(ALIGN(rsize, 4));
209 ecif.rvalue = alloc;
211 else
213 ecif.rvalue = rvalue;
216 if (cif->abi != FFI_SYSV)
217 FFI_ASSERT(0);
219 ffi_call_SYSV (ecif.rvalue, rsize, cif->flags, fn, cif->bytes, &ecif);
221 if (alloc != NULL && rvalue != NULL)
222 memcpy(rvalue, alloc, rsize);
225 extern void ffi_trampoline();
226 extern void ffi_cacheflush(void* start, void* end);
228 ffi_status
229 ffi_prep_closure_loc (ffi_closure* closure,
230 ffi_cif* cif,
231 void (*fun)(ffi_cif*, void*, void**, void*),
232 void *user_data,
233 void *codeloc)
235 /* copye trampoline to stack and patch 'ffi_closure_SYSV' pointer */
236 memcpy(closure->tramp, ffi_trampoline, FFI_TRAMPOLINE_SIZE);
237 *(unsigned int*)(&closure->tramp[8]) = (unsigned int)ffi_closure_SYSV;
239 // Do we have this function?
240 // __builtin___clear_cache(closer->tramp, closer->tramp + FFI_TRAMPOLINE_SIZE)
241 ffi_cacheflush(closure->tramp, closure->tramp + FFI_TRAMPOLINE_SIZE);
243 closure->cif = cif;
244 closure->fun = fun;
245 closure->user_data = user_data;
246 return FFI_OK;
250 long FFI_HIDDEN
251 ffi_closure_SYSV_inner(ffi_closure *closure, void **values, void *rvalue)
253 ffi_cif *cif;
254 ffi_type **arg_types;
255 void **avalue;
256 int i, areg;
258 cif = closure->cif;
259 if (cif->abi != FFI_SYSV)
260 return FFI_BAD_ABI;
262 areg = 0;
264 int rtype = cif->rtype->type;
265 if (rtype == FFI_TYPE_STRUCT && cif->rtype->size > 4 * 4)
267 rvalue = *values;
268 areg++;
271 cif = closure->cif;
272 arg_types = cif->arg_types;
273 avalue = alloca(cif->nargs * sizeof(void *));
275 for (i = 0; i < cif->nargs; i++)
277 if (arg_types[i]->alignment == 8 && (areg & 1) != 0)
278 areg++;
280 // skip the entry 16,a1 framework, add 16 bytes (4 registers)
281 if (areg == FFI_REGISTER_NARGS)
282 areg += 4;
284 if (arg_types[i]->type == FFI_TYPE_STRUCT)
286 int numregs = ((arg_types[i]->size + 3) & ~3) / 4;
287 if (areg < FFI_REGISTER_NARGS && areg + numregs > FFI_REGISTER_NARGS)
288 areg = FFI_REGISTER_NARGS + 4;
291 avalue[i] = &values[areg];
292 areg += (arg_types[i]->size + 3) / 4;
295 (closure->fun)(cif, rvalue, avalue, closure->user_data);
297 return rtype;