Bug 28747

Summary: Empty write STREAM I/O file positioning problem
Product: gcc Reporter: Jerry DeLisle <jvdelisle>
Component: libfortranAssignee: Not yet assigned to anyone <unassigned>
Severity: normal CC: gcc-bugs
Priority: P3    
Version: 4.2.0   
Target Milestone: 4.2.0   
Host: x86_64-unknown-freebsd7.0 Target: x86_64-unknown-freebsd7.0
Build: Known to work:
Known to fail: Last reconfirmed: 2006-08-20 04:25:42
Bug Depends on:    
Bug Blocks: 20585    
Attachments: assembly output for reduced case

Description Jerry DeLisle 2006-08-16 03:11:55 UTC
The following does not work with bleeding edge FreeBSD:

program streamtest
  implicit none
  character(1)   :: lf = char(10)
  character(1)   :: tchar
  integer        :: i,j,k
  real(kind=4), dimension(100,100) :: anarray
  open(10, file="teststream", access="stream", form="unformatted")
  anarray = 3.14159
  write(10) anarray
  anarray = 0.0
  write(10, pos=1) ! This should position for the following read
  read(10) anarray
  anarray = abs(anarray - 3.14159)
  if (any(anarray.gt.0.00001)) call abort()
end program streamtest
Comment 1 Jerry DeLisle 2006-08-18 16:08:22 UTC
Created attachment 12093 [details]
assembly output for reduced case

There is wrong code generated setting up the parameters for the second call to write.  The pointers are off by 400.  You can see this by comparing the instructions just before the first call too _gfortran_st_write vs the instructions leading up to the second _gfortran_st_write.

-fdump-tree-original looks OK.  Inserting a flush right after the first call to write in the test case and the problem goes away.

Middle-end or backend problem?
Comment 2 Jerry DeLisle 2006-08-18 16:12:26 UTC
Simplified test case used in discussion above.

program streamtest
  implicit none
  real, dimension(2,3) :: anarray
  open(10, file="teststream", access="stream", form="unformatted")
  anarray = 3.14159
  write(10) anarray
  write(10, pos=1) ! This is a way to position an unformatted file
  anarray = 0.0
  read(10) anarray
end program streamtest

Additional info:

Using built-in specs.
Target: x86_64-unknown-freebsd7.0
Configured with: ../gcc4x/configure --prefix=/home/sgk/work/4x --enable-languages=c,fortran
Thread model: posix
gcc version 4.2.0 20060816 (experimental)

Comment 3 Andrew Pinski 2006-08-18 16:15:20 UTC
(In reply to comment #1)
> Middle-end or backend problem?
Can you look at the dump that is produced by -fdump-tree-final_cleanup
and see if it is correct?
Comment 4 Jerry DeLisle 2006-08-18 16:29:53 UTC
Using -fdump-tree-final_cleanup all looks OK.
Comment 5 Jerry DeLisle 2006-08-18 20:54:26 UTC
Here is a debug trace showing the steps leading up to the mutation of the dtp pointer.  StevebB on IRC indicated that the assembly output on linux x86-64 natch the freebsd version I posted here and the problem does not occur on that platform.  Notice the before an after values of the dtp pointer!

(gdb) s
*_gfortran_st_write_done (dtp=0x7fffffffe640)
    at ../../../gcc4x/libgfortran/io/transfer.c:2546
2546      if (dtp->u.p.scratch != NULL)
(gdb) s
2548      if (dtp->u.p.current_unit != NULL)
(gdb) s
2549        unlock_unit (dtp->u.p.current_unit);
(gdb) s
*_gfortrani_unlock_unit (u=0x2008103b0) at gthr-posix.h:566
566       if (__gthread_active_p ())
(gdb) p dtp
No symbol "dtp" in current context.
(gdb) p u
$5 = (gfc_unit *) 0x2008103b0
(gdb) p *u
$6 = {unit_number = 10, s = 0x200828000, left = 0x0, right = 0x0,
  priority = 14047, read_bad = 1, current_record = 1, endfile = NO_ENDFILE,
  mode = WRITING, flags = {access = ACCESS_STREAM, action = ACTION_READWRITE,
    blank = BLANK_NULL, delim = DELIM_NONE, form = FORM_UNFORMATTED,
    is_notpadded = 0, position = POSITION_ASIS, status = STATUS_UNKNOWN,
    pad = PAD_YES, convert = CONVERT_NATIVE}, recl = 1, last_record = 25,
  maxrec = 9223372036854775807, bytes_left = 0, lock = 0x0, waiting = 0,
  closed = 0, ls = 0x0, rank = 0, file_len = 10,
  file = 0x20082c140 "teststream"}
(gdb) s
567         return __gthrw_(pthread_mutex_unlock) (mutex);
(gdb) s

Breakpoint 1, *_gfortran_st_write (dtp=0x7fffffffe7d0)
    at ../../../gcc4x/libgfortran/io/transfer.c:2506
2506    {
Comment 6 Jerry DeLisle 2006-08-19 03:29:26 UTC
Here is a comparison of no optimization and with -O1.  Does this code look the same on x86-64 that is not FreeBSD?

Code with no optimization: This does not work.

	call	_gfortran_st_write_done
	movq	$.LC0, -424(%rbp)
	movl	$8, -416(%rbp)
	movl	$10, -428(%rbp)
	movq	$1, -392(%rbp)
	movl	$512, -432(%rbp)
	leaq	-432(%rbp), %rdi
	call	_gfortran_st_write

Code with -O1: This works

        call    _gfortran_st_write_done
        movq    $.LC0, 8(%rsp)
        movl    $8, 16(%rsp)
        movl    $10, 4(%rsp)
        movq    $1, 40(%rsp)
        movl    $512, (%rsp)
        movq    %rsp, %rdi
        call    _gfortran_st_write
Comment 7 Jack Howarth 2006-08-19 15:55:05 UTC
    On Fedora Core 5 x86_64 with the svn pull from  a few days back and last stream patch
I get the follow diff between the code generated with -O0 and -O1...

        call    _gfortran_st_write_done
-       movq    $.LC0, -600(%rbp)
-       movl    $8, -592(%rbp)
-       movl    $10, -604(%rbp)
-       movq    $1, -568(%rbp)
-       movl    $512, -608(%rbp)
-       leaq    -608(%rbp), %rdi
+       movq    $.LC0, 8(%rsp)
+       movl    $8, 16(%rsp)
+       movl    $10, 4(%rsp)
+       movq    $1, 40(%rsp)
+       movl    $512, (%rsp)
+       movq    %rsp, %rdi
        call    _gfortran_st_write

In both cases the reduced test case runs fine.
Comment 8 Jerry DeLisle 2006-08-19 16:52:24 UTC
I think this confirms the problem is in __gthrw_(pthread_mutex_unlock) (mutex) on FreeBSD.
Comment 9 Jerry DeLisle 2006-09-15 13:35:25 UTC
Fixed on 4.2, will not go to 4.1

*** This bug has been marked as a duplicate of 29053 ***