public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call
@ 2011-12-20 15:32 bardeau at iram dot fr
  2011-12-20 17:31 ` [Bug fortran/51638] " burnus at gcc dot gnu.org
                   ` (12 more replies)
  0 siblings, 13 replies; 14+ messages in thread
From: bardeau at iram dot fr @ 2011-12-20 15:32 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

             Bug #: 51638
           Summary: gfortran optimization breaks a single variable used as
                    both input and output for subroutine call
    Classification: Unclassified
           Product: gcc
           Version: fortran-dev
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: fortran
        AssignedTo: unassigned@gcc.gnu.org
        ReportedBy: bardeau@iram.fr


Created attachment 26153
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=26153
Program fails with -O flag under 32 bits systems

Hello,

the attached program provides 2 subroutines which do not run correctly if the
program is compiled with the optimization option (-O). Since the program
behaves correctly without this option, this sounds like a bug (at least it
severely annoys us). The subroutines are inherited from our Fortran 77 legacy
code, which behaved well with the other compilers (ifc/ifort, g95, ...) for at
least one decade.

* About the test program:
 it should be self-explanatory. The idea it to swap the bytes in 4 and 8 bytes
integers, but I am not sure this is a major point. The key point is that the
same variable is used as 2 different dummy variables (input and output) in the
calling sequence.

 Here is the output when the program fails:
ubuntu-32:~$ gfortran -O test.f90 -o test
(some type mismatch warnings)
ubuntu-32:~$ ./test
 Call to subroutine IEI4EI with single I/O variable failed:
 Input:    2147483647  (int4) =    -1   -1   -1  127  (4 int1)
 Output:   2147483519  (int4) =   127   -1   -1  127  (4 int1)
 Call to subroutine IEI8EI with single I/O variable failed:
 In:   9223372036854775807  (int8) =    -1   -1   -1   -1   -1   -1   -1  127 
(8 int1)
 Out:  9223372036854775679  (int8) =   127   -1   -1   -1   -1   -1   -1  127 
(8 int1)

You can see that the bytes of the output variable are not correctly swapped.


* About the context:
- Many (if not all) 32 bits linux (and MinGW) are affected, including the
latest 32 bits Ubuntu (11.10).
- No 64 bits linux I tested is affected.
- All the gfortran versions seem affected, including latest 4.7.0 20111215
- The optimization seems mandatory to reproduce the bug, although I suspect I
observed the bug without this option in the past.

Thanks for your help. Unfortunately I won't be available for feedback during
Xmas holidays.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
@ 2011-12-20 17:31 ` burnus at gcc dot gnu.org
  2011-12-20 17:46 ` kargl at gcc dot gnu.org
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: burnus at gcc dot gnu.org @ 2011-12-20 17:31 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

Tobias Burnus <burnus at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |burnus at gcc dot gnu.org

--- Comment #1 from Tobias Burnus <burnus at gcc dot gnu.org> 2011-12-20 17:20:46 UTC ---
(In reply to comment #0)
> the attached program provides 2 subroutines which do not run correctly if the
> program is compiled with the optimization option (-O).

I can reproduce it with
  -O -m32
on x86-64-linux. It works with -O0 or with -O2 or higher. And it is independent
of the usual suspects, i.e. -fno-frontend-optimize and -mfpmath=sse do not
change the result.

I have not yet understood why it causes problems.

 * * *

> The key point is that the same variable is used as 2 different dummy
> variables (input and output) in the calling sequence.

I think that's actually not the key point. While it is invalid (in the general
case) to pass twice the same argument, it does not seem to cause the problem.
(Passing the same argument multiple times is valid if one does not modify it;
also pointer and target attribute enable some valid use. However, your usage is
clearly invalid.)

The problem of passing the argument multiple times can be removed by changing
the code to:
  call iei4ei( (in4), in4)
  call iei8ei( (in8), in8)
(Note the "(...)".) However, the issue is unaffected by this change.


In terms of code validity, there are two other issues:

a) Wrong objects in EQUIVALENCE:

