]> git.ipfire.org Git - thirdparty/gcc.git/blame - libffi/src/arc/ffi.c
libffi: Sync with libffi 3.4.2
[thirdparty/gcc.git] / libffi / src / arc / ffi.c
CommitLineData
b1760f7f
RH
1/* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2013 Synopsys, Inc. (www.synopsys.com)
3
4 ARC Foreign Function Interface
5
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:
13
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------- */
25
26#include <ffi.h>
27#include <ffi_common.h>
28
29#include <stdlib.h>
30#include <stdint.h>
31
32#include <sys/cachectl.h>
33
34/* for little endian ARC, the code is in fact stored as mixed endian for
35 performance reasons */
36#if __BIG_ENDIAN__
37#define CODE_ENDIAN(x) (x)
38#else
39#define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16))
40#endif
41
42/* ffi_prep_args is called by the assembly routine once stack
43 space has been allocated for the function's arguments. */
44
45void
46ffi_prep_args (char *stack, extended_cif * ecif)
47{
48 unsigned int i;
b1760f7f
RH
49 void **p_argv;
50 char *argp;
51 ffi_type **p_arg;
52
b1760f7f
RH
53 argp = stack;
54
55 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
56 {
57 *(void **) argp = ecif->rvalue;
58 argp += 4;
59 }
60
61 p_argv = ecif->avalue;
62
63 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
64 (i != 0); i--, p_arg++)
65 {
66 size_t z;
67 int alignment;
68
69 /* align alignment to 4 */
70 alignment = (((*p_arg)->alignment - 1) | 3) + 1;
71
72 /* Align if necessary. */
73 if ((alignment - 1) & (unsigned) argp)
92456a4e 74 argp = (char *) FFI_ALIGN (argp, alignment);
b1760f7f
RH
75
76 z = (*p_arg)->size;
77 if (z < sizeof (int))
78 {
79 z = sizeof (int);
80
81 switch ((*p_arg)->type)
82 {
83 case FFI_TYPE_SINT8:
84 *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
85 break;
86
87 case FFI_TYPE_UINT8:
88 *(unsigned int *) argp = (unsigned int) *(UINT8 *) (*p_argv);
89 break;
90
91 case FFI_TYPE_SINT16:
92 *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
93 break;
94
95 case FFI_TYPE_UINT16:
96 *(unsigned int *) argp = (unsigned int) *(UINT16 *) (*p_argv);
97 break;
98
99 case FFI_TYPE_STRUCT:
100 memcpy (argp, *p_argv, (*p_arg)->size);
101 break;
102
103 default:
104 FFI_ASSERT (0);
105 }
106 }
107 else if (z == sizeof (int))
108 {
109 *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
110 }
111 else
112 {
113 if ((*p_arg)->type == FFI_TYPE_STRUCT)
114 {
115 memcpy (argp, *p_argv, z);
116 }
117 else
118 {
119 /* Double or long long 64bit. */
120 memcpy (argp, *p_argv, z);
121 }
122 }
123 p_argv++;
124 argp += z;
125 }
126
127 return;
128}
129
130/* Perform machine dependent cif processing. */
131ffi_status
132ffi_prep_cif_machdep (ffi_cif * cif)
133{
134 /* Set the return type flag. */
135 switch (cif->rtype->type)
136 {
137 case FFI_TYPE_VOID:
138 cif->flags = (unsigned) cif->rtype->type;
139 break;
140
141 case FFI_TYPE_STRUCT:
142 cif->flags = (unsigned) cif->rtype->type;
143 break;
144
145 case FFI_TYPE_SINT64:
146 case FFI_TYPE_UINT64:
147 case FFI_TYPE_DOUBLE:
148 cif->flags = FFI_TYPE_DOUBLE;
149 break;
150
151 case FFI_TYPE_FLOAT:
152 default:
153 cif->flags = FFI_TYPE_INT;
154 break;
155 }
156
157 return FFI_OK;
158}
159
160extern void ffi_call_ARCompact (void (*)(char *, extended_cif *),
161 extended_cif *, unsigned, unsigned,
162 unsigned *, void (*fn) (void));
163
164void
165ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue)
166{
167 extended_cif ecif;
168
169 ecif.cif = cif;
170 ecif.avalue = avalue;
171
172 /* If the return value is a struct and we don't have
173 a return value address then we need to make one. */
174 if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
175 {
176 ecif.rvalue = alloca (cif->rtype->size);
177 }
178 else
179 ecif.rvalue = rvalue;
180
181 switch (cif->abi)
182 {
183 case FFI_ARCOMPACT:
184 ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes,
185 cif->flags, ecif.rvalue, fn);
186 break;
187
188 default:
189 FFI_ASSERT (0);
190 break;
191 }
192}
193
194int
195ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
196 ffi_arg * args)
197{
198 void **arg_area, **p_argv;
199 ffi_cif *cif = closure->cif;
200 char *argp = (char *) args;
201 ffi_type **p_argt;
202 int i;
203
204 arg_area = (void **) alloca (cif->nargs * sizeof (void *));
205
206 /* handle hidden argument */
207 if (cif->flags == FFI_TYPE_STRUCT)
208 {
209 rvalue = *(void **) argp;
210 argp += 4;
211 }
212
213 p_argv = arg_area;
214
215 for (i = 0, p_argt = cif->arg_types; i < cif->nargs;
216 i++, p_argt++, p_argv++)
217 {
218 size_t z;
219 int alignment;
220
221 /* align alignment to 4 */
222 alignment = (((*p_argt)->alignment - 1) | 3) + 1;
223
224 /* Align if necessary. */
225 if ((alignment - 1) & (unsigned) argp)
92456a4e 226 argp = (char *) FFI_ALIGN (argp, alignment);
b1760f7f
RH
227
228 z = (*p_argt)->size;
229 *p_argv = (void *) argp;
230 argp += z;
231 }
232
233 (closure->fun) (cif, rvalue, arg_area, closure->user_data);
234
235 return cif->flags;
236}
237
238extern void ffi_closure_ARCompact (void);
239
240ffi_status
241ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
242 void (*fun) (ffi_cif *, void *, void **, void *),
243 void *user_data, void *codeloc)
244{
245 uint32_t *tramp = (uint32_t *) & (closure->tramp[0]);
246
247 switch (cif->abi)
248 {
249 case FFI_ARCOMPACT:
250 FFI_ASSERT (tramp == codeloc);
251 tramp[0] = CODE_ENDIAN (0x200a1fc0); /* mov r8, pcl */
252 tramp[1] = CODE_ENDIAN (0x20200f80); /* j [long imm] */
253 tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact);
254 break;
255
256 default:
257 return FFI_BAD_ABI;
258 }
259
260 closure->cif = cif;
261 closure->fun = fun;
262 closure->user_data = user_data;
263 cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, BCACHE);
264
265 return FFI_OK;
266}