diff options
| author | Yang Liu <numbksco@gmail.com> | 2024-04-12 19:13:30 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-12 13:13:30 +0200 |
| commit | 1d0e0307c4f2279803a1aa57533c45c6edeea12a (patch) | |
| tree | 63a6ed6f07cd6bede1b899886fa6e8701d8ca361 /src | |
| parent | f94ab1be6f23d4aeb6d1584b267d7620247a4953 (diff) | |
| download | box64-1d0e0307c4f2279803a1aa57533c45c6edeea12a.tar.gz box64-1d0e0307c4f2279803a1aa57533c45c6edeea12a.zip | |
[LA64_DYNAREC] Made the CALLRET optimization complete (#1438)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 12 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.c | 45 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 2 |
3 files changed, 59 insertions, 0 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index c32d1bc3..bf9722f6 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -1125,6 +1125,18 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + case 0xC2: + INST_NAME("RETN"); + // SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...) + if (box64_dynarec_safeflags) { + READFLAGS(X_PEND); // lets play safe here too + } + BARRIER(BARRIER_FLOAT); + i32 = F16; + retn_to_epilog(dyn, ninst, rex, i32); + *need_epilog = 0; + *ok = 0; + break; case 0xC3: INST_NAME("RET"); // SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...) diff --git a/src/dynarec/la64/dynarec_la64_helper.c b/src/dynarec/la64/dynarec_la64_helper.c index 5bba9433..917b0d6c 100644 --- a/src/dynarec/la64/dynarec_la64_helper.c +++ b/src/dynarec/la64/dynarec_la64_helper.c @@ -445,6 +445,51 @@ void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex) CLEARIP(); } +void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n) +{ + MAYUSE(dyn); + MAYUSE(ninst); + MESSAGE(LOG_DUMP, "Retn to epilog\n"); + POP1z(xRIP); + if (n > 0x7ff) { + MOV64x(w1, n); + ADDz(xRSP, xRSP, x1); + } else { + ADDIz(xRSP, xRSP, n); + } + MVz(x1, xRIP); + SMEND(); + if (box64_dynarec_callret) { + // pop the actual return address from RV64 stack + LD_D(x2, xSP, 0); // native addr + LD_D(x6, xSP, 8); // x86 addr + ADDI_D(xSP, xSP, 16); // pop + BNE(x6, xRIP, 2 * 4); // is it the right address? + BR(x2); + // 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); // save LR + CLEARIP(); +} + void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg) { MAYUSE(fnc); diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index 8f306681..bf5e5abb 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -629,6 +629,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define jump_to_epilog_fast STEPNAME(jump_to_epilog_fast) #define jump_to_next STEPNAME(jump_to_next) #define ret_to_epilog STEPNAME(ret_to_epilog) +#define retn_to_epilog STEPNAME(retn_to_epilog) #define call_c STEPNAME(call_c) #define grab_segdata STEPNAME(grab_segdata) #define emit_cmp16 STEPNAME(emit_cmp16) @@ -702,6 +703,7 @@ void jump_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst); void jump_to_epilog_fast(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst); void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits); void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex); +void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n); void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg); void grab_segdata(dynarec_la64_t* dyn, uintptr_t addr, int ninst, int reg, int segment); void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6); |