C591 (R566) If an equivalence-object is default integer, default real, double
precision real, default complex, default logical, or of numeric sequence type,
all of the objects in the equivalence set shall be of these types and kinds.

C594 (R566) If an equivalence-object is of an intrinsic type but is not default
integer, default real, double precision real, default complex, default logical,
or default character, all of the objects in the equivalence set shall be of the
same type with the same kind type parameter value.


b) Passing an INTEGER(kind=4) to an INTEGER(kind=1) is invalid.

Nevertheless, one should try to find out what goes wrong.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
  2011-12-20 17:31 ` [Bug fortran/51638] " burnus at gcc dot gnu.org
@ 2011-12-20 17:46 ` kargl at gcc dot gnu.org
  2012-01-03 10:21 ` bardeau at iram dot fr
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: kargl at gcc dot gnu.org @ 2011-12-20 17:46 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

kargl at gcc dot gnu.org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |kargl at gcc dot gnu.org

--- Comment #2 from kargl at gcc dot gnu.org 2011-12-20 17:44:56 UTC ---
(In reply to comment #1)
> (In reply to comment #0)
> > the attached program provides 2 subroutines which do not run correctly if the
> > program is compiled with the optimization option (-O).
> 
> I can reproduce it with
>   -O -m32
> on x86-64-linux. It works with -O0 or with -O2 or higher. And it is independent
> of the usual suspects, i.e. -fno-frontend-optimize and -mfpmath=sse do not
> change the result.
> 
> I have not yet understood why it causes problems.
> 
>  * * *
> 
> > The key point is that the same variable is used as 2 different dummy
> > variables (input and output) in the calling sequence.

Actually, the same variable is used as the actual argument in the
call to the subroutine, and the actual argument becomes associated
with two different dummy argument.

> I think that's actually not the key point. While it is invalid
> (in the general case) to pass twice the same argument, it does
> not seem to cause the problem.

Huh?  It is not invalid to have an entity appear as multiple
actual arguments in an argument list.

> (Passing the same argument multiple times is valid if one does
> not modify it; also pointer and target attribute enable some
> valid use. However, your usage is clearly invalid.)

You even state that it is valid!  The problem is that the OP
modifies on of the dummy arguments.  This is clearly discussed
in 

12.4.1.7  Restrictions on entities associated with dummy
          arguments

While an entity is associated with a dummy argument, the
following restrictions hold:
  (1) ... Action that affects the value of the entity or
      any subobject of it shall be taken only through the
      dummy argument unless ...

      (unless stuff involves things with POINTER or
       TARGET attributes, which OP doesn't have)

Further down in Note 12.29

If there is a partial or complete overlap between the actual
arguments associated with two different dummy arguments of
the same procedure and the dummy arguments have neither the
POINTER nor TARGET attribute, the overlapped portions shall
not be defined, redefined, or become unde- fined during the
execution of the procedure. For example, in

CALL SUB (A(1:5), A(3:9))

A(3:5) shall not be defined, redefined, or become undefined
through the first dummy argument because it is part of the
argument associated with the second dummy argument and shall
not be defined, redefined, or become undefined through the
second dummy argument because it is part of the argument
associated with the first dummy argument. A(1:2)remains
definable through the first dummy argument and A(6:9)
remains definable through the second dummy argument.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
  2011-12-20 17:31 ` [Bug fortran/51638] " burnus at gcc dot gnu.org
  2011-12-20 17:46 ` kargl at gcc dot gnu.org
@ 2012-01-03 10:21 ` bardeau at iram dot fr
  2012-01-03 19:05 ` kargl at gcc dot gnu.org
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: bardeau at iram dot fr @ 2012-01-03 10:21 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

--- Comment #3 from Sebastien Bardeau <bardeau at iram dot fr> 2012-01-03 10:21:08 UTC ---
(In reply to comment #1)
> 
> I can reproduce it with
>   -O -m32
> on x86-64-linux.

Fine you can reproduce it easily.


> In terms of code validity, there are two other issues:

I definitely agree this code is not latest-Fortran-standard, but it implements
a few F77 tricks which, from my view, are not really broken by the latest
Fortran requirements. Or at least the other compilers and the other gfortran
modes did not need to break these tricks yet. So I will hurry not to change
anything in my code until you have a clear diagnostic of this bug. ;-)

Thanks for your help.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (2 preceding siblings ...)
  2012-01-03 10:21 ` bardeau at iram dot fr
