Fixed problem with precision of tan, atan, sin and cos, and implemented
authorMassimiliano Mantione <massi@mono-cvs.ximian.com>
Wed, 26 May 2004 19:49:55 +0000 (19:49 -0000)
committerMassimiliano Mantione <massi@mono-cvs.ximian.com>
Wed, 26 May 2004 19:49:55 +0000 (19:49 -0000)
related regressions tests (fixes bug 54467, but one new problem appeared
and is not fixed yet).

svn path=/trunk/mono/; revision=28195

mono/mini/ChangeLog
mono/mini/Makefile.am
mono/mini/basic-math.cs [new file with mode: 0644]
mono/mini/cpu-pentium.md
mono/mini/mini-x86.c

index 74a2f4c5b625aadb07ed04236a16f0955b99f510..2c56654e0c93529991345aea63f146cf74b3a3d9 100644 (file)
@@ -1,3 +1,10 @@
+2004-05-26  Massimiliano Mantione  <massi@ximian.com>
+
+       * mini-x86.c cpu-pentium.md Makefile.am basic-math.cs: Fixed problem
+       with precision of tan, atan, sin and cos, and implemented related
+       regressions tests (fixes bug 54467, but one new problem appeared and
+       is not fixed yet).
+
 2004-05-26  Zoltan Varga  <vargaz@freemail.hu>
 
        * cfold.c (FOLD_BINOPZ): Avoid division by zero.
index 71251e53a12c20d8a0cac5b5c803aa465156dd61..352a47e30a1900efb343aae7f9e248137410e7a9 100644 (file)
@@ -120,12 +120,13 @@ test_sources =            \
        objects.cs              \
        arrays.cs               \
        basic-float.cs  \
+       basic-math.cs   \
        basic.cs                \
        exceptions.cs   \
        iltests.il              \
        test.cs
 
-regtests=basic.exe arrays.exe basic-float.exe basic-long.exe objects.exe basic-calls.exe iltests.exe exceptions.exe bench.exe
+regtests=basic.exe arrays.exe basic-float.exe basic-math.exe basic-long.exe objects.exe basic-calls.exe iltests.exe exceptions.exe bench.exe
 
 common_BURGSRC= $(srcdir)/inssel.brg $(srcdir)/inssel-long32.brg $(srcdir)/inssel-float.brg
 
