about summary refs log tree commit diff stats
path: root/src/emu
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2023-10-25 20:14:11 +0800
committerGitHub <noreply@github.com>2023-10-25 14:14:11 +0200
commit87bf751b115267d7c388c849c43fca6d3f0d0881 (patch)
treeedc6f3976538daf8dd1d9a49694d4bda19ef591d /src/emu
parent12c40a5b804143cee0d538c4de4b526522bcfcd2 (diff)
downloadbox64-87bf751b115267d7c388c849c43fca6d3f0d0881.tar.gz
box64-87bf751b115267d7c388c849c43fca6d3f0d0881.zip
[INTERP] Fix fpu_round (#1030)
* [INTERP] Fix fpu_round

* Should be working this time

* Handling wrappedlibm

* Format

* Fix loongarch

* Make it optional

* Fix android build
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/x64run0f.c7
-rw-r--r--src/emu/x64run660f.c37
-rw-r--r--src/emu/x64runf20f.c19
-rw-r--r--src/emu/x64runf30f.c13
-rw-r--r--src/emu/x87emu_private.h10
5 files changed, 72 insertions, 14 deletions
diff --git a/src/emu/x64run0f.c b/src/emu/x64run0f.c
index a05b3596..e8a047f2 100644
--- a/src/emu/x64run0f.c
+++ b/src/emu/x64run0f.c
@@ -3,6 +3,7 @@
 #include <stdio.h>

 #include <stdlib.h>

 #include <math.h>

+#include <fenv.h>

 #include <string.h>

 #include <signal.h>

 #include <sys/types.h>

@@ -232,9 +233,13 @@ uintptr_t Run0F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
                     tmp64s = INT32_MIN;

                 else

                     switch(emu->mxcsr.f.MXCSR_RC) {

-                        case ROUND_Nearest:

+                        case ROUND_Nearest: {

+                            int round = fegetround();

+                            fesetround(FE_TONEAREST);

                             tmp64s = nearbyintf(EX->f[i]);

+                            fesetround(round);

                             break;

+                        }

                         case ROUND_Down:

                             tmp64s = floorf(EX->f[i]);

                             break;

diff --git a/src/emu/x64run660f.c b/src/emu/x64run660f.c
index 84f5a38e..9b969c83 100644
--- a/src/emu/x64run660f.c
+++ b/src/emu/x64run660f.c
@@ -3,6 +3,7 @@
 #include <stdio.h>

 #include <stdlib.h>

 #include <math.h>

+#include <fenv.h>

 #include <string.h>

 #include <signal.h>

 #include <sys/types.h>

@@ -221,10 +222,14 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
         GETEX(0);

         GETGM;

         switch(emu->mxcsr.f.MXCSR_RC) {

-            case ROUND_Nearest:

+            case ROUND_Nearest: {

+                int round = fegetround();

+                fesetround(FE_TONEAREST);

                 i64[0] = nearbyint(EX->d[0]);

                 i64[1] = nearbyint(EX->d[1]);

+                fesetround(round);

                 break;

+            }

             case ROUND_Down:

                 i64[0] = floor(EX->d[0]);

                 i64[1] = floor(EX->d[1]);

@@ -818,10 +823,14 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 else

                     tmp8u &= 3;

                 switch(tmp8u) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         for(int i=0; i<4; ++i)

                             GX->f[i] = nearbyintf(EX->f[i]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         for(int i=0; i<4; ++i)

                             GX->f[i] = floorf(EX->f[i]);

@@ -846,10 +855,14 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 else

                     tmp8u &= 3;

                 switch(tmp8u) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         GX->d[0] = nearbyint(EX->d[0]);

                         GX->d[1] = nearbyint(EX->d[1]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         GX->d[0] = floor(EX->d[0]);

                         GX->d[1] = floor(EX->d[1]);

@@ -874,9 +887,13 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 else

                     tmp8u &= 3;

                 switch(tmp8u) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         GX->f[0] = nearbyintf(EX->f[0]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         GX->f[0] = floorf(EX->f[0]);

                         break;

@@ -898,9 +915,13 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 else

                     tmp8u &= 3;

                 switch(tmp8u) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         GX->d[0] = nearbyint(EX->d[0]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         GX->d[0] = floor(EX->d[0]);

                         break;

@@ -1227,9 +1248,13 @@ uintptr_t Run660F(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 tmp64s = INT32_MIN;

             else

                 switch(emu->mxcsr.f.MXCSR_RC) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         tmp64s = nearbyintf(EX->f[i]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         tmp64s = floorf(EX->f[i]);

                         break;

diff --git a/src/emu/x64runf20f.c b/src/emu/x64runf20f.c
index 33750318..d5ce598f 100644
--- a/src/emu/x64runf20f.c
+++ b/src/emu/x64runf20f.c
@@ -3,6 +3,7 @@
 #include <stdio.h>

 #include <stdlib.h>

 #include <math.h>

+#include <fenv.h>

 #include <string.h>

 #include <signal.h>

 #include <sys/types.h>

@@ -113,9 +114,13 @@ uintptr_t RunF20F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
                 GD->q[0] = 0x8000000000000000LL;

             else

                 switch(emu->mxcsr.f.MXCSR_RC) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         GD->sq[0] = nearbyint(EX->d[0]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         GD->sq[0] = floor(EX->d[0]);

                         break;

@@ -131,9 +136,13 @@ uintptr_t RunF20F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
                 GD->dword[0] = 0x80000000;

             else

                 switch(emu->mxcsr.f.MXCSR_RC) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         GD->sdword[0] = nearbyint(EX->d[0]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         GD->sdword[0] = floor(EX->d[0]);

                         break;

@@ -325,10 +334,14 @@ uintptr_t RunF20F(x64emu_t *emu, rex_t rex, uintptr_t addr, int *step)
         GETEX(0);

         GETGX;

         switch(emu->mxcsr.f.MXCSR_RC) {

-            case ROUND_Nearest:

+            case ROUND_Nearest: {

+                int round = fegetround();

+                fesetround(FE_TONEAREST);

                 tmp64s0 = nearbyint(EX->d[0]);

                 tmp64s1 = nearbyint(EX->d[1]);

+                fesetround(round);

                 break;

+            }

             case ROUND_Down:

                 tmp64s0 = floor(EX->d[0]);

                 tmp64s1 = floor(EX->d[1]);

diff --git a/src/emu/x64runf30f.c b/src/emu/x64runf30f.c
index d5b70b20..bd7c97e9 100644
--- a/src/emu/x64runf30f.c
+++ b/src/emu/x64runf30f.c
@@ -3,6 +3,7 @@
 #include <stdio.h>

 #include <stdlib.h>

 #include <math.h>

+#include <fenv.h>

 #include <string.h>

 #include <signal.h>

 #include <sys/types.h>

@@ -119,9 +120,13 @@ uintptr_t RunF30F(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 GD->q[0] = 0x8000000000000000LL;

             else

                 switch(emu->mxcsr.f.MXCSR_RC) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         GD->sq[0] = nearbyintf(EX->f[0]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         GD->sq[0] = floorf(EX->f[0]);

                         break;

@@ -137,9 +142,13 @@ uintptr_t RunF30F(x64emu_t *emu, rex_t rex, uintptr_t addr)
                 tmp64s = INT32_MIN;

             else

                 switch(emu->mxcsr.f.MXCSR_RC) {

-                    case ROUND_Nearest:

+                    case ROUND_Nearest: {

+                        int round = fegetround();

+                        fesetround(FE_TONEAREST);

                         tmp64s = nearbyintf(EX->f[0]);

+                        fesetround(round);

                         break;

+                    }

                     case ROUND_Down:

                         tmp64s = floorf(EX->f[0]);

                         break;

diff --git a/src/emu/x87emu_private.h b/src/emu/x87emu_private.h
index 5721088f..a8e2d39c 100644
--- a/src/emu/x87emu_private.h
+++ b/src/emu/x87emu_private.h
@@ -3,6 +3,7 @@
 
 #include <stdint.h>
 #include <math.h>
+#include <fenv.h>
 #include "regs.h"
 #include "x64run_private.h"
 #include "debug.h"
@@ -108,8 +109,13 @@ static inline double fpu_round(x64emu_t* emu, double d) {
     if (!isfinite(d))
         return d;
     switch(emu->cw.f.C87_RD) {
-        case ROUND_Nearest:
-            return nearbyint(d);
+        case ROUND_Nearest: {
+            int round = fegetround();
+            fesetround(FE_TONEAREST);
+            double res = nearbyint(d);
+            fesetround(round);
+            return res;
+        }
         case ROUND_Down:
             return floor(d);
         case ROUND_Up: