Patchwork [Fortran] PR 46638 Wrong results with TRANSFER to derived types

login
register
mail settings
Submitter Tobias Burnus
Date Nov. 24, 2010, 3:25 p.m.
Message ID <4CED2E65.4000804@net-b.de>
Download mbox | patch
Permalink /patch/72902/
State New
Headers show

Comments

Tobias Burnus - Nov. 24, 2010, 3:25 p.m.
The code for simplifying the TRANSFER to a derived type assumed that the 
elements are all offset by the amount DECL_FIELD_OFFSET (in bytes). 
However, that's only the case if each element has the size of 
DECL_OFFSET_ALIGN -- or larger. On my system, that's chunks of 16 byte. 
Thus, for all components whose size is smaller, the result will be wrong.

The trick is to add to DECL_FIELD_OFFSET additionally the bits of 
DECL_FIELD_BIT_OFFSET -- that actually done for transferring the data 
from a derived type.

[Instead of using the magical number "8" one could also use 
BITS_PER_UNIT (and add #include "default.h").]

Build and regtested on x86-64-linux.
OK for the trunk and 4.4/4.5?

Tobias

PS: See PR 46638 for other issues raised in the c.l.f thread -- related 
to C_SIZEOF and SIZEOF. Anyone can feel free to work on that item -- I 
do not plan to do so in the near future.
Jerry DeLisle - Nov. 24, 2010, 4:35 p.m.
On 11/24/2010 07:25 AM, Tobias Burnus wrote:
> The code for simplifying the TRANSFER to a derived type assumed that the
> elements are all offset by the amount DECL_FIELD_OFFSET (in bytes). However,
> that's only the case if each element has the size of DECL_OFFSET_ALIGN -- or
> larger. On my system, that's chunks of 16 byte. Thus, for all components whose
> size is smaller, the result will be wrong.
>
> The trick is to add to DECL_FIELD_OFFSET additionally the bits of
> DECL_FIELD_BIT_OFFSET -- that actually done for transferring the data from a
> derived type.
>
> [Instead of using the magical number "8" one could also use BITS_PER_UNIT (and
> add #include "default.h").]
>
> Build and regtested on x86-64-linux.
> OK for the trunk and 4.4/4.5?
>

OK, thanks for quick fix

Patch

2010-11-24  Tobias Burnus  <burnus@net-b.de>

	PR fortran/46638
	* target-memory.c (gfc_interpret_derived): Correctly handle
	component offset.

2010-11-24  Tobias Burnus  <burnus@net-b.de>

	PR fortran/46638
	* gfortran.dg/transfer_simplify_10.f90: New.

diff --git a/gcc/fortran/target-memory.c b/gcc/fortran/target-memory.c
index 93e1c8c..01383c7 100644
--- a/gcc/fortran/target-memory.c
+++ b/gcc/fortran/target-memory.c
@@ -477,7 +477,16 @@  gfc_interpret_derived (unsigned char *buffer, size_t buffer_size, gfc_expr *resu
       /* The constructor points to the component.  */
       c->n.component = cmp;
 
-      ptr = TREE_INT_CST_LOW (DECL_FIELD_OFFSET (cmp->backend_decl));
+      /* Calculate the offset, which consists of the the FIELD_OFFSET in
+	 bytes, which appears in multiples of DECL_OFFSET_ALIGN-bit-sized,
+	 and additional bits of FIELD_BIT_OFFSET. The code assumes that all
+	 sizes of the components are multiples of BITS_PER_UNIT,
+	 i.e. there are, e.g., no bit fields.  */
+
+      ptr = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (cmp->backend_decl));
+      gcc_assert (ptr % 8 == 0);
+      ptr = ptr/8 + TREE_INT_CST_LOW (DECL_FIELD_OFFSET (cmp->backend_decl));
+
       gfc_target_interpret_expr (&buffer[ptr], buffer_size - ptr, e);
     }
     
diff --git a/gcc/testsuite/gfortran.dg/transfer_simplify_10.f90 b/gcc/testsuite/gfortran.dg/transfer_simplify_10.f90
new file mode 100644
index 0000000..d0c83b5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/transfer_simplify_10.f90
@@ -0,0 +1,28 @@ 
+! { dg-do run }
+!
+! PR fortran/46638
+!
+! Contributed by James Van Buskirk
+!
+program test5
+   use ISO_C_BINDING
+   implicit none
+   type, bind(C) :: CPUID_type
+      integer(C_INT32_T) eax
+      integer(C_INT32_T) ebx
+      integer(C_INT32_T) edx
+      integer(C_INT32_T) ecx
+      integer(C_INT32_T) bbb
+   end type CPUID_type
+   type(CPUID_TYPE) result
+  result = transfer(achar(10)//achar(0)//achar(0)//achar(0)//'GenuineIntel'//'abcd',result)
+
+  if (     int(z'0000000A') /= result%eax  &
+      .or. int(z'756E6547') /= result%ebx  &
+      .or. int(z'49656E69') /= result%edx  &
+      .or. int(z'6C65746E') /= result%ecx  &
+      .or. int(z'64636261') /= result%bbb) then
+    write(*,'(5(z8.8:1x))') result
+    call abort()
+  end if
+end program test5