This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [patch/libffi/hppa] Fix handling of 3 and 5-7 byte struct returns
- From: "John David Anglin" <dave at hiauly1 dot hia dot nrc dot ca>
- To: randolph at tausq dot org
- Cc: gcc-patches at sources dot redhat dot com
- Date: Tue, 5 Jul 2005 23:44:35 -0400 (EDT)
- Subject: Re: [patch/libffi/hppa] Fix handling of 3 and 5-7 byte struct returns
> This fixes all the libffi test failures on hppa-linux. Please check
> in if ok.
Installed as floows with a few minor changes to address formatting
and compilation warnings in ffi.c.
Tested on hppa-unknown-linux-gnu, 4.0 and head.
Dave
--
J. David Anglin dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6602)
2005-07-05 Randolph Chung <tausq@debian.org>
* src/pa/ffi.c (ffi_struct_type): Rename FFI_TYPE_SMALL_STRUCT1
as FFI_TYPE_SMALL_STRUCT3. Break out handling for 5-7 byte
structures. Kill compilation warnings.
(ffi_closure_inner_LINUX): Print return values as hex in debug
message. Rename FFI_TYPE_SMALL_STRUCT1 as FFI_TYPE_SMALL_STRUCT3.
Properly handle 5-7 byte structure returns.
* src/pa/ffitarget.h (FFI_TYPE_SMALL_STRUCT1)
(FFI_TYPE_SMALL_STRUCT2): Remove.
(FFI_TYPE_SMALL_STRUCT3, FFI_TYPE_SMALL_STRUCT5)
(FFI_TYPE_SMALL_STRUCT6, FFI_TYPE_SMALL_STRUCT7): Define.
* src/pa/linux.S: Mark source file as using PA1.1 assembly.
(checksmst1, checksmst2): Remove.
(checksmst3): Optimize handling of 3-byte struct returns.
(checksmst567): Properly handle 5-7 byte struct returns.
Index: src/pa/ffi.c
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/pa/ffi.c,v
retrieving revision 1.1
diff -u -3 -p -r1.1 ffi.c
--- src/pa/ffi.c 19 Mar 2004 22:34:17 -0000 1.1
+++ src/pa/ffi.c 6 Jul 2005 03:22:05 -0000
@@ -27,6 +27,7 @@
#include <ffi_common.h>
#include <stdlib.h>
+#include <stdio.h>
#define ROUND_UP(v, a) (((size_t)(v) + (a) - 1) & ~((a) - 1))
#define ROUND_DOWN(v, a) (((size_t)(v) - (a) + 1) & ~((a) - 1))
@@ -53,11 +54,15 @@ static inline int ffi_struct_type(ffi_ty
else if (sz == 2)
return FFI_TYPE_UINT16;
else if (sz == 3)
- return FFI_TYPE_SMALL_STRUCT1;
+ return FFI_TYPE_SMALL_STRUCT3;
else if (sz == 4)
return FFI_TYPE_UINT32;
- else if (sz <= 6)
- return FFI_TYPE_SMALL_STRUCT2;
+ else if (sz == 5)
+ return FFI_TYPE_SMALL_STRUCT5;
+ else if (sz == 6)
+ return FFI_TYPE_SMALL_STRUCT6;
+ else if (sz == 7)
+ return FFI_TYPE_SMALL_STRUCT7;
else if (sz <= 8)
return FFI_TYPE_UINT64;
else
@@ -491,34 +496,32 @@ UINT32 ffi_closure_inner_LINUX(ffi_closu
/* Invoke the closure. */
(closure->fun) (cif, rvalue, avalue, closure->user_data);
- debug(3, "after calling function, ret[0] = %d, ret[1] = %d\n", ret[0], ret[1]);
+ debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0], ret[1]);
/* Store the result */
switch (cif->flags)
{
case FFI_TYPE_UINT8:
- *(stack - FIRST_ARG_SLOT) = *(UINT8 *)&ret[0];
+ *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24);
break;
case FFI_TYPE_SINT8:
- *(stack - FIRST_ARG_SLOT) = *(SINT8 *)&ret[0];
+ *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24);
break;
case FFI_TYPE_UINT16:
- *(stack - FIRST_ARG_SLOT) = *(UINT16 *)&ret[0];
+ *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16);
break;
case FFI_TYPE_SINT16:
- *(stack - FIRST_ARG_SLOT) = *(SINT16 *)&ret[0];
+ *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16);
break;
case FFI_TYPE_INT:
- case FFI_TYPE_UINT32:
- *(stack - FIRST_ARG_SLOT) = *(UINT32 *)&ret[0];
- break;
case FFI_TYPE_SINT32:
- *(stack - FIRST_ARG_SLOT) = *(SINT32 *)&ret[0];
+ case FFI_TYPE_UINT32:
+ *(stack - FIRST_ARG_SLOT) = ret[0];
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
- *(stack - FIRST_ARG_SLOT) = *(UINT32 *)&ret[0];
- *(stack - FIRST_ARG_SLOT - 1) = *(UINT32 *)&ret[1];
+ *(stack - FIRST_ARG_SLOT) = ret[0];
+ *(stack - FIRST_ARG_SLOT - 1) = ret[1];
break;
case FFI_TYPE_DOUBLE:
@@ -533,15 +536,34 @@ UINT32 ffi_closure_inner_LINUX(ffi_closu
/* Don't need a return value, done by caller. */
break;
- case FFI_TYPE_SMALL_STRUCT1:
+ case FFI_TYPE_SMALL_STRUCT3:
tmp = (void*)(stack - FIRST_ARG_SLOT);
tmp += 4 - cif->rtype->size;
memcpy((void*)tmp, &ret[0], cif->rtype->size);
break;
- case FFI_TYPE_SMALL_STRUCT2:
- *(stack - FIRST_ARG_SLOT) = ret[0];
- *(stack - FIRST_ARG_SLOT - 1) = ret[1];
+ case FFI_TYPE_SMALL_STRUCT5:
+ case FFI_TYPE_SMALL_STRUCT6:
+ case FFI_TYPE_SMALL_STRUCT7:
+ {
+ unsigned int ret2[2];
+ int off;
+
+ /* Right justify ret[0] and ret[1] */
+ switch (cif->flags)
+ {
+ case FFI_TYPE_SMALL_STRUCT5: off = 3; break;
+ case FFI_TYPE_SMALL_STRUCT6: off = 2; break;
+ case FFI_TYPE_SMALL_STRUCT7: off = 1; break;
+ default: off = 0; break;
+ }
+
+ memset (ret2, 0, sizeof (ret2));
+ memcpy ((char *)ret2 + off, ret, 8 - off);
+
+ *(stack - FIRST_ARG_SLOT) = ret2[0];
+ *(stack - FIRST_ARG_SLOT - 1) = ret2[1];
+ }
break;
case FFI_TYPE_POINTER:
Index: src/pa/ffitarget.h
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/pa/ffitarget.h,v
retrieving revision 1.1
diff -u -3 -p -r1.1 ffitarget.h
--- src/pa/ffitarget.h 19 Mar 2004 22:34:17 -0000 1.1
+++ src/pa/ffitarget.h 6 Jul 2005 03:22:05 -0000
@@ -51,7 +51,9 @@ typedef enum ffi_abi {
#define FFI_TRAMPOLINE_SIZE 32
-#define FFI_TYPE_SMALL_STRUCT1 -1
-#define FFI_TYPE_SMALL_STRUCT2 -2
+#define FFI_TYPE_SMALL_STRUCT3 -1
+#define FFI_TYPE_SMALL_STRUCT5 -2
+#define FFI_TYPE_SMALL_STRUCT6 -3
+#define FFI_TYPE_SMALL_STRUCT7 -4
#endif
Index: src/pa/linux.S
===================================================================
RCS file: /cvs/gcc/gcc/libffi/src/pa/linux.S,v
retrieving revision 1.2
diff -u -3 -p -r1.2 linux.S
--- src/pa/linux.S 20 Mar 2004 11:58:01 -0000 1.2
+++ src/pa/linux.S 6 Jul 2005 03:22:05 -0000
@@ -28,6 +28,7 @@
#include <ffi.h>
.text
+ .level 1.1
.align 4
/* void ffi_call_LINUX(void (*)(char *, extended_cif *),
@@ -105,21 +106,46 @@ ffi_call_LINUX:
/* Store the result according to the return type. */
-checksmst1:
- comib,<>,n FFI_TYPE_SMALL_STRUCT1, %r21, checksmst2
- /* There is maybe a better way to handle 3 byte structs. */
- sh2add %ret0,0,%ret0
- sh2add %ret0,0,%ret0
- sh2add %ret0,0,%ret0
- sh2add %ret0,0,%ret0
+checksmst3:
+ comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, checksmst567
+ /* 3-byte structs are returned in ret0 as ??xxyyzz. Shift
+ left 8 bits to write to the result structure. */
+ zdep %ret0, 23, 24, %r22
b done
- stw %ret0, 0(%r20)
+ stw %r22, 0(%r20)
-checksmst2:
- comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, checkint8
- /* Up to now I don't have a way to handle 6/7 byte structs.
- The values are left bounded in the registers. In the struct
- itself they are left bounded. */
+checksmst567:
+ /* 5-7 byte values are returned right justified:
+ ret0 ret1
+ 5: ??????aa bbccddee
+ 6: ????aabb ccddeeff
+ 7: ??aabbcc ddeeffgg
+
+ To store this in the result, write the first 4 bytes into a temp
+ register using shrpw (t1 = aabbccdd), followed by a rotation of
+ ret1:
+
+ ret0 ret1 ret1
+ 5: ??????aa bbccddee -> eebbccdd (rotate 8)
+ 6: ????aabb ccddeeff -> eeffccdd (rotate 16)
+ 7: ??aabbcc ddeeffgg -> eeffggdd (rotate 24)
+
+ then we write (t1, ret1) into the result. */
+
+ addi,<> -FFI_TYPE_SMALL_STRUCT5,%r21,%r0
+ ldi 8, %r22
+ addi,<> -FFI_TYPE_SMALL_STRUCT6,%r21,%r0
+ ldi 16, %r22
+ addi,<> -FFI_TYPE_SMALL_STRUCT7,%r21,%r0
+ ldi 24, %r22
+
+ /* This relies on all the FFI_TYPE_*_STRUCT* defines being <0 */
+ cmpib,<=,n 0, %r21, checkint8
+ mtsar %r22
+
+ shrpw %ret0, %ret1, %sar, %ret0 /* ret0 = aabbccdd */
+ shrpw %ret1, %ret1, %sar, %ret1 /* rotate ret1 */
+
stw %ret0, 0(%r20)
b done
stw %ret1, 4(%r20)