about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2024-10-07 22:57:47 +0800
committerGitHub <noreply@github.com>2024-10-07 16:57:47 +0200
commit4c69bcd97aff691b464f01ebed057cfcb912612b (patch)
tree3dbf5c2aad18598a6306d5b3ed9e324f66a593d8
parent05aac0879e415b99225d731e154bc5d6535c1d15 (diff)
downloadbox64-4c69bcd97aff691b464f01ebed057cfcb912612b.tar.gz
box64-4c69bcd97aff691b464f01ebed057cfcb912612b.zip
[DYNAREC] Optimized CALL/RET RAS for out of dynablock jumps (#1909)
-rw-r--r--src/dynarec/arm64/dynarec_arm64_00.c30
-rw-r--r--src/dynarec/arm64/dynarec_arm64_64.c15
-rw-r--r--src/dynarec/arm64/dynarec_arm64_67.c15
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c32
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_3.c32
-rw-r--r--src/dynarec/rv64/rv64_prolog.S2
6 files changed, 93 insertions, 33 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index 098c3072..5b5a253b 100644
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -3162,10 +3162,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                             ADR_S20(x4, j64);
                             MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         } else {
-                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
-                            j64 = getJumpTableAddress64(addr);
-                            TABLE64(x4, j64);
-                            LDRx_U12(x4, x4, 0);
+                            j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
+                            ADR_S20(x4, j64);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         }
                         STPx_S7_preindex(x4, x2, xSP, -16);
                     } else {
@@ -3177,6 +3176,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     else
                         j64 = addr+i32;
                     jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
+                    if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
+                        // jumps out of current dynablock...
+                        MARK;
+                        j64 = getJumpTableAddress64(addr);
+                        TABLE64(x4, j64);
+                        LDRx_U12(x4, x4, 0);
+                        BR(x4);
+                    }
                     break;
             }
             break;
@@ -3674,15 +3681,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                             ADR_S20(x4, j64);
                             MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         } else {
-                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
-                            j64 = getJumpTableAddress64(addr);
-                            TABLE64(x4, j64);
-                            LDRx_U12(x4, x4, 0);
+                            j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
+                            ADR_S20(x4, j64);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         }
                         STPx_S7_preindex(x4, xRIP, xSP, -16);
                     }
                     PUSH1z(xRIP);
                     jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
+                    if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
+                        // jumps out of current dynablock...
+                        MARK;
+                        j64 = getJumpTableAddress64(addr);
+                        TABLE64(x4, j64);
+                        LDRx_U12(x4, x4, 0);
+                        BR(x4);
+                    }
                     break;
                 case 3: // CALL FAR Ed
                     if(MODREG) {
diff --git a/src/dynarec/arm64/dynarec_arm64_64.c b/src/dynarec/arm64/dynarec_arm64_64.c
index 160bc2db..681b386f 100644
--- a/src/dynarec/arm64/dynarec_arm64_64.c
+++ b/src/dynarec/arm64/dynarec_arm64_64.c
@@ -1384,15 +1384,22 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                             ADR_S20(x4, j64);
                             MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         } else {
-                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
-                            j64 = getJumpTableAddress64(addr);
-                            TABLE64(x4, j64);
-                            LDRx_U12(x4, x4, 0);
+                            j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
+                            ADR_S20(x4, j64);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         }
                         STPx_S7_preindex(x4, xRIP, xSP, -16);
                     }
                     PUSH1z(xRIP);
                     jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
+                    if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
+                        // jumps out of current dynablock...
+                        MARK;
+                        j64 = getJumpTableAddress64(addr);
+                        TABLE64(x4, j64);
+                        LDRx_U12(x4, x4, 0);
+                        BR(x4);
+                    }
                     break;
                 case 4: // JMP Ed
                     INST_NAME("JMP Ed");
diff --git a/src/dynarec/arm64/dynarec_arm64_67.c b/src/dynarec/arm64/dynarec_arm64_67.c
index 117e090a..111bcf8e 100644
--- a/src/dynarec/arm64/dynarec_arm64_67.c
+++ b/src/dynarec/arm64/dynarec_arm64_67.c
@@ -1541,15 +1541,22 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                             ADR_S20(x4, j64);

                             MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);

                         } else {

-                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);

-                            j64 = getJumpTableAddress64(addr);

-                            TABLE64(x4, j64);

-                            LDRx_U12(x4, x4, 0);

+                            j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;

+                            ADR_S20(x4, j64);

+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);

                         }

                         STPx_S7_preindex(x4, xRIP, xSP, -16);

                     }

                     PUSH1z(xRIP);

                     jump_to_next(dyn, 0, ed, ninst, rex.is32bits);

