]> git.ipfire.org Git - thirdparty/gcc.git/blob - libffi/src/kvx/ffi.c
libffi: Sync with libffi 3.4.2
[thirdparty/gcc.git] / libffi / src / kvx / ffi.c
1 /* Copyright (c) 2020 Kalray
2
3 Permission is hereby granted, free of charge, to any person obtaining
4 a copy of this software and associated documentation files (the
5 ``Software''), to deal in the Software without restriction, including
6 without limitation the rights to use, copy, modify, merge, publish,
7 distribute, sublicense, and/or sell copies of the Software, and to
8 permit persons to whom the Software is furnished to do so, subject to
9 the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
21
22 #if defined(__kvx__)
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <fficonfig.h>
27 #include <ffi.h>
28 #include "ffi_common.h"
29 #include "asm.h"
30
31 #define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1)
32 #define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
33 #define KVX_ABI_STACK_ALIGNMENT (32)
34 #define KVX_ABI_STACK_ARG_ALIGNMENT (8)
35 #define max(a,b) ((a) > (b) ? (a) : (b))
36
37 #ifdef FFI_DEBUG
38 #define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); } while(0)
39 #else
40 #define DEBUG_PRINT(...)
41 #endif
42
43 struct ret_value {
44 unsigned long int r0;
45 unsigned long int r1;
46 unsigned long int r2;
47 unsigned long int r3;
48 };
49
50 extern struct ret_value ffi_call_SYSV(unsigned total_size,
51 unsigned size,
52 extended_cif *ecif,
53 unsigned *rvalue_addr,
54 void *fn,
55 unsigned int_ext_method);
56
57 /* Perform machine dependent cif processing */
58 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
59 {
60 cif->flags = cif->rtype->size;
61 return FFI_OK;
62 }
63
64 /* ffi_prep_args is called by the assembly routine once stack space
65 has been allocated for the function's arguments */
66
67 void *ffi_prep_args(char *stack, unsigned int arg_slots_size, extended_cif *ecif)
68 {
69 char *stacktemp = stack;
70 char *current_arg_passed_by_value = stack + arg_slots_size;
71 int i, s;
72 ffi_type **arg;
73 int count = 0;
74 ffi_cif *cif = ecif->cif;
75 void **argv = ecif->avalue;
76
77 arg = cif->arg_types;
78
79 DEBUG_PRINT("stack: %p\n", stack);
80 DEBUG_PRINT("arg_slots_size: %u\n", arg_slots_size);
81 DEBUG_PRINT("current_arg_passed_by_value: %p\n", current_arg_passed_by_value);
82 DEBUG_PRINT("ecif: %p\n", ecif);
83 DEBUG_PRINT("ecif->avalue: %p\n", ecif->avalue);
84
85 for (i = 0; i < cif->nargs; i++) {
86
87 s = KVX_ABI_SLOT_SIZE;
88 switch((*arg)->type) {
89 case FFI_TYPE_SINT8:
90 case FFI_TYPE_UINT8:
91 case FFI_TYPE_SINT16:
92 case FFI_TYPE_UINT16:
93 case FFI_TYPE_SINT32:
94 case FFI_TYPE_UINT32:
95 case FFI_TYPE_FLOAT:
96 case FFI_TYPE_DOUBLE:
97 case FFI_TYPE_UINT64:
98 case FFI_TYPE_SINT64:
99 case FFI_TYPE_POINTER:
100 DEBUG_PRINT("INT64/32/16/8/FLOAT/DOUBLE or POINTER @%p\n", stack);
101 *(uint64_t *) stack = *(uint64_t *)(* argv);
102 break;
103
104 case FFI_TYPE_COMPLEX:
105 if ((*arg)->size == 8)
106 *(_Complex float *) stack = *(_Complex float *)(* argv);
107 else if ((*arg)->size == 16) {
108 *(_Complex double *) stack = *(_Complex double *)(* argv);
109 s = 16;
110 } else
111 abort();
112 break;
113 case FFI_TYPE_STRUCT: {
114 char *value;
115 unsigned int written_size = 0;
116 DEBUG_PRINT("struct by value @%p\n", stack);
117 if ((*arg)->size > KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE) {
118 DEBUG_PRINT("big struct\n");
119 *(uint64_t *) stack = (uintptr_t)current_arg_passed_by_value;
120 value = current_arg_passed_by_value;
121 current_arg_passed_by_value += (*arg)->size;
122 written_size = KVX_ABI_SLOT_SIZE;
123 } else {
124 value = stack;
125 written_size = (*arg)->size;
126 }
127 memcpy(value, *argv, (*arg)->size);
128 s = ALIGN(written_size, KVX_ABI_STACK_ARG_ALIGNMENT);
129 break;
130 }
131 default:
132 printf("Error: unsupported arg type %d\n", (*arg)->type);
133 abort();
134 break;
135
136 }
137 stack += s;
138 count += s;
139 argv++;
140 arg++;
141 }
142 #ifdef FFI_DEBUG
143 FFI_ASSERT(((intptr_t)(stacktemp + REG_ARGS_SIZE) & (KVX_ABI_STACK_ALIGNMENT-1)) == 0);
144 #endif
145 return stacktemp + REG_ARGS_SIZE;
146 }
147
148 /* Perform machine dependent cif processing when we have a variadic function */
149
150 ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
151 unsigned int ntotalargs)
152 {
153 cif->flags = cif->rtype->size;
154 return FFI_OK;
155 }
156
157 static unsigned long handle_small_int_ext(kvx_intext_method *int_ext_method,
158 const ffi_type *rtype)
159 {
160 switch (rtype->type) {
161 case FFI_TYPE_SINT8:
162 *int_ext_method = KVX_RET_SXBD;
163 return KVX_REGISTER_SIZE;
164
165 case FFI_TYPE_SINT16:
166 *int_ext_method = KVX_RET_SXHD;
167 return KVX_REGISTER_SIZE;
168
169 case FFI_TYPE_SINT32:
170 *int_ext_method = KVX_RET_SXWD;
171 return KVX_REGISTER_SIZE;
172
173 case FFI_TYPE_UINT8:
174 *int_ext_method = KVX_RET_ZXBD;
175 return KVX_REGISTER_SIZE;
176
177 case FFI_TYPE_UINT16:
178 *int_ext_method = KVX_RET_ZXHD;
179 return KVX_REGISTER_SIZE;
180
181 case FFI_TYPE_UINT32:
182 *int_ext_method = KVX_RET_ZXWD;
183 return KVX_REGISTER_SIZE;
184
185 default:
186 *int_ext_method = KVX_RET_NONE;
187 return rtype->size;
188 }
189 }
190
191 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
192 {
193 int i;
194 unsigned long int slot_fitting_args_size = 0;
195 unsigned long int total_size = 0;
196 unsigned long int big_struct_size = 0;
197 kvx_intext_method int_extension_method;
198 ffi_type **arg;
199 struct ret_value local_rvalue = {0};
200 size_t wb_size;
201
202
203 /* Calculate size to allocate on stack */
204 for (i = 0, arg = cif->arg_types; i < cif->nargs; i++, arg++) {
205 DEBUG_PRINT("argument %d, type %d, size %lu\n", i, (*arg)->type, (*arg)->size);
206 if (((*arg)->type == FFI_TYPE_STRUCT) || ((*arg)->type == FFI_TYPE_COMPLEX)) {
207 if ((*arg)->size <= KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE) {
208 slot_fitting_args_size += ALIGN((*arg)->size, KVX_ABI_SLOT_SIZE);
209 } else {
210 slot_fitting_args_size += KVX_ABI_SLOT_SIZE; /* aggregate passed by reference */
211 big_struct_size += ALIGN((*arg)->size, KVX_ABI_SLOT_SIZE);
212 }
213 } else if ((*arg)->size <= KVX_ABI_SLOT_SIZE) {
214 slot_fitting_args_size += KVX_ABI_SLOT_SIZE;
215 } else {
216 printf("Error: unsupported arg size %ld arg type %d\n", (*arg)->size, (*arg)->type);
217 abort(); /* should never happen? */
218 }
219 }
220
221 extended_cif ecif;
222 ecif.cif = cif;
223 ecif.avalue = avalue;
224 ecif.rvalue = rvalue;
225
226 /* This implementation allocates anyway for all register based args */
227 slot_fitting_args_size = max(slot_fitting_args_size, REG_ARGS_SIZE);
228 total_size = slot_fitting_args_size + big_struct_size;
229 total_size = ALIGN(total_size, KVX_ABI_STACK_ALIGNMENT);
230
231 /* wb_size: write back size, the size we will need to write back to user
232 * provided buffer. In theory it should always be cif->flags which is
233 * cif->rtype->size. But libffi API mandates that for integral types
234 * of size <= system register size, then we *MUST* write back
235 * the size of system register size.
236 * in our case, if size <= 8 bytes we must write back 8 bytes.
237 * floats, complex and structs are not affected, only integrals.
238 */
239 wb_size = handle_small_int_ext(&int_extension_method, cif->rtype);
240
241 switch (cif->abi) {
242 case FFI_SYSV:
243 DEBUG_PRINT("total_size: %lu\n", total_size);
244 DEBUG_PRINT("slot fitting args size: %lu\n", slot_fitting_args_size);
245 DEBUG_PRINT("rvalue: %p\n", rvalue);
246 DEBUG_PRINT("fn: %p\n", fn);
247 DEBUG_PRINT("rsize: %u\n", cif->flags);
248 DEBUG_PRINT("wb_size: %u\n", wb_size);
249 DEBUG_PRINT("int_extension_method: %u\n", int_extension_method);
250 local_rvalue = ffi_call_SYSV(total_size, slot_fitting_args_size,
251 &ecif, rvalue, fn, int_extension_method);
252 if ((cif->flags <= KVX_ABI_MAX_AGGREGATE_IN_REG_SIZE)
253 && (cif->rtype->type != FFI_TYPE_VOID))
254 memcpy(rvalue, &local_rvalue, wb_size);
255 break;
256 default:
257 abort();
258 break;
259 }
260 }
261
262 /* Closures not supported yet */
263 ffi_status
264 ffi_prep_closure_loc (ffi_closure* closure,
265 ffi_cif* cif,
266 void (*fun)(ffi_cif*,void*,void**,void*),
267 void *user_data,
268 void *codeloc)
269 {
270 return FFI_BAD_ABI;
271 }
272
273 #endif /* (__kvx__) */