[DYNAREC] Fixed idiv optimisation, and added a new test about idiv opcode

This commit is contained in:
ptitSeb 2021-12-22 11:44:11 +01:00
parent 2879cf51cd
commit b655e89af0
6 changed files with 81 additions and 13 deletions

View File

@ -738,11 +738,16 @@ add_test(NAME longjumpInSignals COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME idiv COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
foreach(file ${extension_tests})
get_filename_component(testname "${file}" NAME_WE)

View File

@ -245,9 +245,12 @@ Op is 20-27
// cmp.s dst, src, #imm
#define CMPS_IMM8(src, imm8) \
EMIT(0xe3500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
// cmn.s dst, src, #imm
// cmn.s.cond dst, src, #imm
#define CMNS_IMM8_COND(cond, src, imm8) \
EMIT((cond) | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
// cmn.s dst, src, #imm
#define CMNS_IMM8(src, imm8) \
EMIT(c__ | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
// tst.s dst, src1, src2, lsl #imm
#define TSTS_REG_LSL_IMM5(src1, src2, imm5) \
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
@ -257,6 +260,9 @@ Op is 20-27
// tst.s dst, src1, #imm ror rot*2
#define TSTS_IMM8_ROR(src, imm8, rot) \
EMIT(0xe3100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// tst.s.cond dst, src1, #imm ror rot*2
#define TSTS_IMM8_ROR_COND(cond, src, imm8, rot) \
EMIT((cond) | 0x03100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// orr dst, src1, src2, lsl #imm
#define ORR_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )

View File

@ -2683,31 +2683,29 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETED;
SDIV(x2, xEAX, ed); // x1 = xEAX / ed
MLS(xEDX, x2, ed, xEAX); // x14 = xEAX mod ed (i.e. xEAX - x1*ed)
TSTS_IMM8_ROR(xEDX, 0b10, 1); // test if reminder is negative
ADD_REG_LSL_IMM5_COND(cNE, xEDX, xEDX, ed, 0); // add ed if negative
MOV_REG(xEAX, x2);
} else {
GETEDH(x1);
// disabling the use of SDIV for now. It breaks X3Reunion
// seems to be an issue with large number
// for example EDX=0xffffffff EAX=0xe7f30000 and div ecx=0x186a0
// gives wrong modulo
if(arm_div && 0) {
if(arm_div) {
// check if a 32bits division is enough
CMPS_IMM8(xEDX, 0); // compare to 0
CMNS_IMM8_COND(cNE, xEDX, 1); // compare to FFFFFFFF if not 0
TSTS_IMM8_ROR_COND(cEQ, xEAX, 0b10, 1); // also test that xEAX is not signed!
B_MARK(cEQ);
CMNS_IMM8(xEDX, 1); // compare to FFFFFFFF if not 0
B_MARK2(cNE);
TSTS_IMM8_ROR(xEAX, 0b10, 1); // also test that xEAX is signed!
B_MARK(cNE);
MARK2;
}
if(ed!=x1) {MOV_REG(x1, ed);}
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
CALL(idiv32, -1, 0);
LDM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
if(arm_div && 0) {
if(arm_div) {
B_NEXT(c__);
MARK;
SDIV(x2, xEAX, ed); // x2 = xEAX / ed
MLS(xEDX, x2, ed, xEAX); // x14 = xEAX mod ed (i.e. xEAX - x2*ed)
TSTS_IMM8_ROR(xEDX, 0b10, 1); // test if reminder is negative
ADD_REG_LSL_IMM5_COND(cNE, xEDX, xEDX, ed, 0); // add ed if negative
MOV_REG(xEAX, x2);
SET_DFNONE(x2); // flags are undefined
}

11
tests/ref20.txt Normal file
View File

@ -0,0 +1,11 @@
SDHLD/SAR/IDIV 0x2d0 0x500 => 0x0 / 0x9000 (47185920/1280 => 36864 + 0)
SDHLD/SAR/IDIV 0xfffffa5d 0x186a0 => 0xfffef4a0 / 0xfffffc4f (281474882142208/100000 => -945 + -68448)
SDHLD/SAR/IDIV 0x1701 0x186a0 => 0xa220 / 0xf13 (385941504/100000 => 3859 + 41504)
SDHLD/SAR/IDIV 0xffff9a19 0x186a0 => 0xffff6d00 / 0xffffbd38 (281473267073024/100000 => -17096 + -37632)
SDHLD/SAR/IDIV 0xffffe7f3 0x186a0 => 0xffffebe0 / 0xfffff03d (281474573205504/100000 => -4035 + -5152)
SDHLD/SAR/IDIV 0x15840 0x186a0 => 0xdd20 / 0xe19b (5775556608/100000 => 57755 + 56608)
SDHLD/SAR/IDIV 0xff451330 0x186a0 => 0xfffee8a0 / 0xff857f2f (280672139739136/100000 => -8028369 + -71520)
SDHLD/SAR/IDIV 0xffff626a 0x186a0 => 0xffff2fc0 / 0xffff98ba (281472332857344/100000 => -26438 + -53312)
SDHLD/SAR/IDIV 0x9120 0x186a0 => 0x16d20 / 0x5f1b (2434793472/100000 => 24347 + 93472)
Done

BIN
tests/test20 Executable file

Binary file not shown.

48
tests/test20.c Normal file
View File

@ -0,0 +1,48 @@
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#if defined(__x86_64__)
#error Nope!
#else
__attribute__((naked)) uint64_t _idiv_(uint32_t a, uint32_t b)
{
asm volatile (
"xor %%eax, %%eax\n"
"mov 4(%%esp), %%edx\n"
"mov 8(%%esp), %%ecx\n"
"shrd $0x10, %%edx, %%eax\n"
"sar $0x10, %%edx\n"
"idiv %%ecx\n"
"ret"
:::);
}
#endif
int main(int argc, const char** argv)
{
uint32_t tests[][2] = {
{0x000002d0, 0x00000500},
{0xfffffa5d, 0x000186a0},
{0x00001701, 0x000186a0},
{0xffff9a19, 0x000186a0},
{0xffffe7f3, 0x000186a0},
{0x00015840, 0x000186a0},
{0xff451330, 0x000186a0},
{0xffff626a, 0x000186a0},
{0x00009120, 0x000186a0},
};
int n = sizeof(tests)/sizeof(tests[0]);
uint64_t res;
for(int i=0; i<n; ++i) {
printf("SDHLD/SAR/IDIV 0x%x 0x%x ", tests[i][0], tests[i][1]);
res = _idiv_(tests[i][0], tests[i][1]);
uint32_t divi = res & 0xffffffffLL;
uint32_t modo = res >> 32;
printf("=> 0x%x / 0x%x (%lld/%d => %d + %d)\n", modo, divi, ((int64_t)tests[i][0])<<16, tests[i][1], divi, modo);
}
printf("\nDone\n");
}