github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/alpha/ffi.c (about) 1 /* ----------------------------------------------------------------------- 2 ffi.c - Copyright (c) 2012 Anthony Green 3 Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc. 4 5 Alpha 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 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; 34 all further uses in this file will refer to the 128-bit type. */ 35 #if defined(__LONG_DOUBLE_128__) 36 # if FFI_TYPE_LONGDOUBLE != 4 37 # error FFI_TYPE_LONGDOUBLE out of date 38 # endif 39 #else 40 # undef FFI_TYPE_LONGDOUBLE 41 # define FFI_TYPE_LONGDOUBLE 4 42 #endif 43 44 extern void ffi_call_osf(void *stack, void *frame, unsigned flags, 45 void *raddr, void (*fn)(void), void *closure) 46 FFI_HIDDEN; 47 extern void ffi_closure_osf(void) FFI_HIDDEN; 48 extern void ffi_go_closure_osf(void) FFI_HIDDEN; 49 50 /* Promote a float value to its in-register double representation. 51 Unlike actually casting to double, this does not trap on NaN. */ 52 static inline UINT64 lds(void *ptr) 53 { 54 UINT64 ret; 55 asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr)); 56 return ret; 57 } 58 59 /* And the reverse. */ 60 static inline void sts(void *ptr, UINT64 val) 61 { 62 asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val)); 63 } 64 65 ffi_status FFI_HIDDEN 66 ffi_prep_cif_machdep(ffi_cif *cif) 67 { 68 size_t bytes = 0; 69 int flags, i, avn; 70 ffi_type *rtype, *itype; 71 72 if (cif->abi != FFI_OSF) 73 return FFI_BAD_ABI; 74 75 /* Compute the size of the argument area. */ 76 for (i = 0, avn = cif->nargs; i < avn; i++) 77 { 78 itype = cif->arg_types[i]; 79 switch (itype->type) 80 { 81 case FFI_TYPE_INT: 82 case FFI_TYPE_SINT8: 83 case FFI_TYPE_UINT8: 84 case FFI_TYPE_SINT16: 85 case FFI_TYPE_UINT16: 86 case FFI_TYPE_SINT32: 87 case FFI_TYPE_UINT32: 88 case FFI_TYPE_SINT64: 89 case FFI_TYPE_UINT64: 90 case FFI_TYPE_POINTER: 91 case FFI_TYPE_FLOAT: 92 case FFI_TYPE_DOUBLE: 93 case FFI_TYPE_LONGDOUBLE: 94 /* All take one 8 byte slot. */ 95 bytes += 8; 96 break; 97 98 case FFI_TYPE_VOID: 99 case FFI_TYPE_STRUCT: 100 /* Passed by value in N slots. */ 101 bytes += ALIGN(itype->size, FFI_SIZEOF_ARG); 102 break; 103 104 case FFI_TYPE_COMPLEX: 105 /* _Complex long double passed by reference; others in 2 slots. */ 106 if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE) 107 bytes += 8; 108 else 109 bytes += 16; 110 break; 111 112 default: 113 abort(); 114 } 115 } 116 117 /* Set the return type flag */ 118 rtype = cif->rtype; 119 switch (rtype->type) 120 { 121 case FFI_TYPE_VOID: 122 flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID); 123 break; 124 case FFI_TYPE_INT: 125 case FFI_TYPE_UINT32: 126 case FFI_TYPE_SINT32: 127 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32); 128 break; 129 case FFI_TYPE_FLOAT: 130 flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT); 131 break; 132 case FFI_TYPE_DOUBLE: 133 flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE); 134 break; 135 case FFI_TYPE_UINT8: 136 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8); 137 break; 138 case FFI_TYPE_SINT8: 139 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8); 140 break; 141 case FFI_TYPE_UINT16: 142 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16); 143 break; 144 case FFI_TYPE_SINT16: 145 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16); 146 break; 147 case FFI_TYPE_UINT64: 148 case FFI_TYPE_SINT64: 149 case FFI_TYPE_POINTER: 150 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64); 151 break; 152 case FFI_TYPE_LONGDOUBLE: 153 case FFI_TYPE_STRUCT: 154 /* Passed in memory, with a hidden pointer. */ 155 flags = ALPHA_RET_IN_MEM; 156 break; 157 case FFI_TYPE_COMPLEX: 158 itype = rtype->elements[0]; 159 switch (itype->type) 160 { 161 case FFI_TYPE_FLOAT: 162 flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF); 163 break; 164 case FFI_TYPE_DOUBLE: 165 flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD); 166 break; 167 default: 168 if (rtype->size <= 8) 169 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64); 170 else 171 flags = ALPHA_RET_IN_MEM; 172 break; 173 } 174 break; 175 default: 176 abort(); 177 } 178 cif->flags = flags; 179 180 /* Include the hidden structure pointer in args requirement. */ 181 if (flags == ALPHA_RET_IN_MEM) 182 bytes += 8; 183 /* Minimum size is 6 slots, so that ffi_call_osf can pop them. */ 184 if (bytes < 6*8) 185 bytes = 6*8; 186 cif->bytes = bytes; 187 188 return FFI_OK; 189 } 190 191 static unsigned long 192 extend_basic_type(void *valp, int type, int argn) 193 { 194 switch (type) 195 { 196 case FFI_TYPE_SINT8: 197 return *(SINT8 *)valp; 198 case FFI_TYPE_UINT8: 199 return *(UINT8 *)valp; 200 case FFI_TYPE_SINT16: 201 return *(SINT16 *)valp; 202 case FFI_TYPE_UINT16: 203 return *(UINT16 *)valp; 204 205 case FFI_TYPE_FLOAT: 206 if (argn < 6) 207 return lds(valp); 208 /* FALLTHRU */ 209 210 case FFI_TYPE_INT: 211 case FFI_TYPE_SINT32: 212 case FFI_TYPE_UINT32: 213 /* Note that unsigned 32-bit quantities are sign extended. */ 214 return *(SINT32 *)valp; 215 216 case FFI_TYPE_SINT64: 217 case FFI_TYPE_UINT64: 218 case FFI_TYPE_POINTER: 219 case FFI_TYPE_DOUBLE: 220 return *(UINT64 *)valp; 221 222 default: 223 abort(); 224 } 225 } 226 227 static void 228 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, 229 void **avalue, void *closure) 230 { 231 unsigned long *argp; 232 long i, avn, argn, flags = cif->flags; 233 ffi_type **arg_types; 234 void *frame; 235 236 /* If the return value is a struct and we don't have a return 237 value address then we need to make one. */ 238 if (rvalue == NULL && flags == ALPHA_RET_IN_MEM) 239 rvalue = alloca(cif->rtype->size); 240 241 /* Allocate the space for the arguments, plus 4 words of temp 242 space for ffi_call_osf. */ 243 argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); 244 frame += cif->bytes; 245 246 argn = 0; 247 if (flags == ALPHA_RET_IN_MEM) 248 argp[argn++] = (unsigned long)rvalue; 249 250 avn = cif->nargs; 251 arg_types = cif->arg_types; 252 253 for (i = 0, avn = cif->nargs; i < avn; i++) 254 { 255 ffi_type *ty = arg_types[i]; 256 void *valp = avalue[i]; 257 int type = ty->type; 258 size_t size; 259 260 switch (type) 261 { 262 case FFI_TYPE_INT: 263 case FFI_TYPE_SINT8: 264 case FFI_TYPE_UINT8: 265 case FFI_TYPE_SINT16: 266 case FFI_TYPE_UINT16: 267 case FFI_TYPE_SINT32: 268 case FFI_TYPE_UINT32: 269 case FFI_TYPE_SINT64: 270 case FFI_TYPE_UINT64: 271 case FFI_TYPE_POINTER: 272 case FFI_TYPE_FLOAT: 273 case FFI_TYPE_DOUBLE: 274 argp[argn] = extend_basic_type(valp, type, argn); 275 argn++; 276 break; 277 278 case FFI_TYPE_LONGDOUBLE: 279 by_reference: 280 /* Note that 128-bit long double is passed by reference. */ 281 argp[argn++] = (unsigned long)valp; 282 break; 283 284 case FFI_TYPE_VOID: 285 case FFI_TYPE_STRUCT: 286 size = ty->size; 287 memcpy(argp + argn, valp, size); 288 argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; 289 break; 290 291 case FFI_TYPE_COMPLEX: 292 type = ty->elements[0]->type; 293 if (type == FFI_TYPE_LONGDOUBLE) 294 goto by_reference; 295 296 /* Most complex types passed as two separate arguments. */ 297 size = ty->elements[0]->size; 298 argp[argn] = extend_basic_type(valp, type, argn); 299 argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1); 300 argn += 2; 301 break; 302 303 default: 304 abort(); 305 } 306 } 307 308 flags = (flags >> ALPHA_ST_SHIFT) & 0xff; 309 ffi_call_osf(argp, frame, flags, rvalue, fn, closure); 310 } 311 312 void 313 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) 314 { 315 ffi_call_int(cif, fn, rvalue, avalue, NULL); 316 } 317 318 void 319 ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, 320 void **avalue, void *closure) 321 { 322 ffi_call_int(cif, fn, rvalue, avalue, closure); 323 } 324 325 ffi_status 326 ffi_prep_closure_loc (ffi_closure* closure, 327 ffi_cif* cif, 328 void (*fun)(ffi_cif*, void*, void**, void*), 329 void *user_data, 330 void *codeloc) 331 { 332 unsigned int *tramp; 333 334 if (cif->abi != FFI_OSF) 335 return FFI_BAD_ABI; 336 337 tramp = (unsigned int *) &closure->tramp[0]; 338 tramp[0] = 0x47fb0401; /* mov $27,$1 */ 339 tramp[1] = 0xa77b0010; /* ldq $27,16($27) */ 340 tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */ 341 tramp[3] = 0x47ff041f; /* nop */ 342 *(void **) &tramp[4] = ffi_closure_osf; 343 344 closure->cif = cif; 345 closure->fun = fun; 346 closure->user_data = user_data; 347 348 /* Flush the Icache. 349 350 Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal 351 instead, since both Compaq as and gas can handle it. 352 353 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */ 354 asm volatile ("call_pal 0x86" : : : "memory"); 355 356 return FFI_OK; 357 } 358 359 ffi_status 360 ffi_prep_go_closure (ffi_go_closure* closure, 361 ffi_cif* cif, 362 void (*fun)(ffi_cif*, void*, void**, void*)) 363 { 364 if (cif->abi != FFI_OSF) 365 return FFI_BAD_ABI; 366 367 closure->tramp = (void *)ffi_go_closure_osf; 368 closure->cif = cif; 369 closure->fun = fun; 370 371 return FFI_OK; 372 } 373 374 long FFI_HIDDEN 375 ffi_closure_osf_inner (ffi_cif *cif, 376 void (*fun)(ffi_cif*, void*, void**, void*), 377 void *user_data, 378 void *rvalue, unsigned long *argp) 379 { 380 void **avalue; 381 ffi_type **arg_types; 382 long i, avn, argn, flags; 383 384 avalue = alloca(cif->nargs * sizeof(void *)); 385 flags = cif->flags; 386 argn = 0; 387 388 /* Copy the caller's structure return address to that the closure 389 returns the data directly to the caller. */ 390 if (flags == ALPHA_RET_IN_MEM) 391 { 392 rvalue = (void *) argp[0]; 393 argn = 1; 394 } 395 396 arg_types = cif->arg_types; 397 398 /* Grab the addresses of the arguments from the stack frame. */ 399 for (i = 0, avn = cif->nargs; i < avn; i++) 400 { 401 ffi_type *ty = arg_types[i]; 402 int type = ty->type; 403 void *valp = &argp[argn]; 404 size_t size; 405 406 switch (type) 407 { 408 case FFI_TYPE_INT: 409 case FFI_TYPE_SINT8: 410 case FFI_TYPE_UINT8: 411 case FFI_TYPE_SINT16: 412 case FFI_TYPE_UINT16: 413 case FFI_TYPE_SINT32: 414 case FFI_TYPE_UINT32: 415 case FFI_TYPE_SINT64: 416 case FFI_TYPE_UINT64: 417 case FFI_TYPE_POINTER: 418 argn += 1; 419 break; 420 421 case FFI_TYPE_VOID: 422 case FFI_TYPE_STRUCT: 423 size = ty->size; 424 argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; 425 break; 426 427 case FFI_TYPE_FLOAT: 428 /* Floats coming from registers need conversion from double 429 back to float format. */ 430 if (argn < 6) 431 { 432 valp = &argp[argn - 6]; 433 sts(valp, argp[argn - 6]); 434 } 435 argn += 1; 436 break; 437 438 case FFI_TYPE_DOUBLE: 439 if (argn < 6) 440 valp = &argp[argn - 6]; 441 argn += 1; 442 break; 443 444 case FFI_TYPE_LONGDOUBLE: 445 by_reference: 446 /* 128-bit long double is passed by reference. */ 447 valp = (void *)argp[argn]; 448 argn += 1; 449 break; 450 451 case FFI_TYPE_COMPLEX: 452 type = ty->elements[0]->type; 453 switch (type) 454 { 455 case FFI_TYPE_SINT64: 456 case FFI_TYPE_UINT64: 457 /* Passed as separate arguments, but they wind up sequential. */ 458 break; 459 460 case FFI_TYPE_INT: 461 case FFI_TYPE_SINT8: 462 case FFI_TYPE_UINT8: 463 case FFI_TYPE_SINT16: 464 case FFI_TYPE_UINT16: 465 case FFI_TYPE_SINT32: 466 case FFI_TYPE_UINT32: 467 /* Passed as separate arguments. Disjoint, but there's room 468 enough in one slot to hold the pair. */ 469 size = ty->elements[0]->size; 470 memcpy(valp + size, valp + 8, size); 471 break; 472 473 case FFI_TYPE_FLOAT: 474 /* Passed as separate arguments. Disjoint, and each piece 475 may need conversion back to float. */ 476 if (argn < 6) 477 { 478 valp = &argp[argn - 6]; 479 sts(valp, argp[argn - 6]); 480 } 481 if (argn + 1 < 6) 482 sts(valp + 4, argp[argn + 1 - 6]); 483 else 484 *(UINT32 *)(valp + 4) = argp[argn + 1]; 485 break; 486 487 case FFI_TYPE_DOUBLE: 488 /* Passed as separate arguments. Only disjoint if one part 489 is in fp regs and the other is on the stack. */ 490 if (argn < 5) 491 valp = &argp[argn - 6]; 492 else if (argn == 5) 493 { 494 valp = alloca(16); 495 ((UINT64 *)valp)[0] = argp[5 - 6]; 496 ((UINT64 *)valp)[1] = argp[6]; 497 } 498 break; 499 500 case FFI_TYPE_LONGDOUBLE: 501 goto by_reference; 502 503 default: 504 abort(); 505 } 506 argn += 2; 507 break; 508 509 default: 510 abort (); 511 } 512 513 avalue[i] = valp; 514 } 515 516 /* Invoke the closure. */ 517 fun (cif, rvalue, avalue, user_data); 518 519 /* Tell ffi_closure_osf how to perform return type promotions. */ 520 return (flags >> ALPHA_LD_SHIFT) & 0xff; 521 }