1 /* ----------------------------------------------------------------------- 2 ffi.c - Copyright (c) 1998, 2007, 2008 Red Hat, Inc. 3 Copyright (c) 2000 Hewlett Packard Company 4 5 IA64 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 31 #include <stdlib.h> 32 #include <stdbool.h> 33 #include <float.h> 34 35 #include "ia64_flags.h" 36 37 /* A 64-bit pointer value. In LP64 mode, this is effectively a plain 38 pointer. In ILP32 mode, it's a pointer that's been extended to 39 64 bits by "addp4". */ 40 typedef void *PTR64 __attribute__((mode(DI))); 41 42 /* Memory image of fp register contents. This is the implementation 43 specific format used by ldf.fill/stf.spill. All we care about is 44 that it wants a 16 byte aligned slot. */ 45 typedef struct 46 { 47 UINT64 x[2] __attribute__((aligned(16))); 48 } fpreg; 49 50 51 /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */ 52 53 struct ia64_args 54 { 55 fpreg fp_regs[8]; /* Contents of 8 fp arg registers. */ 56 UINT64 gp_regs[8]; /* Contents of 8 gp arg registers. */ 57 UINT64 other_args[]; /* Arguments passed on stack, variable size. */ 58 }; 59 60 61 /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */ 62 63 static inline void * 64 endian_adjust (void *addr, size_t len) 65 { 66 #ifdef __BIG_ENDIAN__ 67 return addr + (8 - len); 68 #else 69 return addr; 70 #endif 71 } 72 73 /* Store VALUE to ADDR in the current cpu implementation's fp spill format. 74 This is a macro instead of a function, so that it works for all 3 floating 75 point types without type conversions. Type conversion to long double breaks 76 the denorm support. */ 77 78 #define stf_spill(addr, value) \ 79 asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value)); 80 81 /* Load a value from ADDR, which is in the current cpu implementation's 82 fp spill format. As above, this must also be a macro. */ 83 84 #define ldf_fill(result, addr) \ 85 asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr)); 86 87 /* Return the size of the C type associated with with TYPE. Which will 88 be one of the FFI_IA64_TYPE_HFA_* values. */ 89 90 static size_t 91 hfa_type_size (int type) 92 { 93 switch (type) 94 { 95 case FFI_IA64_TYPE_HFA_FLOAT: 96 return sizeof(float); 97 case FFI_IA64_TYPE_HFA_DOUBLE: 98 return sizeof(double); 99 case FFI_IA64_TYPE_HFA_LDOUBLE: 100 return sizeof(__float80); 101 default: 102 abort (); 103 } 104 } 105 106 /* Load from ADDR a value indicated by TYPE. Which will be one of 107 the FFI_IA64_TYPE_HFA_* values. */ 108 109 static void 110 hfa_type_load (fpreg *fpaddr, int type, void *addr) 111 { 112 switch (type) 113 { 114 case FFI_IA64_TYPE_HFA_FLOAT: 115 stf_spill (fpaddr, *(float *) addr); 116 return; 117 case FFI_IA64_TYPE_HFA_DOUBLE: 118 stf_spill (fpaddr, *(double *) addr); 119 return; 120 case FFI_IA64_TYPE_HFA_LDOUBLE: 121 stf_spill (fpaddr, *(__float80 *) addr); 122 return; 123 default: 124 abort (); 125 } 126 } 127 128 /* Load VALUE into ADDR as indicated by TYPE. Which will be one of 129 the FFI_IA64_TYPE_HFA_* values. */ 130 131 static void 132 hfa_type_store (int type, void *addr, fpreg *fpaddr) 133 { 134 switch (type) 135 { 136 case FFI_IA64_TYPE_HFA_FLOAT: 137 { 138 float result; 139 ldf_fill (result, fpaddr); 140 *(float *) addr = result; 141 break; 142 } 143 case FFI_IA64_TYPE_HFA_DOUBLE: 144 { 145 double result; 146 ldf_fill (result, fpaddr); 147 *(double *) addr = result; 148 break; 149 } 150 case FFI_IA64_TYPE_HFA_LDOUBLE: 151 { 152 __float80 result; 153 ldf_fill (result, fpaddr); 154 *(__float80 *) addr = result; 155 break; 156 } 157 default: 158 abort (); 159 } 160 } 161 162 /* Is TYPE a struct containing floats, doubles, or extended doubles, 163 all of the same fp type? If so, return the element type. Return 164 FFI_TYPE_VOID if not. */ 165 166 static int 167 hfa_element_type (ffi_type *type, int nested) 168 { 169 int element = FFI_TYPE_VOID; 170 171 switch (type->type) 172 { 173 case FFI_TYPE_FLOAT: 174 /* We want to return VOID for raw floating-point types, but the 175 synthetic HFA type if we're nested within an aggregate. */ 176 if (nested) 177 element = FFI_IA64_TYPE_HFA_FLOAT; 178 break; 179 180 case FFI_TYPE_DOUBLE: 181 /* Similarly. */ 182 if (nested) 183 element = FFI_IA64_TYPE_HFA_DOUBLE; 184 break; 185 186 case FFI_TYPE_LONGDOUBLE: 187 /* Similarly, except that that HFA is true for double extended, 188 but not quad precision. Both have sizeof == 16, so tell the 189 difference based on the precision. */ 190 if (LDBL_MANT_DIG == 64 && nested) 191 element = FFI_IA64_TYPE_HFA_LDOUBLE; 192 break; 193 194 case FFI_TYPE_STRUCT: 195 { 196 ffi_type **ptr = &type->elements[0]; 197 198 for (ptr = &type->elements[0]; *ptr ; ptr++) 199 { 200 int sub_element = hfa_element_type (*ptr, 1); 201 if (sub_element == FFI_TYPE_VOID) 202 return FFI_TYPE_VOID; 203 204 if (element == FFI_TYPE_VOID) 205 element = sub_element; 206 else if (element != sub_element) 207 return FFI_TYPE_VOID; 208 } 209 } 210 break; 211 212 default: 213 return FFI_TYPE_VOID; 214 } 215 216 return element; 217 } 218 219 220 /* Perform machine dependent cif processing. */ 221 222 ffi_status 223 ffi_prep_cif_machdep(ffi_cif *cif) 224 { 225 int flags; 226 227 /* Adjust cif->bytes to include space for the bits of the ia64_args frame 228 that preceeds the integer register portion. The estimate that the 229 generic bits did for the argument space required is good enough for the 230 integer component. */ 231 cif->bytes += offsetof(struct ia64_args, gp_regs[0]); 232 if (cif->bytes < sizeof(struct ia64_args)) 233 cif->bytes = sizeof(struct ia64_args); 234 235 /* Set the return type flag. */ 236 flags = cif->rtype->type; 237 switch (cif->rtype->type) 238 { 239 case FFI_TYPE_LONGDOUBLE: 240 /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision, 241 and encode quad precision as a two-word integer structure. */ 242 if (LDBL_MANT_DIG != 64) 243 flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8); 244 break; 245 246 case FFI_TYPE_STRUCT: 247 { 248 size_t size = cif->rtype->size; 249 int hfa_type = hfa_element_type (cif->rtype, 0); 250 251 if (hfa_type != FFI_TYPE_VOID) 252 { 253 size_t nelts = size / hfa_type_size (hfa_type); 254 if (nelts <= 8) 255 flags = hfa_type | (size << 8); 256 } 257 else 258 { 259 if (size <= 32) 260 flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8); 261 } 262 } 263 break; 264 265 default: 266 break; 267 } 268 cif->flags = flags; 269 270 return FFI_OK; 271 } 272 273 extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64); 274 275 void 276 ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) 277 { 278 struct ia64_args *stack; 279 long i, avn, gpcount, fpcount; 280 ffi_type **p_arg; 281 282 FFI_ASSERT (cif->abi == FFI_UNIX); 283 284 /* If we have no spot for a return value, make one. */ 285 if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID) 286 rvalue = alloca (cif->rtype->size); 287 288 /* Allocate the stack frame. */ 289 stack = alloca (cif->bytes); 290 291 gpcount = fpcount = 0; 292 avn = cif->nargs; 293 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) 294 { 295 switch ((*p_arg)->type) 296 { 297 case FFI_TYPE_SINT8: 298 stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i]; 299 break; 300 case FFI_TYPE_UINT8: 301 stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i]; 302 break; 303 case FFI_TYPE_SINT16: 304 stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i]; 305 break; 306 case FFI_TYPE_UINT16: 307 stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i]; 308 break; 309 case FFI_TYPE_SINT32: 310 stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i]; 311 break; 312 case FFI_TYPE_UINT32: 313 stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; 314 break; 315 case FFI_TYPE_SINT64: 316 case FFI_TYPE_UINT64: 317 stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; 318 break; 319 320 case FFI_TYPE_POINTER: 321 stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i]; 322 break; 323 324 case FFI_TYPE_FLOAT: 325 if (gpcount < 8 && fpcount < 8) 326 stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]); 327 stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; 328 break; 329 330 case FFI_TYPE_DOUBLE: 331 if (gpcount < 8 && fpcount < 8) 332 stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]); 333 stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; 334 break; 335 336 case FFI_TYPE_LONGDOUBLE: 337 if (gpcount & 1) 338 gpcount++; 339 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) 340 stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]); 341 memcpy (&stack->gp_regs[gpcount], avalue[i], 16); 342 gpcount += 2; 343 break; 344 345 case FFI_TYPE_STRUCT: 346 { 347 size_t size = (*p_arg)->size; 348 size_t align = (*p_arg)->alignment; 349 int hfa_type = hfa_element_type (*p_arg, 0); 350 351 FFI_ASSERT (align <= 16); 352 if (align == 16 && (gpcount & 1)) 353 gpcount++; 354 355 if (hfa_type != FFI_TYPE_VOID) 356 { 357 size_t hfa_size = hfa_type_size (hfa_type); 358 size_t offset = 0; 359 size_t gp_offset = gpcount * 8; 360 361 while (fpcount < 8 362 && offset < size 363 && gp_offset < 8 * 8) 364 { 365 hfa_type_load (&stack->fp_regs[fpcount], hfa_type, 366 avalue[i] + offset); 367 offset += hfa_size; 368 gp_offset += hfa_size; 369 fpcount += 1; 370 } 371 } 372 373 memcpy (&stack->gp_regs[gpcount], avalue[i], size); 374 gpcount += (size + 7) / 8; 375 } 376 break; 377 378 default: 379 abort (); 380 } 381 } 382 383 ffi_call_unix (stack, rvalue, fn, cif->flags); 384 } 385 386 /* Closures represent a pair consisting of a function pointer, and 387 some user data. A closure is invoked by reinterpreting the closure 388 as a function pointer, and branching to it. Thus we can make an 389 interpreted function callable as a C function: We turn the 390 interpreter itself, together with a pointer specifying the 391 interpreted procedure, into a closure. 392 393 For IA64, function pointer are already pairs consisting of a code 394 pointer, and a gp pointer. The latter is needed to access global 395 variables. Here we set up such a pair as the first two words of 396 the closure (in the "trampoline" area), but we replace the gp 397 pointer with a pointer to the closure itself. We also add the real 398 gp pointer to the closure. This allows the function entry code to 399 both retrieve the user data, and to restire the correct gp pointer. */ 400 401 extern void ffi_closure_unix (); 402 403 ffi_status 404 ffi_prep_closure_loc (ffi_closure* closure, 405 ffi_cif* cif, 406 void (*fun)(ffi_cif*,void*,void**,void*), 407 void *user_data, 408 void *codeloc) 409 { 410 /* The layout of a function descriptor. A C function pointer really 411 points to one of these. */ 412 struct ia64_fd 413 { 414 UINT64 code_pointer; 415 UINT64 gp; 416 }; 417 418 struct ffi_ia64_trampoline_struct 419 { 420 UINT64 code_pointer; /* Pointer to ffi_closure_unix. */ 421 UINT64 fake_gp; /* Pointer to closure, installed as gp. */ 422 UINT64 real_gp; /* Real gp value. */ 423 }; 424 425 struct ffi_ia64_trampoline_struct *tramp; 426 struct ia64_fd *fd; 427 428 FFI_ASSERT (cif->abi == FFI_UNIX); 429 430 tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp; 431 fd = (struct ia64_fd *)(void *)ffi_closure_unix; 432 433 tramp->code_pointer = fd->code_pointer; 434 tramp->real_gp = fd->gp; 435 tramp->fake_gp = (UINT64)(PTR64)codeloc; 436 closure->cif = cif; 437 closure->user_data = user_data; 438 closure->fun = fun; 439 440 return FFI_OK; 441 } 442 443 444 UINT64 445 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack, 446 void *rvalue, void *r8) 447 { 448 ffi_cif *cif; 449 void **avalue; 450 ffi_type **p_arg; 451 long i, avn, gpcount, fpcount; 452 453 cif = closure->cif; 454 avn = cif->nargs; 455 avalue = alloca (avn * sizeof (void *)); 456 457 /* If the structure return value is passed in memory get that location 458 from r8 so as to pass the value directly back to the caller. */ 459 if (cif->flags == FFI_TYPE_STRUCT) 460 rvalue = r8; 461 462 gpcount = fpcount = 0; 463 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) 464 { 465 switch ((*p_arg)->type) 466 { 467 case FFI_TYPE_SINT8: 468 case FFI_TYPE_UINT8: 469 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1); 470 break; 471 case FFI_TYPE_SINT16: 472 case FFI_TYPE_UINT16: 473 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2); 474 break; 475 case FFI_TYPE_SINT32: 476 case FFI_TYPE_UINT32: 477 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4); 478 break; 479 case FFI_TYPE_SINT64: 480 case FFI_TYPE_UINT64: 481 avalue[i] = &stack->gp_regs[gpcount++]; 482 break; 483 case FFI_TYPE_POINTER: 484 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*)); 485 break; 486 487 case FFI_TYPE_FLOAT: 488 if (gpcount < 8 && fpcount < 8) 489 { 490 fpreg *addr = &stack->fp_regs[fpcount++]; 491 float result; 492 avalue[i] = addr; 493 ldf_fill (result, addr); 494 *(float *)addr = result; 495 } 496 else 497 avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4); 498 gpcount++; 499 break; 500 501 case FFI_TYPE_DOUBLE: 502 if (gpcount < 8 && fpcount < 8) 503 { 504 fpreg *addr = &stack->fp_regs[fpcount++]; 505 double result; 506 avalue[i] = addr; 507 ldf_fill (result, addr); 508 *(double *)addr = result; 509 } 510 else 511 avalue[i] = &stack->gp_regs[gpcount]; 512 gpcount++; 513 break; 514 515 case FFI_TYPE_LONGDOUBLE: 516 if (gpcount & 1) 517 gpcount++; 518 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) 519 { 520 fpreg *addr = &stack->fp_regs[fpcount++]; 521 __float80 result; 522 avalue[i] = addr; 523 ldf_fill (result, addr); 524 *(__float80 *)addr = result; 525 } 526 else 527 avalue[i] = &stack->gp_regs[gpcount]; 528 gpcount += 2; 529 break; 530 531 case FFI_TYPE_STRUCT: 532 { 533 size_t size = (*p_arg)->size; 534 size_t align = (*p_arg)->alignment; 535 int hfa_type = hfa_element_type (*p_arg, 0); 536 537 FFI_ASSERT (align <= 16); 538 if (align == 16 && (gpcount & 1)) 539 gpcount++; 540 541 if (hfa_type != FFI_TYPE_VOID) 542 { 543 size_t hfa_size = hfa_type_size (hfa_type); 544 size_t offset = 0; 545 size_t gp_offset = gpcount * 8; 546 void *addr = alloca (size); 547 548 avalue[i] = addr; 549 550 while (fpcount < 8 551 && offset < size 552 && gp_offset < 8 * 8) 553 { 554 hfa_type_store (hfa_type, addr + offset, 555 &stack->fp_regs[fpcount]); 556 offset += hfa_size; 557 gp_offset += hfa_size; 558 fpcount += 1; 559 } 560 561 if (offset < size) 562 memcpy (addr + offset, (char *)stack->gp_regs + gp_offset, 563 size - offset); 564 } 565 else 566 avalue[i] = &stack->gp_regs[gpcount]; 567 568 gpcount += (size + 7) / 8; 569 } 570 break; 571 572 default: 573 abort (); 574 } 575 } 576 577 closure->fun (cif, rvalue, avalue, closure->user_data); 578 579 return cif->flags; 580 } 581