diff --git a/mono/mini/basic-math.cs b/mono/mini/basic-math.cs
new file mode 100644 (file)
index 0000000..05c39cd
--- /dev/null
@@ -0,0 +1,158 @@
+using System;
+using System.Reflection;
+
+/*
+ * Regression tests for the mono JIT.
+ *
+ * Each test needs to be of the form:
+ *
+ * static int test_<result>_<name> ();
+ *
+ * where <result> is an integer (the value that needs to be returned by
+ * the method to make it pass.
+ * <name> is a user-displayed name used to identify the test.
+ *
+ * The tests can be driven in two ways:
+ * *) running the program directly: Main() uses reflection to find and invoke
+ *     the test methods (this is useful mostly to check that the tests are correct)
+ * *) with the --regression switch of the jit (this is the preferred way since
+ *     all the tests will be run with optimizations on and off)
+ *
+ * The reflection logic could be moved to a .dll since we need at least another
+ * regression test file written in IL code to have better control on how
+ * the IL code looks.
+ */
+
+class Tests {
+
+       static int Main () {
+               return TestDriver.RunTests (typeof (Tests));
+       }
+       
+       static int test_0_sin_precision () {
+               double d1 = Math.Sin (1);
+                double d2 = Math.Sin (1) - d1;
+               return (d2 == 0) ? 0 : 1;
+       }
+
+       static int test_0_cos_precision () {
+               double d1 = Math.Cos (1);
+                double d2 = Math.Cos (1) - d1;
+               return (d2 == 0) ? 0 : 1;
+       }
+
+       static int test_0_tan_precision () {
+               double d1 = Math.Tan (1);
+                double d2 = Math.Tan (1) - d1;
+               return (d2 == 0) ? 0 : 1;
+       }
+
+       static int test_0_atan_precision () {
+               double d1 = Math.Atan (double.NegativeInfinity);
+                double d2 = Math.Atan (double.NegativeInfinity) - d1;
+               return (d2 == 0) ? 0 : 1;
+       }
+
+       static int test_0_sqrt_precision () {
+               double d1 = Math.Sqrt (2);
+                double d2 = Math.Sqrt (2) - d1;
+               return (d2 == 0) ? 0 : 1;
+       }
+
+       static int test_2_sqrt () {
+               return (int) Math.Sqrt (4);
+       }
+       static int test_0_sqrt_precision_and_not_spill () {
+               double expected = 0;
+               double[] operands = new double[3];
+               double[] temporaries = new double[3];
+               for (int i = 0; i < 3; i++) {
+                       operands [i] = (i+1) * (i+1) * (i+1);
+                       if (i == 0) {
+                               expected = operands [0];
+                       } else {
+                               temporaries [i] =  operands [i] / expected;
+                               temporaries [i] = Math.Sqrt (temporaries [i]);
+                               expected = temporaries [i];
+                       }
+                       
+                       //Console.Write( "{0}: {1}\n", i, temporaries [i] );
+               }
+               expected = temporaries [2];
+               
+               double result = Math.Sqrt (operands [2] / Math.Sqrt (operands [1] / operands [0]));
+               
+               //Console.Write( "result: {0,20:G}\n", result );
+               
+               return (result == expected) ? 0 : 1;
+       }
+       
+       static int test_0_sqrt_precision_and_spill () {
+               double expected = 0;
+               double[] operands = new double[9];
+               double[] temporaries = new double[9];
+               for (int i = 0; i < 9; i++) {
+                       operands [i] = (i+1) * (i+1) * (i+1);
+                       if (i == 0) {
+                               expected = operands [0];
+                       } else {
+                               temporaries [i] =  operands [i] / expected;
+                               temporaries [i] = Math.Sqrt (temporaries [i]);
+                               expected = temporaries [i];
+                       }
+                       
+                       //Console.Write( "{0}: {1}\n", i, temporaries [i] );
+               }
+               expected = temporaries [8];
+               
+               double result = Math.Sqrt (operands [8] / Math.Sqrt (operands [7] / Math.Sqrt (operands [6] / Math.Sqrt (operands [5] / Math.Sqrt (operands [4] / Math.Sqrt (operands [3] / Math.Sqrt (operands [2] / Math.Sqrt (operands [1] / operands [0]))))))));
+               
+               //Console.Write( "result: {0,20:G}\n", result );
+               
+               return (result == expected) ? 0 : 1;
+       }
+       
+       static int test_0_div_precision_and_spill () {
+               double expected = 0;
+               double[] operands = new double[9];
+               double[] temporaries = new double[9];
+               for (int i = 0; i < 9; i++) {
+                       operands [i] = (i+1) * (i+1);
+                       if (i == 0) {
+                               expected = operands [0];
+                       } else {
+                               temporaries [i] =  operands [i] / expected;
+                               expected = temporaries [i];
+                       }
+                       
+                       //Console.Write( "{0}: {1}\n", i, temporaries [i] );
+               }
+               expected = temporaries [8];
+               
+               double result = (operands [8] / (operands [7] / (operands [6] / (operands [5] / (operands [4] / (operands [3] / (operands [2] / (operands [1] / operands [0]))))))));
+               
+               //Console.Write( "result: {0,20:G}\n", result );
+               
+               return (result == expected) ? 0 : 1;
+       }
+       
+       static int test_0_sqrt_nan () {
+               return Double.IsNaN (Math.Sqrt (Double.NaN)) ? 0 : 1;
+       }
+       
+       static int test_0_sin_nan () {
+               return Double.IsNaN (Math.Sin (Double.NaN)) ? 0 : 1;
+       }
+       
+       static int test_0_cos_nan () {
+               return Double.IsNaN (Math.Cos (Double.NaN)) ? 0 : 1;
+       }
+       
+       static int test_0_tan_nan () {
+               return Double.IsNaN (Math.Tan (Double.NaN)) ? 0 : 1;
+       }
+       
+       static int test_0_atan_nan () {
+               return Double.IsNaN (Math.Atan (Double.NaN)) ? 0 : 1;
+       }
+}
index 2839dc8e5a165e693b96f20edbb77a217397dbab..90807e93b943cec4589b554314a4a8eccc92b78f 100644 (file)
@@ -553,11 +553,11 @@ adc_imm: dest:i src1:i len:6 clob:1
 sbb: dest:i src1:i src2:i len:2 clob:1
 sbb_imm: dest:i src1:i len:6 clob:1
 br_reg: src1:i len:2
-sin: dest:f src1:f len:2
-cos: dest:f src1:f len:2
+sin: dest:f src1:f len:6
+cos: dest:f src1:f len:6
 abs: dest:f src1:f len:2
-tan: dest:f src1:f len:45
-atan: dest:f src1:f len:4
+tan: dest:f src1:f len:49
+atan: dest:f src1:f len:8
 sqrt: dest:f src1:f len:2
 op_bigmul: len:2 dest:l src1:a src2:i
 op_bigmul_un: len:2 dest:l src1:a src2:i
index f1fe94f58b7c86103ce81042c2ae9257214abf11..4d02e743b8c6ad3b0305375f4c1113e068bb6ed2 100644 (file)
@@ -2952,9 +2952,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;          
                case OP_SIN:
                        x86_fsin (code);
+                       x86_fldz (code);
+                       x86_fp_op_reg (code, X86_FADD, 1, TRUE);
                        break;          
                case OP_COS:
                        x86_fcos (code);
+                       x86_fldz (code);
+                       x86_fp_op_reg (code, X86_FADD, 1, TRUE);
                        break;          
                case OP_ABS:
                        x86_fabs (code);
@@ -2989,12 +2993,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        x86_fstp (code, 0); /* pop the 1.0 */
                        x86_patch (check_pos, code);
                        x86_patch (end_tan, code);
+                       x86_fldz (code);
+                       x86_fp_op_reg (code, X86_FADD, 1, TRUE);
                        x86_pop_reg (code, X86_EAX);
                        break;
                }
                case OP_ATAN:
                        x86_fld1 (code);
                        x86_fpatan (code);
+                       x86_fldz (code);
+                       x86_fp_op_reg (code, X86_FADD, 1, TRUE);
                        break;          
                case OP_SQRT:
                        x86_fsqrt (code);