diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-06-18 11:22:57 +0200 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-06-18 11:22:57 +0200 |
| commit | 3dcef655c37cc2e9656cb79007ab4f6ad6da5b67 (patch) | |
| tree | f41edbf1c6cc37dab8c433f973d249c33d891813 /src | |
| parent | 4c476de74b8124c2f70c18e7397199a41105c065 (diff) | |
| download | box64-3dcef655c37cc2e9656cb79007ab4f6ad6da5b67.tar.gz box64-3dcef655c37cc2e9656cb79007ab4f6ad6da5b67.zip | |
[DYNAREC] Optimized DIV/IDIV 32/64bits opcodes
Diffstat (limited to 'src')
| -rwxr-xr-x | src/dynarec/arm64_emitter.h | 22 | ||||
| -rwxr-xr-x | src/dynarec/arm64_printer.c | 13 | ||||
| -rwxr-xr-x | src/dynarec/dynarec_arm64_00.c | 78 | ||||
| -rwxr-xr-x | src/dynarec/dynarec_arm64_helper.h | 10 |
4 files changed, 112 insertions, 11 deletions
diff --git a/src/dynarec/arm64_emitter.h b/src/dynarec/arm64_emitter.h index b64413ef..3114d214 100755 --- a/src/dynarec/arm64_emitter.h +++ b/src/dynarec/arm64_emitter.h @@ -580,13 +580,27 @@ #define UMULH(Xd, Xn, Xm) EMIT(MULH_gen(1, Xm, Xn, Xd)) #define SMULH(Xd, Xn, Xm) EMIT(MULH_gen(0, Xm, Xn, Xd)) -#define MADD_gen(sf, Rm, Ra, Rn, Rd) ((sf)<<31 | 0b11011<<24 | (Rm)<<16 | (Ra)<<10 | (Rn)<<5 | (Rd)) -#define MADDx(Rd, Rn, Rm, Ra) EMIT(MADD_gen(1, Rm, Ra, Rn, Rd)) -#define MADDw(Rd, Rn, Rm, Ra) EMIT(MADD_gen(0, Rm, Ra, Rn, Rd)) -#define MADDxw(Rd, Rn, Rm, Ra) EMIT(MADD_gen(rex.w, Rm, Ra, Rn, Rd)) +#define MADD_gen(sf, Rm, o0, Ra, Rn, Rd) ((sf)<<31 | 0b11011<<24 | (Rm)<<16 | (o0)<<15 | (Ra)<<10 | (Rn)<<5 | (Rd)) +#define MADDx(Rd, Rn, Rm, Ra) EMIT(MADD_gen(1, Rm, 0, Ra, Rn, Rd)) +#define MADDw(Rd, Rn, Rm, Ra) EMIT(MADD_gen(0, Rm, 0, Ra, Rn, Rd)) +#define MADDxw(Rd, Rn, Rm, Ra) EMIT(MADD_gen(rex.w, Rm, 0, Ra, Rn, Rd)) #define MULx(Rd, Rn, Rm) MADDx(Rd, Rn, Rm, xZR) #define MULw(Rd, Rn, Rm) MADDw(Rd, Rn, Rm, xZR) #define MULxw(Rd, Rn, Rm) MADDxw(Rd, Rn, Rm, xZR) +#define MSUBx(Rd, Rn, Rm, Ra) EMIT(MADD_gen(1, Rm, 1, Ra, Rn, Rd)) +#define MSUBw(Rd, Rn, Rm, Ra) EMIT(MADD_gen(0, Rm, 1, Ra, Rn, Rd)) +#define MSUBxw(Rd, Rn, Rm, Ra) EMIT(MADD_gen(rex.w, Rm, 1, Ra, Rn, Rd)) +#define MNEGx(Rd, Rn, Rm) EMIT(MADD_gen(1, Rm, 1, xZR, Rn, Rd)) +#define MNEGw(Rd, Rn, Rm) EMIT(MADD_gen(0, Rm, 1, xZR, Rn, Rd)) +#define MNEGxw(Rd, Rn, Rm) EMIT(MADD_gen(rex.w, Rm, 1, xZR, Rn, Rd)) + + +// DIV +#define DIV_gen(sf, Rm, o1, Rn, Rd) ((sf)<<31 | 0b11010110<<21 | (Rm)<<16 | 0b00001<<11 | (o1)<<10 | (Rn)<<5 | (Rd)) +#define UDIVw(Wd, Wn, Wm) EMIT(DIV_gen(0, Wm, 0, Wn, Wd)) +#define UDIVx(Xd, Xn, Xm) EMIT(DIV_gen(1, Xm, 0, Xn, Xd)) +#define SDIVw(Wd, Wn, Wm) EMIT(DIV_gen(0, Wm, 1, Wn, Wd)) +#define SDIVx(Xd, Xn, Xm) EMIT(DIV_gen(1, Xm, 1, Xn, Xd)) // CLZ #define CL_gen(sf, op, Rn, Rd) ((sf)<<31 | 1<<30 | 0b11010110<<21 | 0b00010<<11 | (op)<<10 | (Rn)<<5 | (Rd)) diff --git a/src/dynarec/arm64_printer.c b/src/dynarec/arm64_printer.c index f0ca7f36..b2c90dda 100755 --- a/src/dynarec/arm64_printer.c +++ b/src/dynarec/arm64_printer.c @@ -777,6 +777,19 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr) snprintf(buff, sizeof(buff), "MADD %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], sf?Xt[Ra]:Wt[Ra]); return buff; } + if(isMask(opcode, "f0011011000mmmmm1aaaaannnnnddddd", &a)) { + if(Ra==31) + snprintf(buff, sizeof(buff), "MNEG %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]); + else + snprintf(buff, sizeof(buff), "MSUB %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], sf?Xt[Ra]:Wt[Ra]); + return buff; + } + + // DIV + if(isMask(opcode, "f0011010110mmmmm00001onnnnnddddd", &a)) { + snprintf(buff, sizeof(buff), "%cDIV %s, %s, %s", option?'S':'U', sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]); + return buff; + } // MRS / MSR if(isMask(opcode, "110101010001opppnnnnmmmm222ttttt", &a)) { diff --git a/src/dynarec/dynarec_arm64_00.c b/src/dynarec/dynarec_arm64_00.c index 4e0721d2..3a136b12 100755 --- a/src/dynarec/dynarec_arm64_00.c +++ b/src/dynarec/dynarec_arm64_00.c @@ -35,13 +35,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin uint8_t gb1, gb2, eb1, eb2; uint32_t u32; uint64_t u64; - uint8_t wback, wb1, wb2; + uint8_t wback, wb1, wb2, wb; int64_t fixedaddress; opcode = F8; MAYUSE(eb1); MAYUSE(eb2); MAYUSE(j64); + MAYUSE(wb); switch(opcode) { case 0x00: @@ -2171,16 +2172,79 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin case 6: INST_NAME("DIV Ed"); SETFLAGS(X_ALL, SF_SET); - GETEDH(x1, 0); - if(ed!=x1) {MOVxw_REG(x1, ed);} - CALL(rex.w?((void*)div64):((void*)div32), -1); + if(!rex.w) { + SET_DFNONE(x2); + GETED(0); + MOVw_REG(x3, xRAX); + ORRx_REG_LSL(x3, x3, xRDX, 32); + if(MODREG) { + MOVw_REG(x4, ed); + ed = x4; + } + UDIVx(x2, x3, ed); + MSUBx(x4, x2, ed, xRAX); + MOVw_REG(xRAX, x2); + MOVw_REG(xRDX, x4); + } else { + if(ninst && dyn->insts + && dyn->insts[ninst-1].x64.addr + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31 + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) { + SET_DFNONE(x2); + GETED(0); + UDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVx_REG(xRAX, x2); + } else { + GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + CBZxw_MARK(xRDX); + if(ed!=x1) {MOVxw_REG(x1, ed);} + CALL(div64, -1); + B_NEXT_nocond; + MARK; + UDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVx_REG(xRAX, x2); + SET_DFNONE(x2); + } + } break; case 7: INST_NAME("IDIV Ed"); SETFLAGS(X_ALL, SF_SET); - GETEDH(x1, 0); - if(ed!=x1) {MOVxw_REG(x1, ed);} - CALL(rex.w?((void*)idiv64):((void*)idiv32), -1); + if(!rex.w) { + SET_DFNONE(x2) + GETSEDw(0); + MOVw_REG(x3, xRAX); + ORRx_REG_LSL(x3, x3, xRDX, 32); + SDIVx(x2, x3, wb); + MSUBx(x4, x2, wb, x3); + MOVw_REG(xRAX, x2); + MOVw_REG(xRDX, x4); + } else { + if(ninst && dyn->insts + && dyn->insts[ninst-1].x64.addr + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x99) { + SET_DFNONE(x2) + GETED(0); + SDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVw_REG(xRAX, x2); + } else { + GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + CBZxw_MARK(xRDX); + MVNx_REG(x2, xRDX); + CBZxw_MARK(x2); + if(ed!=x1) {MOVxw_REG(x1, ed);} + CALL((void*)idiv64, -1); + B_NEXT_nocond; + MARK; + SDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVw_REG(xRAX, x2); + SET_DFNONE(x2) + } + } break; } break; diff --git a/src/dynarec/dynarec_arm64_helper.h b/src/dynarec/dynarec_arm64_helper.h index cf778874..aae92a2d 100755 --- a/src/dynarec/dynarec_arm64_helper.h +++ b/src/dynarec/dynarec_arm64_helper.h @@ -59,6 +59,16 @@ LDRw_U12(x1, wback, fixedaddress); \ ed = x1; \ } +#define GETSEDw(D) if((nextop&0xC0)==0xC0) { \ + ed = xRAX+(nextop&7)+(rex.b<<3); \ + SXTWx(x1, ed); \ + wb = x1; \ + wback = 0; \ + } else { \ + addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \ + LDRw_U12(x1, wback, fixedaddress); \ + wb = ed = x1; \ + } //GETEDH can use hint for ed, and r1 or r2 for wback (depending on hint). wback is 0 if ed is xEAX..xEDI #define GETEDH(hint, D) if(MODREG) { \ ed = xRAX+(nextop&7)+(rex.b<<3); \ |