2018-10-25 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libffi / src / riscv / ffi.c
blob8c5a86050607194b5a29bc237d77cd488547efec
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
3 2015 Andrew Waterman <waterman@cs.berkeley.edu>
4 2018 Stef O'Rear <sorear2@gmail.com>
5 Based on MIPS N32/64 port
7 RISC-V Foreign Function Interface
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 ``Software''), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
28 ----------------------------------------------------------------------- */
30 #include <ffi.h>
31 #include <ffi_common.h>
33 #include <stdlib.h>
34 #include <stdint.h>
36 #if __riscv_float_abi_double
37 #define ABI_FLEN 64
38 #define ABI_FLOAT double
39 #elif __riscv_float_abi_single
40 #define ABI_FLEN 32
41 #define ABI_FLOAT float
42 #endif
44 #define NARGREG 8
45 #define STKALIGN 16
46 #define MAXCOPYARG (2 * sizeof(double))
48 typedef struct call_context
50 #if ABI_FLEN
51 ABI_FLOAT fa[8];
52 #endif
53 size_t a[8];
54 /* used by the assembly code to in-place construct its own stack frame */
55 char frame[16];
56 } call_context;
58 typedef struct call_builder
60 call_context *aregs;
61 int used_integer;
62 int used_float;
63 size_t *used_stack;
64 } call_builder;
66 /* integer (not pointer) less than ABI XLEN */
67 /* FFI_TYPE_INT does not appear to be used */
68 #if __SIZEOF_POINTER__ == 8
69 #define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT64)
70 #else
71 #define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT32)
72 #endif
74 #if ABI_FLEN
75 typedef struct {
76 char as_elements, type1, offset2, type2;
77 } float_struct_info;
79 #if ABI_FLEN >= 64
80 #define IS_FLOAT(type) ((type) >= FFI_TYPE_FLOAT && (type) <= FFI_TYPE_DOUBLE)
81 #else
82 #define IS_FLOAT(type) ((type) == FFI_TYPE_FLOAT)
83 #endif
85 static ffi_type **flatten_struct(ffi_type *in, ffi_type **out, ffi_type **out_end) {
86 int i;
87 if (out == out_end) return out;
88 if (in->type != FFI_TYPE_STRUCT) {
89 *(out++) = in;
90 } else {
91 for (i = 0; in->elements[i]; i++)
92 out = flatten_struct(in->elements[i], out, out_end);
94 return out;
97 /* Structs with at most two fields after flattening, one of which is of
98 floating point type, are passed in multiple registers if sufficient
99 registers are available. */
100 static float_struct_info struct_passed_as_elements(call_builder *cb, ffi_type *top) {
101 float_struct_info ret = {0, 0, 0, 0};
102 ffi_type *fields[3];
103 int num_floats, num_ints;
104 int num_fields = flatten_struct(top, fields, fields + 3) - fields;
106 if (num_fields == 1) {
107 if (IS_FLOAT(fields[0]->type)) {
108 ret.as_elements = 1;
109 ret.type1 = fields[0]->type;
111 } else if (num_fields == 2) {
112 num_floats = IS_FLOAT(fields[0]->type) + IS_FLOAT(fields[1]->type);
113 num_ints = IS_INT(fields[0]->type) + IS_INT(fields[1]->type);
114 if (num_floats == 0 || num_floats + num_ints != 2)
115 return ret;
116 if (cb->used_float + num_floats > NARGREG || cb->used_integer + (2 - num_floats) > NARGREG)
117 return ret;
118 if (!IS_FLOAT(fields[0]->type) && !IS_FLOAT(fields[1]->type))
119 return ret;
121 ret.type1 = fields[0]->type;
122 ret.type2 = fields[1]->type;
123 ret.offset2 = ALIGN(fields[0]->size, fields[1]->alignment);
124 ret.as_elements = 1;
127 return ret;
129 #endif
131 /* allocates a single register, float register, or XLEN-sized stack slot to a datum */
132 static void marshal_atom(call_builder *cb, int type, void *data) {
133 size_t value = 0;
134 switch (type) {
135 case FFI_TYPE_UINT8: value = *(uint8_t *)data; break;
136 case FFI_TYPE_SINT8: value = *(int8_t *)data; break;
137 case FFI_TYPE_UINT16: value = *(uint16_t *)data; break;
138 case FFI_TYPE_SINT16: value = *(int16_t *)data; break;
139 /* 32-bit quantities are always sign-extended in the ABI */
140 case FFI_TYPE_UINT32: value = *(int32_t *)data; break;
141 case FFI_TYPE_SINT32: value = *(int32_t *)data; break;
142 #if __SIZEOF_POINTER__ == 8
143 case FFI_TYPE_UINT64: value = *(uint64_t *)data; break;
144 case FFI_TYPE_SINT64: value = *(int64_t *)data; break;
145 #endif
146 case FFI_TYPE_POINTER: value = *(size_t *)data; break;
148 /* float values may be recoded in an implementation-defined way
149 by hardware conforming to 2.1 or earlier, so use asm to
150 reinterpret floats as doubles */
151 #if ABI_FLEN >= 32
152 case FFI_TYPE_FLOAT:
153 asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : "0"(*(float *)data));
154 return;
155 #endif
156 #if ABI_FLEN >= 64
157 case FFI_TYPE_DOUBLE:
158 asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : "0"(*(double *)data));
159 return;
160 #endif
161 default: FFI_ASSERT(0); break;
164 if (cb->used_integer == NARGREG) {
165 *cb->used_stack++ = value;
166 } else {
167 cb->aregs->a[cb->used_integer++] = value;
171 static void unmarshal_atom(call_builder *cb, int type, void *data) {
172 size_t value;
173 switch (type) {
174 #if ABI_FLEN >= 32
175 case FFI_TYPE_FLOAT:
176 asm("" : "=f"(*(float *)data) : "0"(cb->aregs->fa[cb->used_float++]));
177 return;
178 #endif
179 #if ABI_FLEN >= 64
180 case FFI_TYPE_DOUBLE:
181 asm("" : "=f"(*(double *)data) : "0"(cb->aregs->fa[cb->used_float++]));
182 return;
183 #endif
186 if (cb->used_integer == NARGREG) {
187 value = *cb->used_stack++;
188 } else {
189 value = cb->aregs->a[cb->used_integer++];
192 switch (type) {
193 case FFI_TYPE_UINT8: *(uint8_t *)data = value; break;
194 case FFI_TYPE_SINT8: *(uint8_t *)data = value; break;
195 case FFI_TYPE_UINT16: *(uint16_t *)data = value; break;
196 case FFI_TYPE_SINT16: *(uint16_t *)data = value; break;
197 case FFI_TYPE_UINT32: *(uint32_t *)data = value; break;
198 case FFI_TYPE_SINT32: *(uint32_t *)data = value; break;
199 #if __SIZEOF_POINTER__ == 8
200 case FFI_TYPE_UINT64: *(uint64_t *)data = value; break;
201 case FFI_TYPE_SINT64: *(uint64_t *)data = value; break;
202 #endif
203 case FFI_TYPE_POINTER: *(size_t *)data = value; break;
204 default: FFI_ASSERT(0); break;
208 /* adds an argument to a call, or a not by reference return value */
209 static void marshal(call_builder *cb, ffi_type *type, int var, void *data) {
210 size_t realign[2];
212 #if ABI_FLEN
213 if (!var && type->type == FFI_TYPE_STRUCT) {
214 float_struct_info fsi = struct_passed_as_elements(cb, type);
215 if (fsi.as_elements) {
216 marshal_atom(cb, fsi.type1, data);
217 if (fsi.offset2)
218 marshal_atom(cb, fsi.type2, ((char*)data) + fsi.offset2);
219 return;
223 if (!var && cb->used_float < NARGREG && IS_FLOAT(type->type)) {
224 marshal_atom(cb, type->type, data);
225 return;
227 #endif
229 if (type->size > 2 * __SIZEOF_POINTER__) {
230 /* pass by reference */
231 marshal_atom(cb, FFI_TYPE_POINTER, &data);
232 } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) {
233 marshal_atom(cb, type->type, data);
234 } else {
235 /* overlong integers, soft-float floats, and structs without special
236 float handling are treated identically from this point on */
238 /* variadics are aligned even in registers */
239 if (type->alignment > __SIZEOF_POINTER__) {
240 if (var)
241 cb->used_integer = ALIGN(cb->used_integer, 2);
242 cb->used_stack = (size_t *)ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__);
245 memcpy(realign, data, type->size);
246 if (type->size > 0)
247 marshal_atom(cb, FFI_TYPE_POINTER, realign);
248 if (type->size > __SIZEOF_POINTER__)
249 marshal_atom(cb, FFI_TYPE_POINTER, realign + 1);
253 /* for arguments passed by reference returns the pointer, otherwise the arg is copied (up to MAXCOPYARG bytes) */
254 static void *unmarshal(call_builder *cb, ffi_type *type, int var, void *data) {
255 size_t realign[2];
256 void *pointer;
258 #if ABI_FLEN
259 if (!var && type->type == FFI_TYPE_STRUCT) {
260 float_struct_info fsi = struct_passed_as_elements(cb, type);
261 if (fsi.as_elements) {
262 unmarshal_atom(cb, fsi.type1, data);
263 if (fsi.offset2)
264 unmarshal_atom(cb, fsi.type2, ((char*)data) + fsi.offset2);
265 return data;
269 if (!var && cb->used_float < NARGREG && IS_FLOAT(type->type)) {
270 unmarshal_atom(cb, type->type, data);
271 return data;
273 #endif
275 if (type->size > 2 * __SIZEOF_POINTER__) {
276 /* pass by reference */
277 unmarshal_atom(cb, FFI_TYPE_POINTER, (char*)&pointer);
278 return pointer;
279 } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) {
280 unmarshal_atom(cb, type->type, data);
281 return data;
282 } else {
283 /* overlong integers, soft-float floats, and structs without special
284 float handling are treated identically from this point on */
286 /* variadics are aligned even in registers */
287 if (type->alignment > __SIZEOF_POINTER__) {
288 if (var)
289 cb->used_integer = ALIGN(cb->used_integer, 2);
290 cb->used_stack = (size_t *)ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__);
293 if (type->size > 0)
294 unmarshal_atom(cb, FFI_TYPE_POINTER, realign);
295 if (type->size > __SIZEOF_POINTER__)
296 unmarshal_atom(cb, FFI_TYPE_POINTER, realign + 1);
297 memcpy(data, realign, type->size);
298 return data;
302 static int passed_by_ref(call_builder *cb, ffi_type *type, int var) {
303 #if ABI_FLEN
304 if (!var && type->type == FFI_TYPE_STRUCT) {
305 float_struct_info fsi = struct_passed_as_elements(cb, type);
306 if (fsi.as_elements) return 0;
308 #endif
310 return type->size > 2 * __SIZEOF_POINTER__;
313 /* Perform machine dependent cif processing */
314 ffi_status ffi_prep_cif_machdep(ffi_cif *cif) {
315 cif->riscv_nfixedargs = cif->nargs;
316 return FFI_OK;
319 /* Perform machine dependent cif processing when we have a variadic function */
321 ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs) {
322 cif->riscv_nfixedargs = nfixedargs;
323 return FFI_OK;
326 /* Low level routine for calling functions */
327 extern void ffi_call_asm (void *stack, struct call_context *regs,
328 void (*fn) (void), void *closure) FFI_HIDDEN;
330 static void
331 ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
332 void *closure)
334 /* this is a conservative estimate, assuming a complex return value and
335 that all remaining arguments are long long / __int128 */
336 size_t arg_bytes = cif->nargs <= 3 ? 0 :
337 ALIGN(2 * sizeof(size_t) * (cif->nargs - 3), STKALIGN);
338 size_t rval_bytes = 0;
339 if (rvalue == NULL && cif->rtype->size > 2*__SIZEOF_POINTER__)
340 rval_bytes = ALIGN(cif->rtype->size, STKALIGN);
341 size_t alloc_size = arg_bytes + rval_bytes + sizeof(call_context);
343 /* the assembly code will deallocate all stack data at lower addresses
344 than the argument region, so we need to allocate the frame and the
345 return value after the arguments in a single allocation */
346 size_t alloc_base;
347 /* Argument region must be 16-byte aligned */
348 if (_Alignof(max_align_t) >= STKALIGN) {
349 /* since sizeof long double is normally 16, the compiler will
350 guarantee alloca alignment to at least that much */
351 alloc_base = (size_t)alloca(alloc_size);
352 } else {
353 alloc_base = ALIGN(alloca(alloc_size + STKALIGN - 1), STKALIGN);
356 if (rval_bytes)
357 rvalue = (void*)(alloc_base + arg_bytes);
359 call_builder cb;
360 cb.used_float = cb.used_integer = 0;
361 cb.aregs = (call_context*)(alloc_base + arg_bytes + rval_bytes);
362 cb.used_stack = (void*)alloc_base;
364 int return_by_ref = passed_by_ref(&cb, cif->rtype, 0);
365 if (return_by_ref)
366 marshal(&cb, &ffi_type_pointer, 0, &rvalue);
368 int i;
369 for (i = 0; i < cif->nargs; i++)
370 marshal(&cb, cif->arg_types[i], i >= cif->riscv_nfixedargs, avalue[i]);
372 ffi_call_asm ((void *) alloc_base, cb.aregs, fn, closure);
374 cb.used_float = cb.used_integer = 0;
375 if (!return_by_ref && rvalue)
376 unmarshal(&cb, cif->rtype, 0, rvalue);
379 void
380 ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
382 ffi_call_int(cif, fn, rvalue, avalue, NULL);
385 void
386 ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
387 void **avalue, void *closure)
389 ffi_call_int(cif, fn, rvalue, avalue, closure);
392 extern void ffi_closure_asm(void) FFI_HIDDEN;
394 ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void *codeloc)
396 uint32_t *tramp = (uint32_t *) &closure->tramp[0];
397 uint64_t fn = (uint64_t) (uintptr_t) ffi_closure_asm;
399 if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI)
400 return FFI_BAD_ABI;
402 /* we will call ffi_closure_inner with codeloc, not closure, but as long
403 as the memory is readable it should work */
405 tramp[0] = 0x00000317; /* auipc t1, 0 (i.e. t0 <- codeloc) */
406 #if __SIZEOF_POINTER__ == 8
407 tramp[1] = 0x01033383; /* ld t2, 16(t1) */
408 #else
409 tramp[1] = 0x01032383; /* lw t2, 16(t1) */
410 #endif
411 tramp[2] = 0x00038067; /* jr t2 */
412 tramp[3] = 0x00000013; /* nop */
413 tramp[4] = fn;
414 tramp[5] = fn >> 32;
416 closure->cif = cif;
417 closure->fun = fun;
418 closure->user_data = user_data;
420 __builtin___clear_cache(codeloc, codeloc + FFI_TRAMPOLINE_SIZE);
422 return FFI_OK;
425 extern void ffi_go_closure_asm (void) FFI_HIDDEN;
427 ffi_status
428 ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
429 void (*fun) (ffi_cif *, void *, void **, void *))
431 if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI)
432 return FFI_BAD_ABI;
434 closure->tramp = (void *) ffi_go_closure_asm;
435 closure->cif = cif;
436 closure->fun = fun;
438 return FFI_OK;
441 /* Called by the assembly code with aregs pointing to saved argument registers
442 and stack pointing to the stacked arguments. Return values passed in
443 registers will be reloaded from aregs. */
444 void FFI_HIDDEN
445 ffi_closure_inner (ffi_cif *cif,
446 void (*fun) (ffi_cif *, void *, void **, void *),
447 void *user_data,
448 size_t *stack, call_context *aregs)
450 void **avalue = alloca(cif->nargs * sizeof(void*));
451 /* storage for arguments which will be copied by unmarshal(). We could
452 theoretically avoid the copies in many cases and use at most 128 bytes
453 of memory, but allocating disjoint storage for each argument is
454 simpler. */
455 char *astorage = alloca(cif->nargs * MAXCOPYARG);
456 void *rvalue;
457 call_builder cb;
458 int return_by_ref;
459 int i;
461 cb.aregs = aregs;
462 cb.used_integer = cb.used_float = 0;
463 cb.used_stack = stack;
465 return_by_ref = passed_by_ref(&cb, cif->rtype, 0);
466 if (return_by_ref)
467 unmarshal(&cb, &ffi_type_pointer, 0, &rvalue);
468 else
469 rvalue = alloca(cif->rtype->size);
471 for (i = 0; i < cif->nargs; i++)
472 avalue[i] = unmarshal(&cb, cif->arg_types[i],
473 i >= cif->riscv_nfixedargs, astorage + i*MAXCOPYARG);
475 fun (cif, rvalue, avalue, user_data);
477 if (!return_by_ref && cif->rtype->type != FFI_TYPE_VOID) {
478 cb.used_integer = cb.used_float = 0;
479 marshal(&cb, cif->rtype, 0, rvalue);