@ 2012-01-03 19:05 ` kargl at gcc dot gnu.org
  2012-01-04  8:46 ` burnus at gcc dot gnu.org
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: kargl at gcc dot gnu.org @ 2012-01-03 19:05 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

--- Comment #4 from kargl at gcc dot gnu.org 2012-01-03 19:05:27 UTC ---
(In reply to comment #3)
> (In reply to comment #1)
> > 
> > I can reproduce it with
> >   -O -m32
> > on x86-64-linux.
> 
> Fine you can reproduce it easily.
> 
> 
> > In terms of code validity, there are two other issues:
> 
> I definitely agree this code is not latest-Fortran-standard, but it implements
> a few F77 tricks which, from my view, are not really broken by the latest
> Fortran requirements. Or at least the other compilers and the other gfortran
> modes did not need to break these tricks yet. So I will hurry not to change
> anything in my code until you have a clear diagnostic of this bug. ;-)
> 
> Thanks for your help.

See comment #3 in the audit trail of this PR.  Your
Fortran code is invalid.  We have a clear diagnostic.
The bug is in your code not the Fortran compiler.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (3 preceding siblings ...)
  2012-01-03 19:05 ` kargl at gcc dot gnu.org
@ 2012-01-04  8:46 ` burnus at gcc dot gnu.org
  2012-01-05 10:44 ` bardeau at iram dot fr
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: burnus at gcc dot gnu.org @ 2012-01-04  8:46 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

--- Comment #5 from Tobias Burnus <burnus at gcc dot gnu.org> 2012-01-04 08:46:30 UTC ---
(In reply to comment #3)
> Or at least the other compilers and the other gfortran modes did not need to
> break these tricks yet.

The issue is essentially that GCC will optimize in

subroutine iei4ei(inpu,oupu)
  inte(:) = inpu(:)
  oupu(4) = inte(1)
  oupu(3) = inte(2)
  oupu(2) = inte(3)
  oupu(1) = inte(4)

the "inte" away, which is perfectly valid as "inpu" and "outu" may not point to
the same memory.

To be more precise (cf. -fdump-tree-optimized), instead of (-O0):
  MEM[(c_char * {ref-all})&inte] = MEM[(c_char * {ref-all})inpu_1(D)];
  D.1820_2 = inte[0];
  *oupu_3(D)[3] = D.1820_2;
  ...
the compiler generates (-O2, -O3):
  inte$0_14 = MEM[(c_char * {ref-all})inpu_1(D)];
  inte$1_15 = MEM[(c_char * {ref-all})inpu_1(D) + 1B];
  ...
  *oupu_3(D)[3] = inte$0_14;
  ...
and depending on the assembler generation (order, register usage), this will
work or not. Seemingly, on i386 the generated assembler will break your program
while it happens to work on x86-64.

This optimization is perfectly valid according the Fortran standard and speeds
valid programs. I am sure that other compilers do the same, though whether it
will break your program depends on the generated assembler code. I wouldn't be
surprised if the program also breaks with other compilers with some compiler
flag or a slightly different compiler version.


This "breakage" happens in principle for all optimization levels (-O1, -O2,
...). However, if "iei8ei"/"iei4ei" and "program gfortran_debug" are in the
same file, inlining and other optimizations happen such that the program
happens to work by chance for -O2/-O3.


Work-around solutions: Use -O0 or make "inte" VOLATILE. [The program is then
still formally wrong, but should work.]


The better change is to change the call to:
  call iei4ei((in4),in4)
  call iei8ei((in8),in8)
That will force the generation of a temporary variable in the caller, which
makes this part of the program valid. (You still have the issue of passing an
INTEGER(4) to an INTEGER(1) and misuse of EQUIVALENCE.)

(The "()" seems to be enough to fix the program; I don't know why it didn't
seem to fix the issue when I wrote comment 1.)


Alternatively, you can add to both arguments of "iei4ei" and "iei8ei" the
TARGET attribute - in that case the compiler knows that the arguments may be
storage associated each other. However, Fortran then requires an explicit
interface. (This will be difficult as you pass an integer(kind=4) to an
integer(kind=1), which is invalid.)


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (4 preceding siblings ...)
  2012-01-04  8:46 ` burnus at gcc dot gnu.org
@ 2012-01-05 10:44 ` bardeau at iram dot fr
  2012-01-05 14:27 ` burnus at gcc dot gnu.org
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: bardeau at iram dot fr @ 2012-01-05 10:44 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

--- Comment #6 from Sebastien Bardeau <bardeau at iram dot fr> 2012-01-05 10:43:52 UTC ---
Dear all,

(In reply to comment #4)
> Your
> Fortran code is invalid.  We have a clear diagnostic.
> The bug is in your code not the Fortran compiler.

This code is like it is since its first commit on 11-Jun-93 under our CVS
repository. And it is probably much older. It has been used since that time
under many systems (VAX, HP-UX, Sun, OSF, AIX, Linux, MS Windows at least) and
compiled by many compilers (ifc/ifort, g95, xlf, lf95, pgf90, etc). All this
without any problem.

If you look twice at this code you will see it does nothing clever: it just
assumes (!) that an INTEGER*4 is 4 bytes aligned. Then it swaps these 4 bytes
by using a local copy

I still do think there is a problem with gfortran, because 1) it is the only
one which breaks this simple code regarding our 25 years experience, and 2)
because it randomly breaks it depending on the architecture and options.


