Problems with double reminder on Windows/x86_64 and Visual Studio 2005
David Holmes - Sun Microsystems
David.Holmes at Sun.COM
Wed Aug 27 05:04:58 PDT 2008
Hi Volker,
I don't know if this is related, or just coincidental timing but a new
bug report has just been filed:
6741940 Nonvolatile XMM registers not preserved across JNI calls
"Calls to the JNI entry point "CallVoidMethod" [in test program] do not
preserve the nonvolatile XMM registers, unless running with -Xint. This
is in violation of the Windows 64-bit ABI:
http://msdn.microsoft.com/en-us/library/ms794547.aspx"
This won't show up on BugParade for a day or so.
Regards,
David Holmes
Volker Simonis said the following on 08/26/08 05:19:
> Hi,
>
> we had a strange problem wich lead to failures in the JCK test
> Math2012. The problem only occured if some other JCK-Tests where
> compiled and execuetd in a special order before the tests in
> Math2012.
>
> I could finally track down the problem to the following simple test case:
>
> ====================================================
> public class Log10 {
>
> public static double log10(double d) {
> return Math.log10(d);
> }
>
> public static double drem2(double d) {
> return d % 2;
> }
>
> public static void main(String args[]) {
> System.out.println("log10(0) = " + Math.log10(0.0d));
> System.out.println("log10(0) = " + log10(0.0d));
> System.out.println("drem2(4.0) = " + drem2(4.0d));
> }
> }
> ====================================================
>
> which always fails on Windows/x86_64 (i.e. prints "NaN" for the result
> of 4.0 % 2.0 which should be 0.0) if executed like this:
>
> java -Xcomp -Xbatch -XX:CompileCommand="compileonly Log10 log10"
> -XX:+PrintCompilation Log10
>
> VM option 'CompileCommand=compileonly Log10 log10'
> VM option '+PrintCompilation'
> CompilerOracle: compileonly Log10.log10
> log10(0) = -Infinity
> 1 b Log10::log10 (5 bytes)
> log10(0) = -Infinity
> drem2(4.0) = NaN
>
> Notice however that we are using a version of the Java 6 HotSpot
> compiled with Visual Studio 2005.
>
> I couldn't reproduce the problem with
> jdk-7-ea-bin-b32-windows-x64-debug-04_aug_2008 however I could verify
> that the code generated by both, our JDK 6 and the latest jdk-7 is
> virtually the same. The interesting part is the compiled version of
> the method Log10.log10():
>
> 000 pushq rbp
> subq rsp, #16 # Create frame
> nop # nop for patch_verified_entry
> 006 fldlg2 #Log10
> fyl2x # Q=Log10*Log_2(x)
> 024 addq rsp, 16 # Destroy frame
> popq rbp
> testl rax, [rip + #offset_to_poll_page] # Safepoint: poll for GC
> 02f ret
>
> The computation of Math.log10(0.0d) which correctly returns -Infinity
> sets the "Zero Divide" flag in the FP status word as described in
> http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26569.pdf.
>
> After this computation "SharedRuntime::drem()" is called for the
> computation of the double reminder in the method "drem2()" of the
> above example. "SharedRuntime::drem()" itself just delegates the
> computation to the "fmod()" function (defined in <math.h>) of the
> underlying platform.
>
> The presence of the "Zero Divide" flag in the FP status word seems to
> be no problem for the "fmod()" which is used by the
> jdk-7-ea-bin-b32-windows-x64-debug-04_aug_2008 executable (from
> msvcr71.dll) and it is no problem on Linux/x86_64 either, but it IS
> definitely a problem for the "fmod()" from the "msvcr80d.dll" which is
> used in our MSVC 2005 build.
>
> I have two questions now:
>
> 1. Is it ok that the intrinsic for Math.log10() leaves the exceptions
> bits as they are in the FP status word?
> 2. Can somebody confirm that the described behaviour of "fmod()" from
> "msvcr80d.dll" as used by MSVC 2005 is buggy? (I couldn't find any bug
> report and I also couldn't find reference if "fmod() should depend on
> the FP status word or not.)
>
> It would also be nice if somebody who has recent OpenJDK built with
> MSVC 2005 could confirm the above problem or if somebody could just
> confirm or disprove the "fmod()" problem within different versions of
> MSVC. Here's a small C-program which can be used to test if "fmod()"
> is dependent on the FP status word:
>
> ====================== fmod.c ====================
> #include <math.h>
> #include <stdio.h>
>
> extern void fpu_asm();
>
> int main(int argc, char* argv[]) {
>
> double d = 0.0;
>
> printf("fmod(4.0, 2.0) = %f\n", fmod(4.0, 2.0));
>
> fpu_asm();
>
> printf("fmod(4.0, 2.0) = %f\n", fmod(4.0, 2.0));
>
> }
> =====================================================
>
> ===================== fpu_asm.asm ====================
> PUBLIC fpu_asm
> .CODE
> ALIGN 8
> fpu_asm PROC
> fldlg2
> fldz
> fyl2x
> ret
> ALIGN 8
> fpu_asm ENDP
> END
> ======================================================
>
> Compile and run with:
>
> ml64 /c fpu_asm.asm
> cl fmod.c fpu_asm.obj
> fmod.exe
> fmod(4.0, 2.0) = 0.000000
> fmod(4.0, 2.0) = -1.#IND00
>
> Regards,
> Volker
>
> PS: the obvious solution of calling "_clearfp()" as defined in
> <float.h> just before a call to "fmod()" unfortunately doesn't work,
> because "_clearfp()" (at least in MSVC 2005) only cleans the SSE
> status register MXCSR. The only solution I see right now is using the
> FCLEX assembler instruction, and because MSVC 2005 has no inline
> assembler for x86_64 I'll probably have to write the whole assembler
> function for the assembler instruction. Or does somebody have a
> smarter solution?
>
> PPS: this is a nice example, how a compiler switch can get you a lot
> of fun (isn't it Kelly:) ...
More information about the hotspot-dev
mailing list