about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.c165
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.c93
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.c221
3 files changed, 151 insertions, 328 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index 088129e7..9a5dab3c 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -565,53 +565,61 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
     BR(x2);
 }
 
+
+static int indirect_lookup(dynarec_arm_t* dyn, int ninst, int is32bits, int s1, int s2)
+{
+    MAYUSE(dyn);
+
+    if (!is32bits) {
+        // check higher 48bits
+        LSRx_IMM(s1, xRIP, 48);
+        CBNZw(s1, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
+        // load table
+        uintptr_t tbl = getJumpTable48(); // this is a static value, so will be a low address
+        MOV64x(s2, tbl);
+        #ifdef JMPTABL_SHIFT4
+        UBFXx(s1, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
+        LDRx_REG_LSL3(s2, s2, s1);
+        #endif
+        UBFXx(s1, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
+        LDRx_REG_LSL3(s2, s2, s1);
+    } else {
+        // check higher 32bits disabled
+        // LSRx_IMM(s1, xRIP, 32);
+        // CBNZw(s1, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
+        // load table
+        uintptr_t tbl = getJumpTable32(); // this will not be a low address
+        TABLE64(s2, tbl);
+        #ifdef JMPTABL_SHIFT4
+        UBFXx(s1, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
+        LDRx_REG_LSL3(s2, s2, s1);
+        #endif
+    }
+    UBFXx(s1, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
+    LDRx_REG_LSL3(s2, s2, s1);
+    UBFXx(s1, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
+    LDRx_REG_LSL3(s1, s2, s1);
+    return s1;
+}
+
 void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits)
 {
-    MAYUSE(dyn); MAYUSE(ninst);
+    MAYUSE(dyn);
+    MAYUSE(ninst);
     MESSAGE(LOG_DUMP, "Jump to next\n");
 
-    if(is32bits)
+    if (is32bits)
         ip &= 0xffffffffLL;
 
     SMEND();
-    if(reg) {
-        if(reg!=xRIP) {
+
+    int dest;
+    if (reg) {
+        if (reg != xRIP) {
             MOVx_REG(xRIP, reg);
         }
         NOTEST(x2);
-        if(!is32bits) {
-            // check higher 48bits
-            LSRx_IMM(x2, xRIP, 48);
-            CBNZw(x2, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
-            // load table
-            uintptr_t tbl = getJumpTable48();   // this is a static value, so will be a low address
-            MOV64x(x3, tbl);
-            #ifdef JMPTABL_SHIFT4
-            UBFXx(x2, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
-            LDRx_REG_LSL3(x3, x3, x2);
-            #endif
-            UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
-            LDRx_REG_LSL3(x3, x3, x2);
-            UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
-            LDRx_REG_LSL3(x3, x3, x2);
-            UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
-            LDRx_REG_LSL3(x2, x3, x2);
-        } else {
-            // check higher 32bits disabled
-            //LSRx_IMM(x2, xRIP, 32);
-            //CBNZw(x2, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
-            // load table
-            uintptr_t tbl = getJumpTable32();   // this will not be a low address
-            TABLE64(x3, tbl);
-            #ifdef JMPTABL_SHIFT4
-            UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
-            LDRx_REG_LSL3(x3, x3, x2);
-            #endif
-            UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
-            LDRx_REG_LSL3(x3, x3, x2);
-            UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
-            LDRx_REG_LSL3(x2, x3, x2);
-        }
+        dest = indirect_lookup(dyn, ninst, is32bits, x2, x3);
     } else {
         NOTEST(x2);
         uintptr_t p = getJumpTableAddress64(ip);
@@ -619,6 +627,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
         MOV64x(x3, p);
         GETIP_(ip);
         LDRx_U12(x2, x3, 0);
+        dest = x2;
     }
     if(reg!=x1) {
         MOVx_REG(x1, xRIP);
@@ -626,12 +635,12 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
     CLEARIP();
     #ifdef HAVE_TRACE
     //MOVx(x3, 15);    no access to PC reg
-    BLR(x2); // save LR...
+    BLR(dest); // save LR...
     #else
     if (dyn->insts[ninst].x64.has_callret) {
-        BLR(x2); // save LR...
+        BLR(dest); // save LR...
     } else {
-        BR(x2);
+        BR(dest);
     }
     #endif
 }
@@ -653,43 +662,11 @@ void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
         SUBx_U12(xSP, xSavedSP, 16);
     }
     NOTEST(x2);
-    if(!rex.is32bits) {
-        // check higher 48bits
-        LSRx_IMM(x2, xRIP, 48);
-        CBNZw(x2, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
-        // load table
-        uintptr_t tbl = getJumpTable48();
-        MOV64x(x3, tbl);
-        #ifdef JMPTABL_SHIFT4
-        UBFXx(x2, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
-        LDRx_REG_LSL3(x3, x3, x2);
-        #endif
-        UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
-        LDRx_REG_LSL3(x3, x3, x2);
-        UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
-        LDRx_REG_LSL3(x3, x3, x2);
-        UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
-        LDRx_REG_LSL3(x2, x3, x2);
-    } else {
-        // check higher 32bits disabled
-        //LSRx_IMM(x2, xRIP, 32);
-        //CBNZw(x2, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
-        // load table
-        uintptr_t tbl = getJumpTable32();
-        TABLE64(x3, tbl);
-        #ifdef JMPTABL_SHIFT4
-        UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
-        LDRx_REG_LSL3(x3, x3, x2);
-        #endif
-        UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
-        LDRx_REG_LSL3(x3, x3, x2);
-        UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
-        LDRx_REG_LSL3(x2, x3, x2);
-    }
+    int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
     #ifdef HAVE_TRACE
-    BLR(x2);
+    BLR(dest);
     #else
-    BR(x2);
+    BR(dest);
     #endif
     CLEARIP();
 }
@@ -717,43 +694,11 @@ void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int
         SUBx_U12(xSP, xSavedSP, 16);
     }
     NOTEST(x2);
-    if(!rex.is32bits) {
-        // check higher 48bits
-        LSRx_IMM(x2, xRIP, 48);
-        CBNZw(x2, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
-        // load table
-        uintptr_t tbl = getJumpTable48();
-        MOV64x(x3, tbl);
-        #ifdef JMPTABL_SHIFT4
-        UBFXx(x2, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
-        LDRx_REG_LSL3(x3, x3, x2);
-        #endif
-        UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
-        LDRx_REG_LSL3(x3, x3, x2);
-        UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
-        LDRx_REG_LSL3(x3, x3, x2);
-        UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
-        LDRx_REG_LSL3(x2, x3, x2);
-    } else {
-        // check higher 32bits disbaled
-        //LSRx_IMM(x2, xRIP, 32);
-        //CBNZw(x2, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
-        // load table
-        uintptr_t tbl = getJumpTable32();
-        TABLE64(x3, tbl);
-        #ifdef JMPTABL_SHIFT4
-        UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
-        LDRx_REG_LSL3(x3, x3, x2);
-        #endif
-        UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
-        LDRx_REG_LSL3(x3, x3, x2);
-        UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
-        LDRx_REG_LSL3(x2, x3, x2);
-    }
+    int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
     #ifdef HAVE_TRACE
-    BLR(x2);
+    BLR(dest);
     #else
-    BR(x2);
+    BR(dest);
     #endif
     CLEARIP();
 }
diff --git a/src/dynarec/la64/dynarec_la64_helper.c b/src/dynarec/la64/dynarec_la64_helper.c
index 97ed2d97..6fa48606 100644
--- a/src/dynarec/la64/dynarec_la64_helper.c
+++ b/src/dynarec/la64/dynarec_la64_helper.c
@@ -526,6 +526,31 @@ void jump_to_epilog_fast(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst)
     BR(x2);
 }
 
+
+static int indirect_lookup(dynarec_la64_t* dyn, int ninst, int is32bits, int s1, int s2)
+{
+    MAYUSE(dyn);
+    if (!is32bits) {
+        SRLI_D(s1, xRIP, 48);
+        BNEZ_safe(s1, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
+        uintptr_t tbl = getJumpTable48();
+        MOV64x(s2, tbl);
+        BSTRPICK_D(s1, xRIP, JMPTABL_START2 + JMPTABL_SHIFT2 - 1, JMPTABL_START2);
+        ALSL_D(s2, s1, s2, 3);
+        LD_D(s2, s2, 0);
+    } else {
+        uintptr_t tbl = getJumpTable32();
+        TABLE64(s2, tbl);
+    }
+    BSTRPICK_D(s1, xRIP, JMPTABL_START1 + JMPTABL_SHIFT1 - 1, JMPTABL_START1);
+    ALSL_D(s2, s1, s2, 3);
+    LD_D(s2, s2, 0);
+    BSTRPICK_D(s1, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
+    ALSL_D(s2, s1, s2, 3);
+    LD_D(s1, s2, 0);
+    return s1;
+}
+
 void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits)
 {
     MAYUSE(dyn);
@@ -535,45 +560,28 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
     if (is32bits)
         ip &= 0xffffffffLL;
 
+    int dest;
     if (reg) {
         if (reg != xRIP) {
             MV(xRIP, reg);
         }
         NOTEST(x2);
-        uintptr_t tbl = is32bits ? getJumpTable32() : getJumpTable64();
-        MAYUSE(tbl);
-        TABLE64(x3, tbl);
-        if (!is32bits) {
-            BSTRPICK_D(x2, xRIP, JMPTABL_START3 + JMPTABL_SHIFT3 - 1, JMPTABL_START3);
-            ALSL_D(x3, x2, x3, 3);
-            LD_D(x3, x3, 0);
-            BSTRPICK_D(x2, xRIP, JMPTABL_START2 + JMPTABL_SHIFT2 - 1, JMPTABL_START2);
-            ALSL_D(x3, x2, x3, 3);
-            LD_D(x3, x3, 0);
-        }
-        BSTRPICK_D(x2, xRIP, JMPTABL_START1 + JMPTABL_SHIFT1 - 1, JMPTABL_START1);
-        ALSL_D(x3, x2, x3, 3);
-        LD_D(x3, x3, 0);
-        BSTRPICK_D(x2, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
-        ALSL_D(x3, x2, x3, 3);
-        LD_D(x2, x3, 0);
+        dest = indirect_lookup(dyn, ninst, is32bits, x2, x3);
     } else {
         NOTEST(x2);
         uintptr_t p = getJumpTableAddress64(ip);
         MAYUSE(p);
         TABLE64(x3, p);
         GETIP_(ip);
-        LD_D(x2, x3, 0); // LR_D(x2, x3, 1, 1);
+        LD_D(x2, x3, 0);
+        dest = x2;
     }
     if (reg != x1) {
         MV(x1, xRIP);
     }
     CLEARIP();
-#ifdef HAVE_TRACE
-// MOVx(x3, 15);    no access to PC reg
-#endif
     SMEND();
-    JIRL((dyn->insts[ninst].x64.has_callret ? xRA : xZR), x2, 0x0); // save LR...
+    JIRL((dyn->insts[ninst].x64.has_callret ? xRA : xZR), dest, 0x0);
 }
 
 void ret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
@@ -594,24 +602,9 @@ void ret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
         // not the correct return address, regular jump, but purge the stack first, it's unsync now...
         ADDI_D(xSP, xSavedSP, -16);
     }
-
-    uintptr_t tbl = rex.is32bits ? getJumpTable32() : getJumpTable64();
-    MOV64x(x3, tbl);
-    if (!rex.is32bits) {
-        BSTRPICK_D(x2, xRIP, JMPTABL_START3 + JMPTABL_SHIFT3 - 1, JMPTABL_START3);
-        ALSL_D(x3, x2, x3, 3);
-        LD_D(x3, x3, 0);
-        BSTRPICK_D(x2, xRIP, JMPTABL_START2 + JMPTABL_SHIFT2 - 1, JMPTABL_START2);
-        ALSL_D(x3, x2, x3, 3);
-        LD_D(x3, x3, 0);
-    }
-    BSTRPICK_D(x2, xRIP, JMPTABL_START1 + JMPTABL_SHIFT1 - 1, JMPTABL_START1);
-    ALSL_D(x3, x2, x3, 3);
-    LD_D(x3, x3, 0);
-    BSTRPICK_D(x2, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
-    ALSL_D(x3, x2, x3, 3);
-    LD_D(x2, x3, 0);
-    BR(x2);
+    NOTEST(x2);
+    int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
+    BR(dest);
     CLEARIP();
 }
 
@@ -640,23 +633,9 @@ void retn_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int
         ADDI_D(xSP, xSavedSP, -16);
     }
 
-    uintptr_t tbl = rex.is32bits ? getJumpTable32() : getJumpTable64();
-    MOV64x(x3, tbl);
-    if (!rex.is32bits) {
-        BSTRPICK_D(x2, xRIP, JMPTABL_START3 + JMPTABL_SHIFT3 - 1, JMPTABL_START3);
-        ALSL_D(x3, x2, x3, 3);
-        LD_D(x3, x3, 0);
-        BSTRPICK_D(x2, xRIP, JMPTABL_START2 + JMPTABL_SHIFT2 - 1, JMPTABL_START2);
-        ALSL_D(x3, x2, x3, 3);
-        LD_D(x3, x3, 0);
-    }
-    BSTRPICK_D(x2, xRIP, JMPTABL_START1 + JMPTABL_SHIFT1 - 1, JMPTABL_START1);
-    ALSL_D(x3, x2, x3, 3);
-    LD_D(x3, x3, 0);
-    BSTRPICK_D(x2, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
-    ALSL_D(x3, x2, x3, 3);
-    LD_D(x2, x3, 0);
-    BR(x2);
+    NOTEST(x2);
+    int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
+    BR(dest);
     CLEARIP();
 }
 
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c
index 1f4ef25b..79868e55 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.c
+++ b/src/dynarec/rv64/dynarec_rv64_helper.c
@@ -583,6 +583,56 @@ void jump_to_epilog_fast(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst)
 #ifdef JMPTABLE_SHIFT4
 #error TODO!
 #endif
+
+static int indirect_lookup(dynarec_rv64_t* dyn, int ninst, int is32bits, int s1, int s2)
+{
+    MAYUSE(dyn);
+    if (rv64_xtheadbb && rv64_xtheadmemidx) {
+        if (!is32bits) {
+            SRLI(s1, xRIP, 48);
+            BNEZ_safe(s1, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
+            uintptr_t tbl = getJumpTable48();
+            MOV64x(s2, tbl);
+            TH_EXTU(s1, xRIP, JMPTABL_START2 + JMPTABL_SHIFT2 - 1, JMPTABL_START2);
+            TH_LRD(s2, s2, s1, 3);
+        } else {
+            uintptr_t tbl = getJumpTable32();
+            TABLE64(s2, tbl);
+        }
+        TH_EXTU(s1, xRIP, JMPTABL_START1 + JMPTABL_SHIFT1 - 1, JMPTABL_START1);
+        TH_LRD(s2, s2, s1, 3);
+        TH_EXTU(s1, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
+        TH_LRD(s1, s2, s1, 3);
+    } else {
+        if (!is32bits) {
+            SRLI(s1, xRIP, 48);
+            BNEZ_safe(s1, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
+            uintptr_t tbl = getJumpTable48();
+            MOV64x(s2, tbl);
+            SRLI(s1, xRIP, JMPTABL_START2);
+            ADDSL(s2, s2, s1, 3, s1);
+            LD(s2, s2, 0);
+        } else {
+            uintptr_t tbl = getJumpTable32();
+            TABLE64(s2, tbl);
+        }
+        MOV64x(x4, JMPTABLE_MASK1 << 3);
+        SRLI(s1, xRIP, JMPTABL_START1 - 3);
+        AND(s1, s1, x4);
+        ADD(s2, s2, s1);
+        LD(s2, s2, 0);
+        if (JMPTABLE_MASK0 < 2048) {
+            ANDI(s1, xRIP, JMPTABLE_MASK0);
+        } else {
+            MOV64x(x4, JMPTABLE_MASK0); // x4 = mask
+            AND(s1, xRIP, x4);
+        }
+        ADDSL(s2, s2, s1, 3, s1);
+        LD(s1, s2, 0);
+    }
+    return s1;
+}
+
 void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits)
 {
     MAYUSE(dyn);
@@ -592,81 +642,27 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
     if (is32bits)
         ip &= 0xffffffffLL;
 
+    int dest;
     if (reg) {
         if (reg != xRIP) {
             MV(xRIP, reg);
         }
         NOTEST(x2);
-        uintptr_t tbl = is32bits ? getJumpTable32() : getJumpTable64();
-        MAYUSE(tbl);
-        TABLE64(x3, tbl);
-        if (rv64_xtheadbb) {
-            if (!is32bits) {
-                TH_EXTU(x2, xRIP, JMPTABL_START3 + JMPTABL_SHIFT3 - 1, JMPTABL_START3);
-                TH_ADDSL(x3, x3, x2, 3);
-                LD(x3, x3, 0);
-                TH_EXTU(x2, xRIP, JMPTABL_START2 + JMPTABL_SHIFT2 - 1, JMPTABL_START2);
-                TH_ADDSL(x3, x3, x2, 3);
-                LD(x3, x3, 0);
-            }
-            TH_EXTU(x2, xRIP, JMPTABL_START1 + JMPTABL_SHIFT1 - 1, JMPTABL_START1);
-            TH_ADDSL(x3, x3, x2, 3);
-            LD(x3, x3, 0);
-            TH_EXTU(x2, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
-            TH_ADDSL(x3, x3, x2, 3);
-            LD(x2, x3, 0);
-        } else {
-            if (!is32bits) {
-                SRLI(x2, xRIP, JMPTABL_START3);
-                if (rv64_zba)
-                    SH3ADD(x3, x2, x3);
-                else {
-                    SLLI(x2, x2, 3);
-                    ADD(x3, x3, x2);
-                }
-                LD(x3, x3, 0); // could be LR_D(x3, x3, 1, 1); for better safety
-                MOV64x(x4, JMPTABLE_MASK2 << 3); // x4 = mask
-                SRLI(x2, xRIP, JMPTABL_START2 - 3);
-                AND(x2, x2, x4);
-                ADD(x3, x3, x2);
-                LD(x3, x3, 0); // LR_D(x3, x3, 1, 1);
-                if (JMPTABLE_MASK2 != JMPTABLE_MASK1) {
-                    MOV64x(x4, JMPTABLE_MASK1 << 3); // x4 = mask
-                }
-            } else {
-                MOV64x(x4, JMPTABLE_MASK1 << 3);
-            }
-            SRLI(x2, xRIP, JMPTABL_START1 - 3);
-            AND(x2, x2, x4);
-            ADD(x3, x3, x2);
-            LD(x3, x3, 0); // LR_D(x3, x3, 1, 1);
-            if (JMPTABLE_MASK0 < 2048) {
-                ANDI(x2, xRIP, JMPTABLE_MASK0);
-            } else {
-                MOV64x(x4, JMPTABLE_MASK0); // x4 = mask
-                AND(x2, xRIP, x4);
-            }
-            if (rv64_zba)
-                SH3ADD(x3, x2, x3);
-            else {
-                SLLI(x2, x2, 3);
-                ADD(x3, x3, x2);
-            }
-            LD(x2, x3, 0);
-        }
+        dest = indirect_lookup(dyn, ninst, is32bits, x2, x3);
     } else {
         uintptr_t p = getJumpTableAddress64(ip);
         MAYUSE(p);
         GETIP_(ip, x3);
         TABLE64(x3, p);
         LD(x2, x3, 0);
+        dest = x2;
     }
     CLEARIP();
     SMEND();
 #ifdef HAVE_TRACE
-    JALR(xRA, x2);
+    JALR(xRA, dest);
 #else
-    JALR((dyn->insts[ninst].x64.has_callret ? xRA : xZR), x2);
+    JALR((dyn->insts[ninst].x64.has_callret ? xRA : xZR), dest);
 #endif
 }
 
@@ -689,58 +685,9 @@ void ret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
         LD(xSP, xEmu, offsetof(x64emu_t, xSPSave));
         ADDI(xSP, xSP, -16);
     }
-
-    uintptr_t tbl = rex.is32bits ? getJumpTable32() : getJumpTable64();
     NOTEST(x2);
-    MOV64x(x3, tbl);
-    if (rv64_xtheadbb && rv64_xtheadmemidx) {
-        if (!rex.is32bits) {
-            TH_EXTU(x2, xRIP, JMPTABL_START3 + JMPTABL_SHIFT3 - 1, JMPTABL_START3);
-            TH_LRD(x3, x3, x2, 3);
-            TH_EXTU(x2, xRIP, JMPTABL_START2 + JMPTABL_SHIFT2 - 1, JMPTABL_START2);
-            TH_LRD(x3, x3, x2, 3);
-        }
-        TH_EXTU(x2, xRIP, JMPTABL_START1 + JMPTABL_SHIFT1 - 1, JMPTABL_START1);
-        TH_LRD(x3, x3, x2, 3);
-        TH_EXTU(x2, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
-        TH_LRD(x2, x3, x2, 3);
-    } else {
-        if (!rex.is32bits) {
-            SRLI(x2, xRIP, JMPTABL_START3);
-            ADDSL(x3, x3, x2, 3, x2);
-            LD(x3, x3, 0);
-            MOV64x(x4, JMPTABLE_MASK2 << 3); // x4 = mask
-            SRLI(x2, xRIP, JMPTABL_START2 - 3);
-            AND(x2, x2, x4);
-            ADD(x3, x3, x2);
-            LD(x3, x3, 0);
-            if (JMPTABLE_MASK2 != JMPTABLE_MASK1) {
-                MOV64x(x4, JMPTABLE_MASK1 << 3); // x4 = mask
-            }
-        } else {
-            MOV64x(x4, JMPTABLE_MASK1 << 3); // x4 = mask
-        }
-        SRLI(x2, xRIP, JMPTABL_START1 - 3);
-        AND(x2, x2, x4);
-        ADD(x3, x3, x2);
-        LD(x3, x3, 0);
-        if (JMPTABLE_MASK0 < 2048) {
-            ANDI(x2, xRIP, JMPTABLE_MASK0);
-        } else {
-            if (JMPTABLE_MASK1 != JMPTABLE_MASK0) {
-                MOV64x(x4, JMPTABLE_MASK0); // x4 = mask
-            }
-            AND(x2, xRIP, x4);
-        }
-        if (rv64_zba)
-            SH3ADD(x3, x2, x3);
-        else {
-            SLLI(x2, x2, 3);
-            ADD(x3, x3, x2);
-        }
-        LD(x2, x3, 0);
-    }
-    BR(x2);
+    int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
+    BR(dest);
     CLEARIP();
 }
 
@@ -769,57 +716,9 @@ void retn_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int
         LD(xSP, xEmu, offsetof(x64emu_t, xSPSave));
         ADDI(xSP, xSP, -16);
     }
-    uintptr_t tbl = rex.is32bits ? getJumpTable32() : getJumpTable64();
     NOTEST(x2);
-    MOV64x(x3, tbl);
-    if (rv64_xtheadbb && rv64_xtheadmemidx) {
-        if (!rex.is32bits) {
-            TH_EXTU(x2, xRIP, JMPTABL_START3 + JMPTABL_SHIFT3 - 1, JMPTABL_START3);
-            TH_LRD(x3, x3, x2, 3);
-            TH_EXTU(x2, xRIP, JMPTABL_START2 + JMPTABL_SHIFT2 - 1, JMPTABL_START2);
-            TH_LRD(x3, x3, x2, 3);
-        }
-        TH_EXTU(x2, xRIP, JMPTABL_START1 + JMPTABL_SHIFT2 - 1, JMPTABL_START1);
-        TH_LRD(x3, x3, x2, 3);
-        TH_EXTU(x2, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
-        TH_LRD(x2, x3, x2, 3);
-    } else {
-        if (!rex.is32bits) {
-            SRLI(x2, xRIP, JMPTABL_START3);
-            ADDSL(x3, x3, x2, 3, x2);
-            LD(x3, x3, 0);
-            MOV64x(x4, JMPTABLE_MASK2 << 3); // x4 = mask
-            SRLI(x2, xRIP, JMPTABL_START2 - 3);
-            AND(x2, x2, x4);
-            ADD(x3, x3, x2);
-            LD(x3, x3, 0);
-            if (JMPTABLE_MASK2 != JMPTABLE_MASK1) {
-                MOV64x(x4, JMPTABLE_MASK1 << 3); // x4 = mask
-            }
-        } else {
-            MOV64x(x4, JMPTABLE_MASK1 << 3); // x4 = mask
-        }
-        SRLI(x2, xRIP, JMPTABL_START1 - 3);
-        AND(x2, x2, x4);
-        ADD(x3, x3, x2);
-        LD(x3, x3, 0);
-        if (JMPTABLE_MASK0 < 2048) {
-            ANDI(x2, xRIP, JMPTABLE_MASK0);
-        } else {
-            if (JMPTABLE_MASK1 != JMPTABLE_MASK0) {
-                MOV64x(x4, JMPTABLE_MASK0); // x4 = mask
-            }
-            AND(x2, xRIP, x4);
-        }
-        if (rv64_zba)
-            SH3ADD(x3, x2, x3);
-        else {
-            SLLI(x2, x2, 3);
-            ADD(x3, x3, x2);
-        }
-        LD(x2, x3, 0);
-    }
-    BR(x2);
+    int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
+    BR(dest);
     CLEARIP();
 }
 
@@ -942,7 +841,7 @@ void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w)
     int sextw_mask = ((w > 0 ? w : -w) >> 4) & 0b111111;
     for (int i = 0; i < 6; i++) {
         if (sextw_mask & (1 << i)) {
-            SEXT_W(A0+i, A0+i);
+            SEXT_W(A0 + i, A0 + i);
         }
     }
     // native call