(In reply to comment #5)
> The issue is essentially that GCC will optimize in
> 
> subroutine iei4ei(inpu,oupu)
>   inte(:) = inpu(:)
>   oupu(4) = inte(1)
>   oupu(3) = inte(2)
>   oupu(2) = inte(3)
>   oupu(1) = inte(4)
> 
> the "inte" away, which is perfectly valid as "inpu" and "outu" may not point to
> the same memory.

Ok at least the diagnostic is clear.


> To be more precise (cf. -fdump-tree-optimized), instead of (-O0):
>   MEM[(c_char * {ref-all})&inte] = MEM[(c_char * {ref-all})inpu_1(D)];
>   D.1820_2 = inte[0];
>   *oupu_3(D)[3] = D.1820_2;
>   ...
> the compiler generates (-O2, -O3):
>   inte$0_14 = MEM[(c_char * {ref-all})inpu_1(D)];
>   inte$1_15 = MEM[(c_char * {ref-all})inpu_1(D) + 1B];
>   ...
>   *oupu_3(D)[3] = inte$0_14;
>   ...
> and depending on the assembler generation (order, register usage), this will
> work or not. Seemingly, on i386 the generated assembler will break your program
> while it happens to work on x86-64.
> 
> This optimization is perfectly valid according the Fortran standard and speeds
> valid programs. I am sure that other compilers do the same, though whether it
> will break your program depends on the generated assembler code. I wouldn't be
> surprised if the program also breaks with other compilers with some compiler
> flag or a slightly different compiler version.

We have never observed this behavior anywhere else for the past 25 years. I
won't be so confident that the other compilers perform the same optimization
(at least at level O1), exactly because of all the Fortran 66/77 legacy code
the Fortran community uses...


> This "breakage" happens in principle for all optimization levels (-O1, -O2,
> ...). However, if "iei8ei"/"iei4ei" and "program gfortran_debug" are in the
> same file, inlining and other optimizations happen such that the program
> happens to work by chance for -O2/-O3.
> 
> 
> Work-around solutions: Use -O0
Well, we do want a first (i.e. considered as safe) level of optimization...


> or make "inte" VOLATILE.
This seems an interesting path. I am just wondering about computing efficiency
then, but since this avoids making copies out or in the subroutine, this might
be the solution.


> [The program is then
> still formally wrong, but should work.]
> 
> 
> The better change is to change the call to:
>   call iei4ei((in4),in4)
>   call iei8ei((in8),in8)
> That will force the generation of a temporary variable in the caller, which
> makes this part of the program valid.

We definitely want to avoid this kind of requirement when calling subroutines,
this is error prone. If we have to work with a copy, the ideal would be to
factorize it in the subroutine, which is already done...


> (You still have the issue of passing an
> INTEGER(4) to an INTEGER(1)

This subroutine is part of our low-level set of subroutines (here: IEEE <->
EEEI byte swapping), which have to be as simple and efficient as possible (they
can be used on large amount of data). Fortran 77 is pretty well suited for
this.


> and misuse of EQUIVALENCE.)
EQUIVALENCE was just used for the debugging messages, it is not used in our
real code.


> (The "()" seems to be enough to fix the program; I don't know why it didn't
> seem to fix the issue when I wrote comment 1.)
> 
> 
> Alternatively, you can add to both arguments of "iei4ei" and "iei8ei" the
> TARGET attribute - in that case the compiler knows that the arguments may be
> storage associated each other. However, Fortran then requires an explicit
> interface. (This will be difficult as you pass an integer(kind=4) to an
> integer(kind=1), which is invalid.)

Indeed, we can not use explicit interfaces in this context.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (5 preceding siblings ...)
  2012-01-05 10:44 ` bardeau at iram dot fr
@ 2012-01-05 14:27 ` burnus at gcc dot gnu.org
  2012-01-08 11:20 ` tkoenig at gcc dot gnu.org
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: burnus at gcc dot gnu.org @ 2012-01-05 14:27 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

--- Comment #7 from Tobias Burnus <burnus at gcc dot gnu.org> 2012-01-05 14:26:25 UTC ---
(In reply to comment #6)
> > Fortran code is invalid.
> This code is like it is since its first commit on 11-Jun-93

This does not mean that was and/or is valid. Newer compilers tend to optimize
more aggressively than older.


> I still do think there is a problem with gfortran, because 1) it is the only
> one which breaks this simple code regarding our 25 years experience, and 2)
> because it randomly breaks it depending on the architecture and options.

Well, as long as there is no valid program which breaks, I believe that
gfortran does not have a bug (with regards to the this problem report).

In particular, as Steve quoted in comment 2 the 12.4.1.7 guarantees that
nontarget/nonpointer arguments either do not alias or are not modified. With
this in mind, let's look at the generated assembler (compile with "-S" to
generate the assembler file).

If one looks at the assembler for

subroutine iei4ei(inpu,oupu)
  integer(kind=1) :: inpu(4)
  integer(kind=1) :: oupu(4)
  integer(kind=1) :: inte(4)
  inte(:) = inpu(:)
  oupu(4) = inte(1)
  oupu(3) = inte(2)
  oupu(2) = inte(3)
  oupu(1) = inte(4)
end subroutine iei4ei

one gets with -O1 the following (i386-Linux):

.LFB0:
    subl    $8, %esp ! Make space on the stack for 8 byte
.LCFI0:
    movl    %ebx, (%esp)   ! Save %ebx register on the stack
    movl    %esi, 4(%esp)  ! Save %esi register on the stack
.LCFI1:
    movl    12(%esp), %esi ! %esi = addr of inpu
    movl    16(%esp), %ebx ! %ebx = addr of outpu
    movzbl    1(%esi), %ecx  ! %ecx = inpu(2)  ! (zero-extended load)
    movzbl    2(%esi), %edx  ! %edx = inpu(3)  ! (zero-extended load)
    movzbl    3(%esi), %eax  ! %ecx = inpu(4)  ! (zero-extended load)
    movb    %al, (%ebx)    ! outpu(1) = inpu(4) ! al == lowest byte of eax
    movzbl    (%esi), %eax   ! %eax = inpu(1)
    movb    %al, 3(%ebx)   ! outpu(4) = inpu(1)
    movb    %cl, 2(%ebx)   ! outpu(3) = inpu(2)
    movb    %dl, 1(%ebx)   ! outpu(2) = inpu(3)
    movl    (%esp), %ebx  ! Restore ebx register
    movl    4(%esp), %esi ! Restore esi register
    addl    $8, %esp      ! Free the allocated stack
.LCFI2:
    ret                   ! Return


With x86-64-Linux, the assembler is as follows (again with -O1):

.LFB0:
        movzbl  1(%rdi), %ecx  ! ecx = inpu(2)
        movzbl  2(%rdi), %edx  ! edx = inpu(3)
        movzbl  3(%rdi), %eax  ! eax = inpu(4)
        movzbl  (%rdi), %edi   ! edi = inpu(1)
        movb    %dil, 3(%rsi)  ! outpu(4) = inpu(3)
        movb    %cl, 2(%rsi)   ! outpu(3) = inpu(2)
        movb    %dl, 1(%rsi)   ! outpu(2) = inpu(3)
        movb    %al, (%rsi)    ! outpu(1) = inpu(4)
        ret

Thus, it is not surprising that it works with x86-64-Linux and that it fails
with i386-Linux. However, both assembler outputs look perfectly valid - only
that the second version also works if the arguments alias while the first one
does not.


For completeness, ifort 11.1 (ia32) generates with -O2 the code:

        pushl     %edi             ! Save %edi on the stack
        pushl     %esi             ! Save %eds on the stack
        pushl     %ebx             ! Save %ebx on the stack
        movl      16(%esp), %eax          ! eax = inpu
        movl      20(%esp), %esi          ! esi = outpu
        movzbl    (%eax), %edx            ! edx = inpu(1)
        movzbl    1(%eax), %ecx           ! ecx = inpu(2)
        movzbl    2(%eax), %ebx           ! ebx = inpu(3)
        movzbl    3(%eax), %eax           ! eax = inpu(4)
        movb      %dl, iei4ei_$INTE.0.1   ! inte(1) = dl(1)
        movb      %al, (%esi)             ! outpu(1) = inpu(4)
        movb      %cl, 1+iei4ei_$INTE.0.1 ! inte(2) = dl(2)
        movb      %dl, 3(%esi)            ! outpu(4) = inpu(1)
        movb      %cl, 2(%esi)            ! outpu(3) = inpu(2)
        movb      %bl, 2+iei4ei_$INTE.0.1 ! inte(3) = dl(3)
        movb      %al, 3+iei4ei_$INTE.0.1 ! inte(4) = dl(4)
        movb      %bl, 1(%esi)     ! outpu(2) = inpu(3)
        popl      %ebx             ! Restore %ebx
        popl      %esi             ! Restore %esi
        popl      %edi             ! Restore %edi
        ret                        ! Return


Thus, in principle ICC does the same, except that it the generated assembler is
slightly differed such that it works without running into the alias issues.
(I wonder why "ifort" does not optimize the "inte = inpu" away as it is never
used in the assembler.)


> We have never observed this behavior anywhere else for the past 25 years. I
> won't be so confident that the other compilers perform the same optimization
> (at least at level O1), exactly because of all the Fortran 66/77 legacy code
> the Fortran community uses...

I think any well-optimizing compiler takes into account that any pair of
nontarget, nonpointer arguments do not alias (if one of them gets modified).
The C equivalent is that the pointer arguments have the "restrict" attribute.
Thus, unless the compiler is old or not well optimizing, a similar optimization
should be done by other compilers.

Whether that causes alias issues or not (for a given program) depends on the
generated assembler instructions. As the three versions above show, it happens
that only GCC's i386 assembler exposes the alias issues while Intel's version
and GCC's x86-64 version do not. With a slightly different register allocation,
the situation could be different.


> > or make "inte" VOLATILE.
> This seems an interesting path. I am just wondering about computing efficiency
> then, but since this avoids making copies out or in the subroutine, this might
> be the solution.

Well, I think it should not be too bad, though more memory reads are required.


I think the better solution is to mark the two arguments as possibly aliasing
using the TARGET attribute. However, that only works if you do not have the
caller and the callee in the same file - otherwise some compilers will warn or
print an error that an explicit interface is required.

For instance, gfortran or NAG will print an error - while "ifort -warn all"
will warn. (One could argue that gfortran and NAG should only warn, however, it
is always difficult to decide what to allow as vendor extension. The standard
simply states that an explicit interface is required with TARGET. Additionally,
if the caller does not know certain attributes, it might generate wrong code.
Especially in obvious cases like VALUE, if a compiler only warns, users might
miss/ignore the warning and get wrong results [e.g. ifort only warns and not
even with default options].)


> > (You still have the issue of passing an
> > INTEGER(4) to an INTEGER(1)
> 
> This subroutine is part of our low-level set of subroutines (here: IEEE <->
> EEEI byte swapping), which have to be as simple and efficient as possible
> (they can be used on large amount of data).

I do not think that the different integer kinds cause a problem in practice.
Still it's invalid and might cause some trouble in particular cases.

For EQUIVALENCE, the situation is similar - albeit the chance of getting into
trouble is higher. As the elements of equivalence are of different type, the
compiler might do some optimizations which break assumptions that setting one
equivalenced variable will modify the bitpattern of the other.

That's the same with C's union. With -fstrict-aliasing (enabled with -O2), the
compiler does type-based analysis [see -fstrict-aliasing in the GCC manual].


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (6 preceding siblings ...)
  2012-01-05 14:27 ` burnus at gcc dot gnu.org
@ 2012-01-08 11:20 ` tkoenig at gcc dot gnu.org
  2012-01-08 17:04 ` sgk at troutmask dot apl.washington.edu
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: tkoenig at gcc dot gnu.org @ 2012-01-08 11:20 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

Thomas Koenig <tkoenig at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |tkoenig at gcc dot gnu.org

--- Comment #8 from Thomas Koenig <tkoenig at gcc dot gnu.org> 2012-01-08 11:20:02 UTC ---
Should we close this one as INVALID?


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (7 preceding siblings ...)
  2012-01-08 11:20 ` tkoenig at gcc dot gnu.org
@ 2012-01-08 17:04 ` sgk at troutmask dot apl.washington.edu
  2012-01-08 17:37 ` tkoenig at gcc dot gnu.org
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: sgk at troutmask dot apl.washington.edu @ 2012-01-08 17:04 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

--- Comment #9 from Steve Kargl <sgk at troutmask dot apl.washington.edu> 2012-01-08 17:03:41 UTC ---
On Sun, Jan 08, 2012 at 11:20:02AM +0000, tkoenig at gcc dot gnu.org wrote:
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638
> 
> Thomas Koenig <tkoenig at gcc dot gnu.org> changed:
> 
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>                  CC|                            |tkoenig at gcc dot gnu.org
> 
> --- Comment #8 from Thomas Koenig <tkoenig at gcc dot gnu.org> 2012-01-08 11:20:02 UTC ---
> Should we close this one as INVALID?
> 

Yes.  I just have not gotten around to doing it.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (8 preceding siblings ...)
  2012-01-08 17:04 ` sgk at troutmask dot apl.washington.edu
@ 2012-01-08 17:37 ` tkoenig at gcc dot gnu.org
  2012-01-09  9:20 ` bardeau at iram dot fr
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: tkoenig at gcc dot gnu.org @ 2012-01-08 17:37 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

Thomas Koenig <tkoenig at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|                            |INVALID

--- Comment #10 from Thomas Koenig <tkoenig at gcc dot gnu.org> 2012-01-08 17:36:19 UTC ---
As discussed, gfortran does the Right Thing here,
and disabling this optimization would slow down
other programs.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (9 preceding siblings ...)
  2012-01-08 17:37 ` tkoenig at gcc dot gnu.org
@ 2012-01-09  9:20 ` bardeau at iram dot fr
  2012-01-09  9:24 ` bardeau at iram dot fr
  2012-01-09 10:03 ` burnus at gcc dot gnu.org
  12 siblings, 0 replies; 14+ messages in thread
From: bardeau at iram dot fr @ 2012-01-09  9:20 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

Sebastien Bardeau <bardeau at iram dot fr> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
  Attachment #26153|0                           |1
        is obsolete|                            |

--- Comment #11 from Sebastien Bardeau <bardeau at iram dot fr> 2012-01-09 09:20:34 UTC ---
Created attachment 26278
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=26278
Other program which fails with -O flag under 32 bits systems


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (10 preceding siblings ...)
  2012-01-09  9:20 ` bardeau at iram dot fr
@ 2012-01-09  9:24 ` bardeau at iram dot fr
  2012-01-09 10:03 ` burnus at gcc dot gnu.org
  12 siblings, 0 replies; 14+ messages in thread
From: bardeau at iram dot fr @ 2012-01-09  9:24 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

--- Comment #12 from Sebastien Bardeau <bardeau at iram dot fr> 2012-01-09 09:23:41 UTC ---
Dear Tobias,

many thanks for your help and for the many alternatives you gave us. We are
still discussing which one is the best to choose in our context, but at least
we have several solutions to this problem.

A final word: in the new version of the attached program (which also fails with
optimization) I removed as much invalid statements as I could. Only the
"12.4.1.7 restrictions" are still broken, of course. I am surprised to see that
none of the compilers I tested (gfortran, ifort, g95) complain about the fact
that the same variable is used as both intent(in) and intent(out) variable.
Shouldn't it be at least a warning?

And yes, this bug ticket can be closed...


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call
  2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
                   ` (11 preceding siblings ...)
  2012-01-09  9:24 ` bardeau at iram dot fr
@ 2012-01-09 10:03 ` burnus at gcc dot gnu.org
  12 siblings, 0 replies; 14+ messages in thread
From: burnus at gcc dot gnu.org @ 2012-01-09 10:03 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51638

--- Comment #13 from Tobias Burnus <burnus at gcc dot gnu.org> 2012-01-09 10:01:59 UTC ---
(In reply to comment #12)
> I am surprised to see that none of the compilers I tested (gfortran, ifort,
> g95) complain about the fact that the same variable is used as both
> intent(in) and intent(out) variable. Shouldn't it be at least a warning?


gfortran with -Waliasing (or -Wall) actually warns - but not by default:

  call iei4ei(in4,in4)
              1
Warning: Same actual argument associated with INTENT(IN) argument 'inpu' and
INTENT(OUT) argument 'oupu' at (1)


The argument agains warning by default is that one can write perfectly valid
code such as:

call iei4ei(in4, in4, false)
contains
subroutine iei4ei (out, in, mod)
  integer :: out, in
  logical :: mod
  if (mod)
    out = 5
end subroutine ie4ei


Nevertheless, one could think of warning by default.


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-01-09 10:03 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-20 15:32 [Bug fortran/51638] New: gfortran optimization breaks a single variable used as both input and output for subroutine call bardeau at iram dot fr
2011-12-20 17:31 ` [Bug fortran/51638] " burnus at gcc dot gnu.org
2011-12-20 17:46 ` kargl at gcc dot gnu.org
2012-01-03 10:21 ` bardeau at iram dot fr
2012-01-03 19:05 ` kargl at gcc dot gnu.org
2012-01-04  8:46 ` burnus at gcc dot gnu.org
2012-01-05 10:44 ` bardeau at iram dot fr
2012-01-05 14:27 ` burnus at gcc dot gnu.org
2012-01-08 11:20 ` tkoenig at gcc dot gnu.org
2012-01-08 17:04 ` sgk at troutmask dot apl.washington.edu
2012-01-08 17:37 ` tkoenig at gcc dot gnu.org
2012-01-09  9:20 ` bardeau at iram dot fr
2012-01-09  9:24 ` bardeau at iram dot fr
2012-01-09 10:03 ` burnus at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).