From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12071 invoked by alias); 30 Oct 2014 03:54:56 -0000 Mailing-List: contact libffi-discuss-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libffi-discuss-owner@sourceware.org Received: (qmail 11963 invoked by uid 89); 30 Oct 2014 03:54:55 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL,BAYES_00,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pa0-f51.google.com Received: from mail-pa0-f51.google.com (HELO mail-pa0-f51.google.com) (209.85.220.51) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Thu, 30 Oct 2014 03:54:51 +0000 Received: by mail-pa0-f51.google.com with SMTP id kq14so4536512pab.24 for ; Wed, 29 Oct 2014 20:54:49 -0700 (PDT) X-Received: by 10.68.100.197 with SMTP id fa5mr14846892pbb.22.1414641289636; Wed, 29 Oct 2014 20:54:49 -0700 (PDT) Received: from pike.twiddle.home (50-194-63-110-static.hfc.comcastbusiness.net. [50.194.63.110]) by mx.google.com with ESMTPSA id qh7sm5676184pab.48.2014.10.29.20.54.48 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Oct 2014 20:54:48 -0700 (PDT) From: Richard Henderson To: libffi-discuss@sourceware.org Subject: [PATCH 3/4] alpha: Add support for complex types Date: Thu, 30 Oct 2014 03:54:00 -0000 Message-Id: <1414641281-15172-4-git-send-email-rth@twiddle.net> In-Reply-To: <1414641281-15172-1-git-send-email-rth@twiddle.net> References: <1414641281-15172-1-git-send-email-rth@twiddle.net> X-SW-Source: 2014/txt/msg00177.txt.bz2 --- src/alpha/ffi.c | 278 +++++++++++++++++++++------ src/alpha/ffitarget.h | 3 + src/alpha/internal.h | 4 + src/alpha/osf.S | 18 ++ testsuite/libffi.call/call.exp | 10 +- testsuite/libffi.call/cls_complex_va_float.c | 6 + 6 files changed, 255 insertions(+), 64 deletions(-) diff --git a/src/alpha/ffi.c b/src/alpha/ffi.c index 2f9e7e5..1e5187e 100644 --- a/src/alpha/ffi.c +++ b/src/alpha/ffi.c @@ -1,8 +1,8 @@ /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2012 Anthony Green - Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc. - - Alpha Foreign Function Interface + Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc. + + Alpha Foreign Function Interface Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -60,18 +60,61 @@ static inline void sts(void *ptr, UINT64 val) asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val)); } -ffi_status +ffi_status FFI_HIDDEN ffi_prep_cif_machdep(ffi_cif *cif) { - int flags; + size_t bytes = 0; + int flags, i, avn; + ffi_type *rtype, *itype; + + if (cif->abi != FFI_OSF) + return FFI_BAD_ABI; + + /* Compute the size of the argument area. */ + for (i = 0, avn = cif->nargs; i < avn; i++) + { + itype = cif->arg_types[i]; + switch (itype->type) + { + case FFI_TYPE_INT: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + /* All take one 8 byte slot. */ + bytes += 8; + break; + + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + /* Passed by value in N slots. */ + bytes += ALIGN(itype->size, FFI_SIZEOF_ARG); + break; + + case FFI_TYPE_COMPLEX: + /* _Complex long double passed by reference; others in 2 slots. */ + if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE) + bytes += 8; + else + bytes += 16; + break; - /* Adjust cif->bytes to represent a minimum 6 words for the temporary - register argument loading area. */ - if (cif->bytes < 6*FFI_SIZEOF_ARG) - cif->bytes = 6*FFI_SIZEOF_ARG; + default: + abort(); + } + } /* Set the return type flag */ - switch (cif->rtype->type) + rtype = cif->rtype; + switch (rtype->type) { case FFI_TYPE_VOID: flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID); @@ -109,22 +152,83 @@ ffi_prep_cif_machdep(ffi_cif *cif) /* Passed in memory, with a hidden pointer. */ flags = ALPHA_RET_IN_MEM; break; + case FFI_TYPE_COMPLEX: + itype = rtype->elements[0]; + switch (itype->type) + { + case FFI_TYPE_FLOAT: + flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF); + break; + case FFI_TYPE_DOUBLE: + flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD); + break; + default: + if (rtype->size <= 8) + flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64); + else + flags = ALPHA_RET_IN_MEM; + break; + } + break; default: abort(); } cif->flags = flags; - + + /* Include the hidden structure pointer in args requirement. */ + if (flags == ALPHA_RET_IN_MEM) + bytes += 8; + /* Minimum size is 6 slots, so that ffi_call_osf can pop them. */ + if (bytes < 6*8) + bytes = 6*8; + cif->bytes = bytes; + return FFI_OK; } +static unsigned long +extend_basic_type(void *valp, int type, int argn) +{ + switch (type) + { + case FFI_TYPE_SINT8: + return *(SINT8 *)valp; + case FFI_TYPE_UINT8: + return *(UINT8 *)valp; + case FFI_TYPE_SINT16: + return *(SINT16 *)valp; + case FFI_TYPE_UINT16: + return *(UINT16 *)valp; + + case FFI_TYPE_FLOAT: + if (argn < 6) + return lds(valp); + /* FALLTHRU */ + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + /* Note that unsigned 32-bit quantities are sign extended. */ + return *(SINT32 *)valp; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + case FFI_TYPE_DOUBLE: + return *(UINT64 *)valp; + + default: + abort(); + } +} void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { - unsigned long *stack, *argp; - long i, avn, flags = cif->flags; + unsigned long *argp; + long i, avn, argn, flags = cif->flags; ffi_type **arg_types; - + /* If the return value is a struct and we don't have a return value address then we need to make one. */ if (rvalue == NULL && flags == ALPHA_RET_IN_MEM) @@ -132,12 +236,12 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) /* Allocate the space for the arguments, plus 4 words of temp space for ffi_call_osf. */ - argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); + argp = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); + argn = 0; if (flags == ALPHA_RET_IN_MEM) - *argp++ = (unsigned long)rvalue; + argp[argn++] = (unsigned long)rvalue; - i = 0; avn = cif->nargs; arg_types = cif->arg_types; @@ -145,67 +249,59 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { ffi_type *ty = arg_types[i]; void *valp = avalue[i]; - unsigned long val; + int type = ty->type; size_t size; - switch (ty->type) + switch (type) { + case FFI_TYPE_INT: case FFI_TYPE_SINT8: - val = *(SINT8 *)valp; - break; - case FFI_TYPE_UINT8: - val = *(UINT8 *)valp; - break; - case FFI_TYPE_SINT16: - val = *(SINT16 *)valp; - break; - case FFI_TYPE_UINT16: - val = *(UINT16 *)valp; - break; - case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: - /* Note that unsigned 32-bit quantities are sign extended. */ - val = *(SINT32 *)valp; - break; - case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: + case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: - val = *(UINT64 *)valp; + argp[argn] = extend_basic_type(valp, type, argn); + argn++; break; case FFI_TYPE_LONGDOUBLE: + by_reference: /* Note that 128-bit long double is passed by reference. */ - val = (unsigned long)valp; - break; - - case FFI_TYPE_FLOAT: - if (argp - stack < 6) - val = lds(valp); - else - val = *(UINT32 *)valp; + argp[argn++] = (unsigned long)valp; break; + case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: size = ty->size; - memcpy(argp, valp, size); - argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - continue; + memcpy(argp + argn, valp, size); + argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + break; + + case FFI_TYPE_COMPLEX: + type = ty->elements[0]->type; + if (type == FFI_TYPE_LONGDOUBLE) + goto by_reference; + + /* Most complex types passed as two separate arguments. */ + size = ty->elements[0]->size; + argp[argn] = extend_basic_type(valp, type, argn); + argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1); + argn += 2; + break; default: abort(); } - - *argp++ = val; } flags = (flags >> ALPHA_ST_SHIFT) & 0xff; - ffi_call_osf(stack, cif->bytes, flags, rvalue, fn); + ffi_call_osf(argp, cif->bytes, flags, rvalue, fn); } @@ -243,7 +339,6 @@ ffi_prep_closure_loc (ffi_closure* closure, return FFI_OK; } - long FFI_HIDDEN ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) { @@ -266,15 +361,18 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) } arg_types = cif->arg_types; - + /* Grab the addresses of the arguments from the stack frame. */ for (i = 0, avn = cif->nargs; i < avn; i++) { - size_t size = arg_types[i]->size; + ffi_type *ty = arg_types[i]; + int type = ty->type; void *valp = &argp[argn]; + size_t size; - switch (arg_types[i]->type) + switch (type) { + case FFI_TYPE_INT: case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: case FFI_TYPE_SINT16: @@ -284,7 +382,13 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: + argn += 1; + break; + + case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: + size = ty->size; + argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; break; case FFI_TYPE_FLOAT: @@ -295,17 +399,78 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) valp = &argp[argn - 6]; sts(valp, argp[argn - 6]); } + argn += 1; break; case FFI_TYPE_DOUBLE: if (argn < 6) valp = &argp[argn - 6]; + argn += 1; break; case FFI_TYPE_LONGDOUBLE: + by_reference: /* 128-bit long double is passed by reference. */ - valp = (long double *) argp[argn]; - size = sizeof (long double *); + valp = (void *)argp[argn]; + argn += 1; + break; + + case FFI_TYPE_COMPLEX: + type = ty->elements[0]->type; + switch (type) + { + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + /* Passed as separate arguments, but they wind up sequential. */ + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + /* Passed as separate arguments. Disjoint, but there's room + enough in one slot to hold the pair. */ + size = ty->elements[0]->size; + memcpy(valp + size, valp + 8, size); + break; + + case FFI_TYPE_FLOAT: + /* Passed as separate arguments. Disjoint, and each piece + may need conversion back to float. */ + if (argn < 6) + { + valp = &argp[argn - 6]; + sts(valp, argp[argn - 6]); + } + if (argn + 1 < 6) + sts(valp + 4, argp[argn + 1 - 6]); + else + *(UINT32 *)(valp + 4) = argp[argn + 1]; + break; + + case FFI_TYPE_DOUBLE: + /* Passed as separate arguments. Only disjoint if one part + is in fp regs and the other is on the stack. */ + if (argn < 5) + valp = &argp[argn - 6]; + else if (argn == 5) + { + valp = alloca(16); + ((UINT64 *)valp)[0] = argp[5 - 6]; + ((UINT64 *)valp)[1] = argp[6]; + } + break; + + case FFI_TYPE_LONGDOUBLE: + goto by_reference; + + default: + abort(); + } + argn += 2; break; default: @@ -313,7 +478,6 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) } avalue[i] = valp; - argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; } /* Invoke the closure. */ diff --git a/src/alpha/ffitarget.h b/src/alpha/ffitarget.h index af145bc..60f92fd 100644 --- a/src/alpha/ffitarget.h +++ b/src/alpha/ffitarget.h @@ -44,6 +44,9 @@ typedef enum ffi_abi { } ffi_abi; #endif +#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION +#define FFI_TARGET_HAS_COMPLEX_TYPE + /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 diff --git a/src/alpha/internal.h b/src/alpha/internal.h index 664a2a6..44da192 100644 --- a/src/alpha/internal.h +++ b/src/alpha/internal.h @@ -2,6 +2,8 @@ #define ALPHA_ST_INT 1 #define ALPHA_ST_FLOAT 2 #define ALPHA_ST_DOUBLE 3 +#define ALPHA_ST_CPLXF 4 +#define ALPHA_ST_CPLXD 5 #define ALPHA_LD_VOID 0 #define ALPHA_LD_INT64 1 @@ -12,6 +14,8 @@ #define ALPHA_LD_SINT8 6 #define ALPHA_LD_FLOAT 7 #define ALPHA_LD_DOUBLE 8 +#define ALPHA_LD_CPLXF 9 +#define ALPHA_LD_CPLXD 10 #define ALPHA_ST_SHIFT 0 #define ALPHA_LD_SHIFT 8 diff --git a/src/alpha/osf.S b/src/alpha/osf.S index fb9c595..4059f82 100644 --- a/src/alpha/osf.S +++ b/src/alpha/osf.S @@ -117,6 +117,14 @@ E ALPHA_ST_FLOAT E ALPHA_ST_DOUBLE stt $f0, 0($2) ret +E ALPHA_ST_CPLXF + sts $f0, 0($2) + sts $f1, 4($2) + ret +E ALPHA_ST_CPLXD + stt $f0, 0($2) + stt $f1, 8($2) + ret cfi_endproc .end ffi_call_osf @@ -228,6 +236,16 @@ E ALPHA_LD_DOUBLE ldt $f0, 16($sp) epilogue +E ALPHA_LD_CPLXF + lds $f0, 16($sp) + lds $f1, 20($sp) + epilogue + +E ALPHA_LD_CPLXD + ldt $f0, 16($sp) + ldt $f1, 24($sp) + epilogue + cfi_endproc .end ffi_closure_osf diff --git a/testsuite/libffi.call/call.exp b/testsuite/libffi.call/call.exp index 5177f07..09f6965 100644 --- a/testsuite/libffi.call/call.exp +++ b/testsuite/libffi.call/call.exp @@ -24,16 +24,12 @@ set ctlist [lsearch -inline -all -glob [lsort [glob -nocomplain -- $srcdir/$subd run-many-tests $tlist "" -if { ![istarget s390*] } { - +if { [istarget s390*] || [istarget alpha*] } { + run-many-tests $ctlist "" +} else { foreach test $ctlist { unsupported "$test" } - -} else { - - run-many-tests $ctlist "" - } dg-finish diff --git a/testsuite/libffi.call/cls_complex_va_float.c b/testsuite/libffi.call/cls_complex_va_float.c index 0b79979..2b17826 100644 --- a/testsuite/libffi.call/cls_complex_va_float.c +++ b/testsuite/libffi.call/cls_complex_va_float.c @@ -6,5 +6,11 @@ /* { dg-do run } */ +/* Alpha splits _Complex into two arguments. It's illegal to pass + float through varargs, so _Complex float goes badly. In sort of + gets passed as _Complex double, but the compiler doesn't agree + with itself on this issue. */ +/* { dg-do run { xfail alpha*-*-* } } */ + #include "complex_defs_float.inc" #include "cls_complex_va.inc" -- 1.9.3