Hi, I've cross compiled CLASSPATH on an S3C2410 ARM920 architecture. I've also compiled SableVM on it. When I run this code : float a = 1.5f; float b = 26.524f; float c = 1.11E11f; float d = a + b; int e = (int)d; System.Out.println("a is "+a); System.Out.println("b is "+b); System.Out.println("d is "+d); System.Out.println("e is "+e); I get wrong result for float (and double, I've tried them too) output (the output is totally garbaged), but the number show as e is correct. I think the problem seem to be in _dtoa function in fdlibm. ARM are very strict on memory alignment, and is little endian. PS: The same code works on x86. Output is (This is the input => a=1.5f,b=26.524f,c=1.11E11f): ---------- float test ---------- a=1.000007 b=37.63494 c=1.1100000256E11 (int)a =1 (int)b =26 (int)c =2147483647 a+b=39.034943 a+c=1.1100000256E11 a-b=-36.034943 a-c=-1.1100000256E11 (int)(a+b)=28 (int)(a+c)=2147483647 (int)(a-b)=-25 (int)(a-c)=-2147483648 a*b=4:.89693; a*c=1.66500007936E11 a/b=0.02 a/c=28.7935:8 (int)(a*b)=39 (int)(a*c)=2147483647 (int)(a/b)=0 (int)(a/c)=17
Unfortunately, most of us don't have an ARM machine to test this on. However, looking at the fdlibm code, there's #ifdefs for ARM in ieeefp.h, and some more in atoi.c (Pack_32?) so it could be a build issue. I'd try playing around with the #ifdefs. If you find something, please post it here and let us know!
This was originally reported to http://sablevm.org/bugs/74
I'm not entirely sure if this is a general fdlibm problem, or specific to dtoa. Could you test this? I've attached a little test-case which might be an indicator, checking the output of a fdlibm function with the expected value.
Tested your class, and I've added some other tests too. \/ Below is Java File \/ import java.io.*; public class Cos { public static double div(double a, double b){ return a/b; } public static void main(String[] args){ double a = Math.cos(Math.PI); double b = -1.0; System.out.println("a equals b:"+(a == b)); System.out.println("a:"+a); System.out.println("b:"+b); a = 1.002; b = 0.; System.out.println("a div b:" + div(a,b)); System.out.println("a:"+a); System.out.println("b:"+b); a = 8.8888888E21; b = 5.5555555E-21; System.out.println("a:"+a); System.out.println("b:"+b); } } \/ And this is the output \/ a equals b:true a:-1.0 b:-1.0 a div b:Infinity a:2.002:958353678385 b:0.0 a:0.0000000000026E21 b:Q.0E-21
Thanks for the follow-up. Strange. Looks like you're right that this seems to be in dtoa.c, and not a general fdlibm thing. Could you provide output of Float.floatToRawIntBits() and Double.doubleToRawLongBits() for the different input/output values? This would be helpful.
the test class: --------------- import java.io.*; public class Cos { public static double div(double a, double b){ return a/b; } public static void main(String[] args){ double a = Math.cos(Math.PI); double b = -1.0; System.out.println("a equals b:"+(a == b)); System.out.println("a:"+a); System.out.println("b:"+b); System.out.println("Double.doubleToLongBits(a):"+Double.doubleToLongBits(a)); System.out.println("Double.doubleToLongBits(a):"+Double.doubleToLongBits(a)); System.out.println("Double.doubleToRawLongBits(b):"+Double.doubleToRawLongBits(b)); System.out.println("Double.doubleToRawLongBits(b):"+Double.doubleToRawLongBits(b)); System.out.println("Float.floatToRawIntBits((float)a):"+Float.floatToRawIntBits((float)a)); System.out.println("Float.floatToIntBits((float)a):"+Float.floatToIntBits((float)a)); System.out.println("Float.floatToRawIntBits((float)b):"+Float.floatToRawIntBits((float)b)); System.out.println("Float.floatToIntBits((float)b):"+Float.floatToIntBits((float)b)); a = 1.002; b = 0.; System.out.println("a div b:" + div(a,b)); System.out.println("a:"+a); System.out.println("b:"+b); System.out.println("Double.doubleToLongBits(a):"+Double.doubleToLongBits(a)); System.out.println("Double.doubleToLongBits(a):"+Double.doubleToLongBits(a)); System.out.println("Double.doubleToRawLongBits(b):"+Double.doubleToRawLongBits(b)); System.out.println("Double.doubleToRawLongBits(b):"+Double.doubleToRawLongBits(b)); System.out.println("Float.floatToRawIntBits((float)a):"+Float.floatToRawIntBits((float)a)); System.out.println("Float.floatToIntBits((float)a):"+Float.floatToIntBits((float)a)); System.out.println("Float.floatToRawIntBits((float)b):"+Float.floatToRawIntBits((float)b)); System.out.println("Float.floatToIntBits((float)b):"+Float.floatToIntBits((float)b)); a = 8.8888888E21; b = 5.5555555E-21; System.out.println("a:"+a); System.out.println("b:"+b); System.out.println("Double.doubleToLongBits(a):"+Double.doubleToLongBits(a)); System.out.println("Double.doubleToLongBits(a):"+Double.doubleToLongBits(a)); System.out.println("Double.doubleToRawLongBits(b):"+Double.doubleToRawLongBits(b)); System.out.println("Double.doubleToRawLongBits(b):"+Double.doubleToRawLongBits(b)); System.out.println("Float.floatToRawIntBits((float)a):"+Float.floatToRawIntBits((float)a)); System.out.println("Float.floatToIntBits((float)a):"+Float.floatToIntBits((float)a)); System.out.println("Float.floatToRawIntBits((float)b):"+Float.floatToRawIntBits((float)b)); System.out.println("Float.floatToIntBits((float)b):"+Float.floatToIntBits((float)b)); } } Result : -------- a equals b:true a:-1.0 b:-1.0 Double.doubleToLongBits(a):3220176896 Double.doubleToLongBits(a):3220176896 Double.doubleToRawLongBits(b):3220176896 Double.doubleToRawLongBits(b):3220176896 Float.floatToRawIntBits((float)a):-1082130432 Float.floatToIntBits((float)a):-1082130432 Float.floatToRawIntBits((float)b):-1082130432 Float.floatToIntBits((float)b):-1082130432 a div b:Infinity a:2.002:958353678385 b:0.0 Double.doubleToLongBits(a):1072695345 Double.doubleToLongBits(a):1072695345 Double.doubleToRawLongBits(b):0 Double.doubleToRawLongBits(b):0 Float.floatToRawIntBits((float)a):1065369993 Float.floatToIntBits((float)a):1065369993 Float.floatToRawIntBits((float)b):0 Float.floatToIntBits((float)b):0 a:0.0000000000026E21 b:Q.0E-21 Double.doubleToLongBits(a):1149115873 Double.doubleToLongBits(a):1149115873 Double.doubleToRawLongBits(b):1002060865 Double.doubleToRawLongBits(b):1002060865 Float.floatToRawIntBits((float)a):1676734222 Float.floatToIntBits((float)a):1676734222 Float.floatToRawIntBits((float)b):500294153 Float.floatToIntBits((float)b):500294153 ---------- I hope this will be helpful !
Well.. looking at your values here, it seems like the top and bottom dwords of the Double are getting exchanged, and that the top one is getting set to zero. This could be due to dword ordering, or alignment or both. In any case, I'm not entirely sure the problem is in the Double->ASCII conversion alone. It could be that the SableVM double-arithmetic on this architecture is broken. Or both could be broken.
Okay, this could explain why double are not converted correctly. However float are on a single DWORD, hence it should work with float (which, I guess, are corrects) However, even with float _dtoa doesn't work. Is there a _ftoa method ? Thanks
We have seen somthing similar before. The problem for us was that doubles in tha Java class are stored as big endian. And the conversion did not correctly take into account that the arm has what we call a cross-endianess (i.e the dwords are exchanged). You could check if the bits differ when you store a float value in the class file and if you let it compute at run-time.
This may well be a duplicate of gcc PR 16132. However, to be sure we would need to know: The version of gcc used to compile the code The configuration of gcc The options passed to the compiler.
In ./native/fdlibm/mprec.h I found the following macro definition: /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ #if defined(IEEE_8087) + defined(VAX) #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else #define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ ((unsigned short *)a)[1] = (unsigned short)c, a++) #endif It seems that the else branch is selected when gcc is configured like this: Using built-in specs. Target: arm-elf Configured with: ../gcc-4.0.1/configure --prefix=/home/ton/eft2/installdir --target=arm-elf --with-float=soft --enable-languages=c --enable-threads=posix Thread model: posix gcc version 4.0.1 When running this code: _dtoa(-123.4567, 22, 10, &dec, &sgn, &pp, buf, 1); printf("_dtoa: '%s' %d %d\n",buf,dec,sgn); I get this result: _dtoa: '234566006' 3 1 However, when I hack the StoreInc macro to use the code from the if branch, I get: _dtoa: '1234567' 3 1
For TI OMAP 1710 (~ARM926?) (nokia 770), i have compiled a modified jikes 1.22 with native IEEE754 (with exchanged double dword). I have reproduced the same bug with classpath-0.19 (no soft-float)! Thanks to Torben Nielsen, the bug is gone white the alternate StorInc macro (if branch)! Maybe the special case of IEEE_BIG_ENDIAN with IEEE_BYTES_LITTLE_ENDIAN should be adressed this way (force the little endian StoreInc)!
*** Bug 27142 has been marked as a duplicate of this bug. ***
The comment in the duplicate bug #27142 contains a resolution: "#define Just_16" in native/fdlibm/mprec.h
Looking into this further, the correct solution is to define the Storeinc macro correctly. When Just_16 is defined the Storeinc macro is not used, so the problem does not occur. Now, the reason the Storeinc macro is being set improperly is because IEEE_8087 is not set (mprec.h:103), which is because __IEEE_LITTLE_ENDIAN is not set (mprec.h:53), which is because The conditional used to set big/little endian is incorrect at ieeefp.h:14 #if defined(__arm__) || defined(__thumb__) /* ARM traditionally used big-endian words; and within those words the byte ordering was big or little endian depending upon the target. Modern floating-point formats are naturally ordered; in this case __VFP_FP__ will be defined, even if soft-float. */ #ifdef __VFP_FP__ #ifdef __ARMEL__ #define __IEEE_LITTLE_ENDIAN #else #define __IEEE_BIG_ENDIAN #endif #else #define __IEEE_BIG_ENDIAN #ifdef __ARMEL__ #define __IEEE_BYTES_LITTLE_ENDIAN #endif #endif #endif On my XScale PXA255 little-endian ARM v5TE toolchain, the following are defined during build: __arm__ __ARMEL__ __SOFTFP__ however, neither __VFP_FP__ nor __FPA_FP__ is defined. This patch to ieeefp.h possibly? originated at http://sourceware.org/ml/newlib/2004/msg00046.html.
AFAIK FSF toolchains have never defined __FPA_FP__. If your toolchain is configured to use VFP word ordering then it should be defining __VFP_FP__. If your toolchain is using VFP word ordering but not defining __VFP_FP__ then you have a broken toolchain. All the toolchains I've ever seen (from 3.3 onwards) do this correctly.
Digging deeper into the issue (with a little help from Paul Brook), it turns out that this bug only appears on toolchains compiled with FPA soft/hard float. The correct patch is as follows: --- native/fdlibm/mprec.h.orig 2006-04-17 14:04:49.000000000 -0400 +++ native/fdlibm/mprec.h 2006-04-17 14:05:22.000000000 -0400 @@ -100,7 +100,7 @@ union double_union * An alternative that might be better on some machines is * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ -#if defined(IEEE_8087) + defined(VAX) +#if defined(__IEEE_BYTES_LITTLE_ENDIAN) + defined(IEEE_8087) + defined(VAX) #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else This defines the correct Storeinc macro when using FPA. According to ieeefp.h, when using FPA: #define __IEEE_BIG_ENDIAN #ifdef __ARMEL__ #define __IEEE_BYTES_LITTLE_ENDIAN #endif This patch has been discussed in the past but isn't in the mprec.h included in classpath: http://sourceware.org/ml/newlib/2001/msg00395.html Also, a recently commited fix for this issue is incorrect. It should be reverted in favor of this patch: http://developer.classpath.org/pipermail/classpath-patches/2006-January/000019.html Also note when testing, jikes 1.22 does not produce proper bytecode for floats on ARM (FPA only again?). Some notes at http://sourceforge.net/mailarchive/forum.php?thread_id=10191309&forum_id=43932
Created attachment 11284 [details] patch to mprec.h to fix floats on arm toolchains using fpa
As I wrote the patch which should be reverted... why isn't this patch already included? I just tried it on our ARM machines and it works perfectly. I'll propose a patch to classpath-patches.
Sorry for the long delay, but the SWAP_DOUBLE-patch is required. I have it pending locally for months and we had no problems anymore with all Arm machines we tested on. I'll commit a patch in a minute.
Subject: Bug 22800 CVSROOT: /cvsroot/classpath Module name: classpath Changes by: Christian Thalinger <twisti> 07/04/05 12:41:34 Modified files: . : ChangeLog native/jni/java-lang: java_lang_VMDouble.c Log message: 2007-04-05 Christian Thalinger <twisti@complang.tuwien.ac.at> PR classpath/22800: * native/jni/java-lang/java_lang_VMDouble.c (doubleToLongBits) (doubleToRawLongBits, longBitsToDouble): Swap the byte ordering for little-endian arms without VFP. CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/classpath/ChangeLog?cvsroot=classpath&r1=1.9214&r2=1.9215 http://cvs.savannah.gnu.org/viewcvs/classpath/native/jni/java-lang/java_lang_VMDouble.c?cvsroot=classpath&r1=1.16&r2=1.17
The last commit should fix all remaining problems.
This is still not working for me (arm-iwmmxt-linux-gnueabi). With jamvm-1.45 + gnu-classpath-0.93 and gnu-classpath trunk as of 20070821; using the test from comment #6 I get: a equals b:true a:-1.0 b:-1.0 Double.doubleToLongBits(a):-4616189618054758400 Double.doubleToLongBits(a):-4616189618054758400 Double.doubleToRawLongBits(b):-4616189618054758400 Double.doubleToRawLongBits(b):-4616189618054758400 Float.floatToRawIntBits((float)a):-1082130432 Float.floatToIntBits((float)a):-1082130432 Float.floatToRawIntBits((float)b):-1082130432 Float.floatToIntBits((float)b):-1082130432 jamvm: java_lang_VMDouble.c:430: Java_java_lang_VMDouble_toString: Assertion `least_necessary_precision <= maximal_precision' failed. Aborted zaurus java # Meanwhile with gcj and gij (20070810 + ARM EABI patches) on the same system, I get: a equals b:true a:-1.0 b:-1.0 Double.doubleToLongBits(a):-4616189618054758400 Double.doubleToLongBits(a):-4616189618054758400 Double.doubleToRawLongBits(b):-4616189618054758400 Double.doubleToRawLongBits(b):-4616189618054758400 Float.floatToRawIntBits((float)a):-1082130432 Float.floatToIntBits((float)a):-1082130432 Float.floatToRawIntBits((float)b):-1082130432 Float.floatToIntBits((float)b):-1082130432 a div b:Infinity a:1.002 b:0.0 Double.doubleToLongBits(a):4607191425999272149 Double.doubleToLongBits(a):4607191425999272149 Double.doubleToRawLongBits(b):0 Double.doubleToRawLongBits(b):0 Float.floatToRawIntBits((float)a):1065369993 Float.floatToIntBits((float)a):1065369993 Float.floatToRawIntBits((float)b):0 Float.floatToIntBits((float)b):0 a:8.8888888E21 b:5.5555555E-21 Double.doubleToLongBits(a):4935415097293273796 Double.doubleToLongBits(a):4935415097293273796 Double.doubleToRawLongBits(b):4303818644414190050 Double.doubleToRawLongBits(b):4303818644414190050 Float.floatToRawIntBits((float)a):1676734222 Float.floatToIntBits((float)a):1676734222 Float.floatToRawIntBits((float)b):500294153 Float.floatToIntBits((float)b):500294153 In both cases it is the same bytecode compiled with ecj-3.3
(In reply to comment #23) > This is still not working for me (arm-iwmmxt-linux-gnueabi). With jamvm-1.45 + > gnu-classpath-0.93 and gnu-classpath trunk as of 20070821; using the test from > comment #6 I get: > > a equals b:true > a:-1.0 > b:-1.0 > Double.doubleToLongBits(a):-4616189618054758400 > Double.doubleToLongBits(a):-4616189618054758400 > Double.doubleToRawLongBits(b):-4616189618054758400 > Double.doubleToRawLongBits(b):-4616189618054758400 > Float.floatToRawIntBits((float)a):-1082130432 > Float.floatToIntBits((float)a):-1082130432 > Float.floatToRawIntBits((float)b):-1082130432 > Float.floatToIntBits((float)b):-1082130432 > jamvm: java_lang_VMDouble.c:430: Java_java_lang_VMDouble_toString: Assertion > `least_necessary_precision <= maximal_precision' failed. > Aborted > zaurus java # > > Meanwhile with gcj and gij (20070810 + ARM EABI patches) on the same system, I > get: > a equals b:true > a:-1.0 > b:-1.0 > Double.doubleToLongBits(a):-4616189618054758400 > Double.doubleToLongBits(a):-4616189618054758400 > Double.doubleToRawLongBits(b):-4616189618054758400 > Double.doubleToRawLongBits(b):-4616189618054758400 > Float.floatToRawIntBits((float)a):-1082130432 > Float.floatToIntBits((float)a):-1082130432 > Float.floatToRawIntBits((float)b):-1082130432 > Float.floatToIntBits((float)b):-1082130432 > a div b:Infinity > a:1.002 > b:0.0 > Double.doubleToLongBits(a):4607191425999272149 > Double.doubleToLongBits(a):4607191425999272149 > Double.doubleToRawLongBits(b):0 > Double.doubleToRawLongBits(b):0 > Float.floatToRawIntBits((float)a):1065369993 > Float.floatToIntBits((float)a):1065369993 > Float.floatToRawIntBits((float)b):0 > Float.floatToIntBits((float)b):0 > a:8.8888888E21 > b:5.5555555E-21 > Double.doubleToLongBits(a):4935415097293273796 > Double.doubleToLongBits(a):4935415097293273796 > Double.doubleToRawLongBits(b):4303818644414190050 > Double.doubleToRawLongBits(b):4303818644414190050 > Float.floatToRawIntBits((float)a):1676734222 > Float.floatToIntBits((float)a):1676734222 > Float.floatToRawIntBits((float)b):500294153 > Float.floatToIntBits((float)b):500294153 > > In both cases it is the same bytecode compiled with ecj-3.3 > Actually now I see them both on the same page it looks like a different bug...?
(In reply to comment #24) > Actually now I see them both on the same page it looks like a different bug...? > Confirmed as a different bug. I think it might be http://gcc.gnu.org/bugzilla/show_bug.cgi?id=28570
As you are on EABI, the problem seems to be there. A recent thread on classpath-ml was about EABI with JamVM (http://developer.classpath.org/pipermail/classpath/2007-August/002187.html). CACAO has ARM EABI support. Could you give it a try, as I'm not sure I still have access to our EABI board.
Subject: Re: ARM double to ascii conversion issue --- twisti at complang dot tuwien dot ac dot at <gcc-bugzilla@gcc.gnu.org> wrote: > > > ------- Comment #26 from twisti at complang dot tuwien dot ac dot at > 2007-08-22 11:15 ------- > As you are on EABI, the problem seems to be there. A recent thread on > classpath-ml was about EABI with JamVM > (http://developer.classpath.org/pipermail/classpath/2007-August/002187.html). > > CACAO has ARM EABI support. Could you give it a try, as I'm not sure I still > have access to our EABI board. > I've as I mentioned in the bug #28570 JamVM works with -O0. I haven't had any luck getting CACAO working, I did try to get some help on #cacao but I guess no-one was about. I even sent a couple of patches, cacao is/was not using an EABI compatible cache flush and the javac needed "-bootclasspath @CLASSPATH_CLASSES@". Steve ___________________________________________________________ Want ideas for reducing your carbon footprint? Visit Yahoo! For Good http://uk.promotions.yahoo.com/forgood/environment.html
Sorry, didn't see you on IRC. What patches? Did I miss them? What is/was the problem with cache-flush?
Subject: Re: ARM double to ascii conversion issue --- twisti at complang dot tuwien dot ac dot at <gcc-bugzilla@gcc.gnu.org> wrote: > > > ------- Comment #28 from twisti at complang dot tuwien dot ac dot at > 2007-08-22 11:41 ------- > Sorry, didn't see you on IRC. What patches? Did I miss them? What is/was > the > problem with cache-flush? The current CACAO directly uses the OABI cache_flush syscall which isn't present on a pure EABI system. It should either use __clear_cache() or #ifdef __ARM_EABI__ and use the EABI syscall ABI. One of the patches I sent to the cacao list, but I'm not subscribed so it's "waiting for moderator". The other I just put up on http://rafb.net/paste/ and provided the link. Steve ___________________________________________________________ Yahoo! Answers - Got a question? Someone out there knows the answer. Try it now. http://uk.answers.yahoo.com/
Does this patch fix your problem? http://mips.complang.tuwien.ac.at/hg/cacao/rev/4933a3684852