This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug fortran/51638] gfortran optimization breaks a single variable used as both input and output for subroutine call


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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]