PR# 18785 REAL_64 constant with value 0.0 produces uncompilable C code on Linux 32-bit

Problem Report Summary
Submitter: prestoat2000
Category: Compiler
Priority: High
Date: 2013/12/23
Class: Bug
Severity: Critical
Number: 18785
Release: 13.11.93542
Confidential: No
Status: Closed
Responsible:
Environment: Linux x86 32-bit
Synopsis: REAL_64 constant with value 0.0 produces uncompilable C code on Linux 32-bit

Description
A class with a declaration

   angle: REAL_64 = 0.0

causes generation of incorrect C code (and the C code won't compile either).
The generated C code for the above declaration is

/* {TEST}.angle */
EIF_TYPED_VALUE F859_6932 (EIF_REFERENCE Current)
{
	EIF_TYPED_VALUE r;
	r.type = SK_REAL64;
	r.it_r8 = (EIF_REAL_64) -Infinity.;  <==== Wrong
	return r;
}

-Infinity should be 0.

This only happens with the Red Hat Enterprise Linux 32-bit compiler.  The
64-bit version generates the correct C code.  The Solaris SPARC and Solaris x86
versions also generate correct C code (for both 32-bit and 64-bit versions).

Added test ccomp089 for this bug.

We cannot upgrade to 13.11 until this is resolved.
To Reproduce
Run eweasel test ccomp089.
Problem Report Interactions
From:prestoat2000    Date:2014/01/27    Status: Closed    Download   
The 64-bit Linux release seems to be fine (possibly just luck with the
C compiler optimizer?).  Thanks for addressing this.

From:manus_eiffel    Date:2014/01/27    Download   
I put the runtime for the 32-bit version at:

ftp://beta:beta57@ftp.eiffel.com/13.11/runtime_suncc_13.11.tgz

Let me know if you also need the 64-bit version.

From:prestoat2000    Date:2014/01/27    Download   
I finally got around to installing the new version (with the run-time fix
in place).  When I precompile EiffelBase, the C code all compiles but the
link fails with:

/home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/lib/libwkbench.a(interp.o): In function `interpret':
interp.c:(.text+0xd39e): undefined reference to `__divdi3'
interp.c:(.text+0xd46c): undefined reference to `__udivdi3'
interp.c:(.text+0xd952): undefined reference to `__moddi3'
interp.c:(.text+0xdbf4): undefined reference to `__umoddi3'
/home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/lib/libwkbench.a(wmisc.o): In function `eif_sleep':
misc.c:(.text+0x266): undefined reference to `__divdi3'
misc.c:(.text+0x28b): undefined reference to `__moddi3'

Looks like the runtime was compiled with gcc instead of cc.

Can you give me a new version?  I think I just need the contents of
$ISE_EIFFEL/studio/spec/linux-x86/lib where runtime is compiled with Sun cc.

From:manus_eiffel    Date:2014/01/13    Download   
I've put a fixed release of 13.11 on your ftp account at Eiffel Software. This is not a new version, I've merely manually patched the runtime and reran the delivery process against the same version of the generated code.

From:manus_eiffel    Date:2014/01/08    Download   
Fixed added in rev#93937.

From:manus_eiffel    Date:2014/01/08    Download   
I do not have an explanation. I'll redo a 13.11 delivery with this fix included and hopefully this will work properly for you too.

From:prestoat2000    Date:2014/01/08    Download   
With the runtime with the union fix, the test case correctly prints 0.

So we are left with one mystery:  why did the original runtime produce
correct results for you (0) but wrong for me (-Infinity).

From:manus_eiffel    Date:2014/01/08    Download   
It does but so was my previous fix and although it changed what you observed it was still broken. I'll compile a runtime with this union fix included and we will see.

From:prestoat2000    Date:2014/01/08    Download   
I would like to see a version of libfinalized.a where you have added
printf statements after the call to `ieee_init' to print the values of
eif_real_64_negative_infinity, etc that are set by ieee_init.
Also, perhaps some printf statements in `c_buffero_outr64' (in out.c) to print
these same values, plus the value of `d'.  Then we see what is different.

Unless you have a better idea.

From:prestoat2000    Date:2014/01/08    Download   
I would be interested to know whether the attached file inline_bug_2.c
produces correct results when you compile it with your gcc version.
I changed ieee_init to use a union.

Both gcc and cc produce correct results with both -m32 and -m64 on
Solaris SPARC, Solaris x86 and Red Hat Linux.

Attachment: inline_bug_2.c     Size:1595
From:manus_eiffel    Date:2014/01/08    Download   
Yes, indeed I know that and I should implement this properly. But this still doesn't tell us why it works for me and not for you as this is exactly the same code we are running. This is very peculiar.

From:prestoat2000    Date:2014/01/08    Download   
I think that the following may explain why your gcc is producing code that
doesn't work.  The code in ieee_init may be violating strict aliasing rules
and unless code is compiled with -fno-strict-aliasing the results may be
undefined.  See

   http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html

Apologies in advance if you already know about this and it is not relevant.
They suggest using a union, which although is not technically allowed
seems to work with all major compilers.

From:prestoat2000    Date:2014/01/08    Download   
I compared the md5sum values with my versions.  All were identical except
for libmtwkbench.a (because I was using the version with the "volatile"
change).  I reverted to the one that matches the md5sum value you sent
(the original GPL version).  Of course, that didn't make any difference
because only libfinalized.a is being linked in and its md5sum value
matches your value.

Here's my results, in case you see something wrong:

/bin/rm -f test
gcc -o test -O3 -pipe -march=i686 -D_GNU_SOURCE -m32  -DEIF_IEEE_BEHAVIOR -I"/home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/include" -I.  -m32    C14/Cobj14.o C13/Cobj13.o C12/Cobj12.o C11/Cobj11.o C10/Cobj10.o C9/Cobj9.o C8/Cobj8.o C7/Cobj7.o C6/Cobj6.o C5/Cobj5.o C4/Cobj4.o C3/Cobj3.o C2/Cobj2.o C1/Cobj1.o E2/Eobj2.o E1/eref.o E1/epoly.o E1/esize.o E1/eplug.o E1/eskelet.o E1/enames.o E1/evisib.o E1/ececil.o E1/einit.o E1/eparents.o E1/emain.o \
		  "/home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/lib/libfinalized.a" -lm
hilbert 151% 
hilbert 151
....
Output truncated, Click download to get the full message

From:manus_eiffel    Date:2014/01/08    Download   
Unfortunately it prints 0 for me.

This is compiled against the runtime and header files of 
ISE EiffelStudio version 13.11.9.3542 GPL Edition - linux-x86

The runtime are:
-rw-r--r-- 1 manus users 429216 Nov 26 01:26 libfinalized.a
-rwxr-xr-x 1 manus users 388692 Nov 26 01:26 libfinalized.so*
-rw-r--r-- 1 manus users 506334 Nov 26 01:26 libmtfinalized.a
-rwxr-xr-x 1 manus users 464083 Nov 26 01:26 libmtfinalized.so*
-rw-r--r-- 1 manus users 711008 Nov 26 01:26 libmtwkbench.a
-rwxr-xr-x 1 manus users 654779 Nov 26 01:26 libmtwkbench.so*
-rw-r--r-- 1 manus users 627194 Nov 26 01:26 libwkbench.a
-rwxr-xr-x 1 manus users 574987 Nov 26 01:26 libwkbench.so*

ubuntu804 [Manu] : md5sum *
5a0d1717177c8ef04ae1e9ff04b7d860  libfinalized.a
cd67f2a6f1d8941309ab0f7a15df676d  libfinalized.so
1332f9d2085d1a02f9675e0bfefd2f6e  libmtfinalized.a
5e26db2afbecf08b4522696f5f57cd34  libmtfinalized.so
fd7206b97c6eff3965d32d9d1c276da0  libmtwkbench.a
220af722eb837704e980637c6b71cd8b  libmtwkbench.so
e024db84076
....
Output truncated, Click download to get the full message

From:prestoat2000    Date:2014/01/08    Download   
I thought I had attached it.  Here it is.

Attachment: F_code.tar.bz2     Size:218815
From:manus_eiffel    Date:2014/01/08    Download   
The attachment is missing.

From:prestoat2000    Date:2014/01/08    Download   
I'm getting a little confused too.  I have attached the F_code directory
from the test case.  Compiling the code with Sun cc on Solaris x86
produces an executable that works correctly (prints 0).  Compiling the code
with gcc on Linux x86 (with CFLAGS set to "-pipe -march=i686 -D_GNU_SOURCE -m32")
and linking with 

   /home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/lib/libfinalized.a

(where libfinalized.a is from GPL version) produces an executable that
instead prints -Infinity.

Let me know if this wasn't what you were asking for.

From:manus_eiffel    Date:2014/01/07    Download   
Actually I'm now getting very confused with all those different behaviors. The compiler I'm using is the one that was compiled with the shipped run-time since we run the PorterPackage.

To make things easier, could we use the development version of EiffelStudio (i.e. 14.05) to debug this and then we can retrofit to 13.11? To begin with, I'd like if this is possible that you write a program under Solaris that prints values correctly, take the uncompiled F_code of that program and compile it under Linux 32-bit and ensure that it does not work properly.

I can then take this F_code and the accompanying Eiffel code and test this on my locale machine.

Would this be possible?

From:prestoat2000    Date:2014/01/07    Download   
It didn't fix the problem.  I linked the compiler with the runtime with the
volatile workaround and then compiled the test case.  It compiled fine,
but printed -Infinity instead of 0 when executed (it is supposed to print 0
because angle: REAL_64 = 0.0.  

I had already modified the C code for {REAL_VALUE_I}.generate to print
out the values of positive and negative infinity and NaN.  With this latest
runtime, the output is

eif_real_64_negative_infinity is inf
eif_real_64_positive is inf
eif_real_64_nan is inf

Previously, all of these values were 0.000000.


From:manus_eiffel    Date:2014/01/07    Download   
I can disable the optimization by adding a volatile at the right place in ieee_init. I'll adopt this for a solution since it does not cost in performance.

However, if I compile the following program:

class A
create
  make
feature
  make
    do
       io.put_double (d)
       io.put_new_line
       io.put_double ({REAL_64}.negative_infinity)
       io.put_new_line
    end

   t: REAL_64 = 0.0
end

and then compile it (first it compiles just fine for me), second when executed it prints 0 and -Infinity as expected.

I'm going to send you a runtime with the volatile fix in it and see if it solves the issue or not.

From:manus_eiffel    Date:2014/01/07    Download   
Here is our current output:

ubuntu804 [Manu] : gcc -O3 test.c -I $ISE_EIFFEL/studio/spec/linux-x86/include/
ubuntu804 [Manu] : ./a.out 
Negative infinity 32 = 0.000000
Positive infinity 32 = 0.000000
Not a number 32 = 0.000000
Negative infinity 64 = 0.000000
Positive infinity 64 = 0.000000
Not a number 64 = 0.000000

From:prestoat2000    Date:2014/01/07    Download   
Please try compiling and executing the attached test program on Linux.
For me, it produces the correct results:

Negative infinity 32 = -inf
Positive infinity 32 = inf
Not a number 32 = nan
Negative infinity 64 = -inf
Positive infinity 64 = inf
Not a number 64 = nan

I'm curious to see whether it produces correct results for you with -O3.

I used the following command line:

  gcc -Wall -O3 -I /home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/include -o inline_bug -m32 inline_bug.c


Attachment: inline_bug.c     Size:1521
From:prestoat2000    Date:2014/01/07    Download   
I am including this summary of what we have discovered so far, though most
of the communication was done directly via e-mail with Manu.

After considerable experimentation, it appears that this is a bug in the
gcc optimizer.  When the run-time is compiled with -O0, a compiler linked
with that runtime produces correct C code.  When the runtime is compiled with
-O3, a compiler linked with that runtime produces wrong C code.
Note that this only happens with the gcc version Manu is currently using:

   gcc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)

With my version (gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)), it seems to
generate correct C code with optimization level -O3.

Since the runtime for 7.3 does not have this problem, I wonder whether 
your compiler was updated to a newer version after 7.3 was released.  I also
do not understand why you cannot reproduce this problem, since the 
file libmtwkbench.a seems to have incorrect code for ieee_init
(inlined into eif_rtinit).

I have attached the log
....
Output truncated, Click download to get the full message

Attachment: gdb.log     Size:3252
From:manus_eiffel    Date:2013/12/31    Download   
Let's touch base Thursday morning and figure out a way to debug this.

From:prestoat2000    Date:2013/12/31    Download   
So where do we go from here?  Perhaps you could tell me how to debug this with
a workbench version of estudio.  I suppose it could be a bug specific to
Red Hat Enterprise Linux 6.5 (but we still have the 6.4 kernel), though that
doesn't seem likely either.  I will be back to work on Thursday January 2.


From:manus_eiffel    Date:2013/12/31    Download   
The test eweasel test#ccomp089 works just fine for me. All my locale are set to C. I'm note sure what would cause this.

From:prestoat2000    Date:2013/12/24    Download   
Now I can't seem to get correct C code generated for a class with a
constant attribute

   angle: REAL_64 = 0.0

Not sure why it seemed to work with LANG set to "C" yesterday.

I have tried setting LANG to "C", setting LC_ALL to "C", unsetting LANG
and all the LC_* environment variables.  In all cases, the compiler generates
"-Infinity." instead of "0." for the constant attribute above.  So unless
you can give me some magic incantation, this release is unusable for us
(on 32-bit Linux, but we now have some 32-bit Linux programs in production).

We do have some REAL_64 constants with value 0.0 in our source code, so
this isn't just a theoretical concern.  For example, I cannot freeze our big
graphical application with 13.11 Linux 32-bit compiler due to this problem.

I will be on vacation after today until January 2.  I hope we can resolve this
after the holidays.

From:prestoat2000    Date:2013/12/23    Download   
I'm surprised that the underlying parsing tools would produce -Infinity
for "0.0" with LANG set to en_US.UTF-8.  If it isn't too much trouble, could
you point me to the routine or routines you are calling to do the conversion
of the "0.0" string to a numeric value (double)?  I want to understand this
a little better.

From:manus_eiffel    Date:2013/12/23    Download   
This has been a long standing issue with European systems. We just need to not rely on the underlying C parsing tools for floating number in our Eiffel parser. I'll try again to see if we can avoid this.

From:prestoat2000    Date:2013/12/23    Download   
Your guess is correct:

fermi.isi.edu 26% echo $LANG
en_US.UTF-8

If I do

   setenv LANG "C"

then it works.  With the 64-bit Linux compiler, it works correctly 
regardless of whether LANG is set to "en_US.UTF-8" or "C".


From:manus_eiffel    Date:2013/12/23    Status: Analyzed    Download   
Could you check your LANG variable? I'm guessing it is not set to C and that some language specific translation turns the 0.0 into the -Infinity number.