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.)

Reply via email to