github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/sparc/ffi.c (about) 1 /* ----------------------------------------------------------------------- 2 ffi.c - Copyright (c) 2011, 2013 Anthony Green 3 Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc. 4 5 SPARC Foreign Function Interface 6 7 Permission is hereby granted, free of charge, to any person obtaining 8 a copy of this software and associated documentation files (the 9 ``Software''), to deal in the Software without restriction, including 10 without limitation the rights to use, copy, modify, merge, publish, 11 distribute, sublicense, and/or sell copies of the Software, and to 12 permit persons to whom the Software is furnished to do so, subject to 13 the following conditions: 14 15 The above copyright notice and this permission notice shall be included 16 in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 ----------------------------------------------------------------------- */ 27 28 #include <ffi.h> 29 #include <ffi_common.h> 30 #include <stdlib.h> 31 #include "internal.h" 32 33 #ifndef SPARC64 34 35 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; 36 all further uses in this file will refer to the 128-bit type. */ 37 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE 38 # if FFI_TYPE_LONGDOUBLE != 4 39 # error FFI_TYPE_LONGDOUBLE out of date 40 # endif 41 #else 42 # undef FFI_TYPE_LONGDOUBLE 43 # define FFI_TYPE_LONGDOUBLE 4 44 #endif 45 46 /* Perform machine dependent cif processing */ 47 ffi_status FFI_HIDDEN 48 ffi_prep_cif_machdep(ffi_cif *cif) 49 { 50 ffi_type *rtype = cif->rtype; 51 int rtt = rtype->type; 52 size_t bytes; 53 int i, n, flags; 54 55 /* Set the return type flag */ 56 switch (rtt) 57 { 58 case FFI_TYPE_VOID: 59 flags = SPARC_RET_VOID; 60 break; 61 case FFI_TYPE_FLOAT: 62 flags = SPARC_RET_F_1; 63 break; 64 case FFI_TYPE_DOUBLE: 65 flags = SPARC_RET_F_2; 66 break; 67 case FFI_TYPE_LONGDOUBLE: 68 case FFI_TYPE_STRUCT: 69 flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT; 70 flags |= SPARC_RET_STRUCT; 71 break; 72 case FFI_TYPE_SINT8: 73 flags = SPARC_RET_SINT8; 74 break; 75 case FFI_TYPE_UINT8: 76 flags = SPARC_RET_UINT8; 77 break; 78 case FFI_TYPE_SINT16: 79 flags = SPARC_RET_SINT16; 80 break; 81 case FFI_TYPE_UINT16: 82 flags = SPARC_RET_UINT16; 83 break; 84 case FFI_TYPE_INT: 85 case FFI_TYPE_SINT32: 86 case FFI_TYPE_UINT32: 87 case FFI_TYPE_POINTER: 88 flags = SPARC_RET_UINT32; 89 break; 90 case FFI_TYPE_SINT64: 91 case FFI_TYPE_UINT64: 92 flags = SPARC_RET_INT64; 93 break; 94 case FFI_TYPE_COMPLEX: 95 rtt = rtype->elements[0]->type; 96 switch (rtt) 97 { 98 case FFI_TYPE_FLOAT: 99 flags = SPARC_RET_F_2; 100 break; 101 case FFI_TYPE_DOUBLE: 102 flags = SPARC_RET_F_4; 103 break; 104 case FFI_TYPE_LONGDOUBLE: 105 flags = SPARC_RET_F_8; 106 break; 107 case FFI_TYPE_SINT64: 108 case FFI_TYPE_UINT64: 109 flags = SPARC_RET_INT128; 110 break; 111 case FFI_TYPE_INT: 112 case FFI_TYPE_SINT32: 113 case FFI_TYPE_UINT32: 114 flags = SPARC_RET_INT64; 115 break; 116 case FFI_TYPE_SINT16: 117 case FFI_TYPE_UINT16: 118 flags = SP_V8_RET_CPLX16; 119 break; 120 case FFI_TYPE_SINT8: 121 case FFI_TYPE_UINT8: 122 flags = SP_V8_RET_CPLX8; 123 break; 124 default: 125 abort(); 126 } 127 break; 128 default: 129 abort(); 130 } 131 cif->flags = flags; 132 133 bytes = 0; 134 for (i = 0, n = cif->nargs; i < n; ++i) 135 { 136 ffi_type *ty = cif->arg_types[i]; 137 size_t z = ty->size; 138 int tt = ty->type; 139 140 switch (tt) 141 { 142 case FFI_TYPE_STRUCT: 143 case FFI_TYPE_LONGDOUBLE: 144 by_reference: 145 /* Passed by reference. */ 146 z = 4; 147 break; 148 149 case FFI_TYPE_COMPLEX: 150 tt = ty->elements[0]->type; 151 if (tt == FFI_TYPE_FLOAT || z > 8) 152 goto by_reference; 153 /* FALLTHRU */ 154 155 default: 156 z = ALIGN(z, 4); 157 } 158 bytes += z; 159 } 160 161 /* Sparc call frames require that space is allocated for 6 args, 162 even if they aren't used. Make that space if necessary. */ 163 if (bytes < 6 * 4) 164 bytes = 6 * 4; 165 166 /* The ABI always requires space for the struct return pointer. */ 167 bytes += 4; 168 169 /* The stack must be 2 word aligned, so round bytes up appropriately. */ 170 bytes = ALIGN(bytes, 2 * 4); 171 172 /* Include the call frame to prep_args. */ 173 bytes += 4*16 + 4*8; 174 cif->bytes = bytes; 175 176 return FFI_OK; 177 } 178 179 extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue, 180 void **avalue, size_t bytes, void *closure) FFI_HIDDEN; 181 182 int FFI_HIDDEN 183 ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue) 184 { 185 ffi_type **p_arg; 186 int flags = cif->flags; 187 int i, nargs; 188 189 if (rvalue == NULL) 190 { 191 if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT) 192 { 193 /* Since we pass the pointer to the callee, we need a value. 194 We allowed for this space in ffi_call, before ffi_call_v8 195 alloca'd the space. */ 196 rvalue = (char *)argp + cif->bytes; 197 } 198 else 199 { 200 /* Otherwise, we can ignore the return value. */ 201 flags = SPARC_RET_VOID; 202 } 203 } 204 205 /* This could only really be done when we are returning a structure. 206 However, the space is reserved so we can do it unconditionally. */ 207 *argp++ = (unsigned long)rvalue; 208 209 #ifdef USING_PURIFY 210 /* Purify will probably complain in our assembly routine, 211 unless we zero out this memory. */ 212 memset(argp, 0, 6*4); 213 #endif 214 215 p_arg = cif->arg_types; 216 for (i = 0, nargs = cif->nargs; i < nargs; i++) 217 { 218 ffi_type *ty = p_arg[i]; 219 void *a = avalue[i]; 220 int tt = ty->type; 221 size_t z; 222 223 switch (tt) 224 { 225 case FFI_TYPE_STRUCT: 226 case FFI_TYPE_LONGDOUBLE: 227 by_reference: 228 *argp++ = (unsigned long)a; 229 break; 230 231 case FFI_TYPE_DOUBLE: 232 case FFI_TYPE_UINT64: 233 case FFI_TYPE_SINT64: 234 memcpy(argp, a, 8); 235 argp += 2; 236 break; 237 238 case FFI_TYPE_INT: 239 case FFI_TYPE_FLOAT: 240 case FFI_TYPE_UINT32: 241 case FFI_TYPE_SINT32: 242 case FFI_TYPE_POINTER: 243 *argp++ = *(unsigned *)a; 244 break; 245 246 case FFI_TYPE_UINT8: 247 *argp++ = *(UINT8 *)a; 248 break; 249 case FFI_TYPE_SINT8: 250 *argp++ = *(SINT8 *)a; 251 break; 252 case FFI_TYPE_UINT16: 253 *argp++ = *(UINT16 *)a; 254 break; 255 case FFI_TYPE_SINT16: 256 *argp++ = *(SINT16 *)a; 257 break; 258 259 case FFI_TYPE_COMPLEX: 260 tt = ty->elements[0]->type; 261 z = ty->size; 262 if (tt == FFI_TYPE_FLOAT || z > 8) 263 goto by_reference; 264 if (z < 4) 265 { 266 memcpy((char *)argp + 4 - z, a, z); 267 argp++; 268 } 269 else 270 { 271 memcpy(argp, a, z); 272 argp += z / 4; 273 } 274 break; 275 276 default: 277 abort(); 278 } 279 } 280 281 return flags; 282 } 283 284 static void 285 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, 286 void **avalue, void *closure) 287 { 288 size_t bytes = cif->bytes; 289 290 FFI_ASSERT (cif->abi == FFI_V8); 291 292 /* If we've not got a return value, we need to create one if we've 293 got to pass the return value to the callee. Otherwise ignore it. */ 294 if (rvalue == NULL 295 && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT) 296 bytes += ALIGN (cif->rtype->size, 8); 297 298 ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure); 299 } 300 301 void 302 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) 303 { 304 ffi_call_int (cif, fn, rvalue, avalue, NULL); 305 } 306 307 void 308 ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, 309 void **avalue, void *closure) 310 { 311 ffi_call_int (cif, fn, rvalue, avalue, closure); 312 } 313 314 #ifdef __GNUC__ 315 static inline void 316 ffi_flush_icache (void *p) 317 { 318 /* SPARC v8 requires 5 instructions for flush to be visible */ 319 asm volatile ("iflush %0; iflush %0+8; nop; nop; nop; nop; nop" 320 : : "r" (p) : "memory"); 321 } 322 #else 323 extern void ffi_flush_icache (void *) FFI_HIDDEN; 324 #endif 325 326 extern void ffi_closure_v8(void) FFI_HIDDEN; 327 extern void ffi_go_closure_v8(void) FFI_HIDDEN; 328 329 ffi_status 330 ffi_prep_closure_loc (ffi_closure *closure, 331 ffi_cif *cif, 332 void (*fun)(ffi_cif*, void*, void**, void*), 333 void *user_data, 334 void *codeloc) 335 { 336 unsigned int *tramp = (unsigned int *) &closure->tramp[0]; 337 unsigned long ctx = (unsigned long) closure; 338 unsigned long fn = (unsigned long) ffi_closure_v8; 339 340 if (cif->abi != FFI_V8) 341 return FFI_BAD_ABI; 342 343 tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */ 344 tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */ 345 tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */ 346 tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */ 347 348 closure->cif = cif; 349 closure->fun = fun; 350 closure->user_data = user_data; 351 352 ffi_flush_icache (closure); 353 354 return FFI_OK; 355 } 356 357 ffi_status 358 ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, 359 void (*fun)(ffi_cif*, void*, void**, void*)) 360 { 361 if (cif->abi != FFI_V8) 362 return FFI_BAD_ABI; 363 364 closure->tramp = ffi_go_closure_v8; 365 closure->cif = cif; 366 closure->fun = fun; 367 368 return FFI_OK; 369 } 370 371 int FFI_HIDDEN 372 ffi_closure_sparc_inner_v8(ffi_cif *cif, 373 void (*fun)(ffi_cif*, void*, void**, void*), 374 void *user_data, void *rvalue, 375 unsigned long *argp) 376 { 377 ffi_type **arg_types; 378 void **avalue; 379 int i, nargs, flags; 380 381 arg_types = cif->arg_types; 382 nargs = cif->nargs; 383 flags = cif->flags; 384 avalue = alloca(nargs * sizeof(void *)); 385 386 /* Copy the caller's structure return address so that the closure 387 returns the data directly to the caller. Also install it so we 388 can return the address in %o0. */ 389 if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT) 390 { 391 void *new_rvalue = (void *)*argp; 392 *(void **)rvalue = new_rvalue; 393 rvalue = new_rvalue; 394 } 395 396 /* Always skip the structure return address. */ 397 argp++; 398 399 /* Grab the addresses of the arguments from the stack frame. */ 400 for (i = 0; i < nargs; i++) 401 { 402 ffi_type *ty = arg_types[i]; 403 int tt = ty->type; 404 void *a = argp; 405 size_t z; 406 407 switch (tt) 408 { 409 case FFI_TYPE_STRUCT: 410 case FFI_TYPE_LONGDOUBLE: 411 by_reference: 412 /* Straight copy of invisible reference. */ 413 a = (void *)*argp; 414 break; 415 416 case FFI_TYPE_DOUBLE: 417 case FFI_TYPE_SINT64: 418 case FFI_TYPE_UINT64: 419 if ((unsigned long)a & 7) 420 { 421 /* Align on a 8-byte boundary. */ 422 UINT64 *tmp = alloca(8); 423 *tmp = ((UINT64)argp[0] << 32) | argp[1]; 424 a = tmp; 425 } 426 argp++; 427 break; 428 429 case FFI_TYPE_INT: 430 case FFI_TYPE_FLOAT: 431 case FFI_TYPE_UINT32: 432 case FFI_TYPE_SINT32: 433 case FFI_TYPE_POINTER: 434 break; 435 case FFI_TYPE_UINT16: 436 case FFI_TYPE_SINT16: 437 a += 2; 438 break; 439 case FFI_TYPE_UINT8: 440 case FFI_TYPE_SINT8: 441 a += 3; 442 break; 443 444 case FFI_TYPE_COMPLEX: 445 tt = ty->elements[0]->type; 446 z = ty->size; 447 if (tt == FFI_TYPE_FLOAT || z > 8) 448 goto by_reference; 449 if (z < 4) 450 a += 4 - z; 451 else if (z > 4) 452 argp++; 453 break; 454 455 default: 456 abort(); 457 } 458 argp++; 459 avalue[i] = a; 460 } 461 462 /* Invoke the closure. */ 463 fun (cif, rvalue, avalue, user_data); 464 465 /* Tell ffi_closure_sparc how to perform return type promotions. */ 466 return flags; 467 } 468 #endif /* !SPARC64 */