+                    if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {

+                        // jumps out of current dynablock...

+                        MARK;

+                        j64 = getJumpTableAddress64(addr);

+                        TABLE64(x4, j64);

+                        LDRx_U12(x4, x4, 0);

+                        BR(x4);

+                    }

                     break;

                 default:

                     DEFAULT;

diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 3003829f..3e6c0f99 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -2030,10 +2030,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                             ADDI_D(x4, x4, j64 & 0xfff);
                             MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64 >> 2);
                         } else {
-                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
-                            j64 = getJumpTableAddress64(addr);
-                            TABLE64(x4, j64);
-                            LD_D(x4, x4, 0);
+                            j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
+                            PCADDU12I(x4, ((j64 + 0x800) >> 12) & 0xfffff);
+                            ADDI_D(x4, x4, j64 & 0xfff);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         }
                         ADDI_D(xSP, xSP, -16);
                         ST_D(x4, xSP, 0);
@@ -2047,6 +2047,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     else
                         j64 = addr+i32;
                     jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
+                    if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
+                        // jumps out of current dynablock...
+                        MARK;
+                        j64 = getJumpTableAddress64(addr);
+                        TABLE64(x4, j64);
+                        LD_D(x4, x4, 0);
+                        BR(x4);
+                    }
                     break;
             }
             break;
@@ -2371,10 +2379,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                             ADDI_D(x4, x4, j64 & 0xfff);
                             MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64 >> 2);
                         } else {
-                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
-                            j64 = getJumpTableAddress64(addr);
-                            TABLE64(x4, j64);
-                            LD_D(x4, x4, 0);
+                            j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
+                            PCADDU12I(x4, ((j64 + 0x800) >> 12) & 0xfffff);
+                            ADDI_D(x4, x4, j64 & 0xfff);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         }
                         ADDI_D(xSP, xSP, -16);
                         ST_D(x4, xSP, 0);
@@ -2382,6 +2390,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     }
                     PUSH1z(xRIP);
                     jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
+                    if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
+                        // jumps out of current dynablock...
+                        MARK;
+                        j64 = getJumpTableAddress64(addr);
+                        TABLE64(x4, j64);
+                        LD_D(x4, x4, 0);
+                        BR(x4);
+                    }
                     break;
                 case 4: // JMP Ed
                     INST_NAME("JMP Ed");
diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c
index 146645ae..e1804f21 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_3.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_3.c
@@ -957,10 +957,10 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                             ADDI(x4, x4, j64 & 0xfff);
                             MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         } else {
-                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
-                            j64 = getJumpTableAddress64(addr);
-                            TABLE64(x4, j64);
-                            LD(x4, x4, 0);
+                            j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
+                            AUIPC(x4, ((j64 + 0x800) >> 12) & 0xfffff);
+                            ADDI(x4, x4, j64 & 0xfff);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         }
                         ADDI(xSP, xSP, -16);
                         SD(x4, xSP, 0);
@@ -974,6 +974,14 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     else
                         j64 = addr+i32;
                     jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
+                    if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
+                        // jumps out of current dynablock...
+                        MARK;
+                        j64 = getJumpTableAddress64(addr);
+                        TABLE64(x4, j64);
+                        LD(x4, x4, 0);
+                        BR(x4);
+                    }
                     break;
             }
             break;
@@ -1443,10 +1451,10 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                             ADDI(x4, x4, j64 & 0xfff);
                             MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         } else {
-                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
-                            j64 = getJumpTableAddress64(addr);
-                            TABLE64(x4, j64);
-                            LD(x4, x4, 0);
+                            j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
+                            AUIPC(x4, ((j64 + 0x800) >> 12) & 0xfffff);
+                            ADDI(x4, x4, j64 & 0xfff);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         }
                         ADDI(xSP, xSP, -16);
                         SD(x4, xSP, 0);
@@ -1454,6 +1462,14 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     }
                     PUSH1z(xRIP);
                     jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
+                    if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
+                        // jumps out of current dynablock...
+                        MARK;
+                        j64 = getJumpTableAddress64(addr);
+                        TABLE64(x4, j64);
+                        LD(x4, x4, 0);
+                        BR(x4);
+                    }
                     break;
                 case 4: // JMP Ed
                     INST_NAME("JMP Ed");
diff --git a/src/dynarec/rv64/rv64_prolog.S b/src/dynarec/rv64/rv64_prolog.S
index 1ca425fc..67af8253 100644
--- a/src/dynarec/rv64/rv64_prolog.S
+++ b/src/dynarec/rv64/rv64_prolog.S
@@ -67,4 +67,4 @@ rv64_prolog:
     xori    x5, x0, -1
     srli    x5, x5, 32
     // jump to block
-    jalr    a1
+    jr    a1