From 90f98e7cf5ed4fdabf6b6ff16d6886fef9dc7bbc Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 30 Jul 2023 00:08:55 +0300 Subject: [PATCH] drc: try to prevent wrong eviction --- libpcsxcore/new_dynarec/assem_arm.c | 22 +- libpcsxcore/new_dynarec/assem_arm64.c | 12 +- libpcsxcore/new_dynarec/emu_if.c | 1 + libpcsxcore/new_dynarec/new_dynarec.c | 294 ++++++++------------- libpcsxcore/new_dynarec/patches/trace_intr | 17 +- 5 files changed, 145 insertions(+), 201 deletions(-) diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index a7bdfbda..bdb81b4d 100644 --- a/libpcsxcore/new_dynarec/assem_arm.c +++ b/libpcsxcore/new_dynarec/assem_arm.c @@ -217,16 +217,26 @@ static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr) } } - cur->regmap[hr]=reg; - cur->dirty&=~(1<dirty|=dirty<isconst&=~(1<regmap[hr] < 0 || !((cur->noevict >> hr) & 1)); + cur->regmap[hr] = reg; + cur->dirty &= ~(1 << hr); + cur->dirty |= dirty << hr; + cur->isconst &= ~(1u << hr); + cur->noevict |= 1u << hr; } // Alloc cycle count into dedicated register -static void alloc_cc(struct regstat *cur,int i) +static void alloc_cc(struct regstat *cur, int i) { - alloc_arm_reg(cur,i,CCREG,HOST_CCREG); + alloc_arm_reg(cur, i, CCREG, HOST_CCREG); +} + +static void alloc_cc_optional(struct regstat *cur, int i) +{ + if (cur->regmap[HOST_CCREG] < 0) { + alloc_arm_reg(cur, i, CCREG, HOST_CCREG); + cur->noevict &= ~(1u << HOST_CCREG); + } } /* Assembler */ diff --git a/libpcsxcore/new_dynarec/assem_arm64.c b/libpcsxcore/new_dynarec/assem_arm64.c index 0a29eaf4..dc5bb4db 100644 --- a/libpcsxcore/new_dynarec/assem_arm64.c +++ b/libpcsxcore/new_dynarec/assem_arm64.c @@ -101,9 +101,17 @@ static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr) } // Alloc cycle count into dedicated register -static void alloc_cc(struct regstat *cur,int i) +static void alloc_cc(struct regstat *cur, int i) { - alloc_arm_reg(cur,i,CCREG,HOST_CCREG); + alloc_arm_reg(cur, i, CCREG, HOST_CCREG); +} + +static void alloc_cc_optional(struct regstat *cur, int i) +{ + if (cur->regmap[HOST_CCREG] < 0) { + alloc_arm_reg(cur, i, CCREG, HOST_CCREG); + cur->noevict &= ~(1u << HOST_CCREG); + } } /* Special alloc */ diff --git a/libpcsxcore/new_dynarec/emu_if.c b/libpcsxcore/new_dynarec/emu_if.c index 2862c546..06612dbf 100644 --- a/libpcsxcore/new_dynarec/emu_if.c +++ b/libpcsxcore/new_dynarec/emu_if.c @@ -298,6 +298,7 @@ static void ari64_notify(enum R3000Anote note, void *data) { break; case R3000ACPU_NOTIFY_AFTER_LOAD: ari64_reset(); + psxInt.Notify(note, data); break; } } diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index e95d165c..00d307b3 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -164,6 +164,7 @@ struct regstat u_int wasconst; // before; for example 'lw r2, (r2)' wasconst is true u_int isconst; // ... but isconst is false when r2 is known (hr) u_int loadedconst; // host regs that have constants loaded + u_int noevict; // can't evict this hr (alloced by current op) //u_int waswritten; // MIPS regs that were used as store base before }; @@ -982,7 +983,7 @@ static uint32_t get_const(const struct regstat *cur, signed char reg) // Least soon needed registers // Look at the next ten instructions and see which registers // will be used. Try not to reallocate these. -static void lsn(u_char hsn[], int i, int *preferred_reg) +static void lsn(u_char hsn[], int i) { int j; int b=-1; @@ -1656,6 +1657,72 @@ void ndrc_add_jump_out(u_int vaddr, void *src) /* Register allocation */ +static void alloc_set(struct regstat *cur, int reg, int hr) +{ + cur->regmap[hr] = reg; + cur->dirty &= ~(1u << hr); + cur->isconst &= ~(1u << hr); + cur->noevict |= 1u << hr; +} + +static void evict_alloc_reg(struct regstat *cur, int i, int reg, int preferred_hr) +{ + u_char hsn[MAXREG+1]; + int j, r, hr; + memset(hsn, 10, sizeof(hsn)); + lsn(hsn, i); + //printf("hsn(%x): %d %d %d %d %d %d %d\n",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); + if(i>0) { + // Don't evict the cycle count at entry points, otherwise the entry + // stub will have to write it. + if(dops[i].bt&&hsn[CCREG]>2) hsn[CCREG]=2; + if (i>1 && hsn[CCREG] > 2 && dops[i-2].is_jump) hsn[CCREG]=2; + for(j=10;j>=3;j--) + { + // Alloc preferred register if available + if (!((cur->noevict >> preferred_hr) & 1) + && hsn[cur->regmap[preferred_hr]] == j) + { + alloc_set(cur, reg, preferred_hr); + return; + } + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j&&r!=dops[i-1].rs1&&r!=dops[i-1].rs2&&r!=dops[i-1].rt1&&r!=dops[i-1].rt2) { + for(hr=0;hrnoevict >> hr) & 1)) + continue; + if(hr!=HOST_CCREG||jregmap[hr]==r) { + alloc_set(cur, reg, hr); + return; + } + } + } + } + } + } + } + for(j=10;j>=0;j--) + { + for(r=1;r<=MAXREG;r++) + { + if(hsn[r]==j) { + for(hr=0;hrnoevict >> hr) & 1)) + continue; + if(cur->regmap[hr]==r) { + alloc_set(cur, reg, hr); + return; + } + } + } + } + } + SysPrintf("This shouldn't happen (evict_alloc_reg)\n"); + abort(); +} + // Note: registers are allocated clean (unmodified state) // if you intend to modify the register, you must call dirty_reg(). static void alloc_reg(struct regstat *cur,int i,signed char reg) @@ -1672,25 +1739,23 @@ static void alloc_reg(struct regstat *cur,int i,signed char reg) if((cur->u>>reg)&1) return; // see if it's already allocated - if (get_reg(cur->regmap, reg) >= 0) + if ((hr = get_reg(cur->regmap, reg)) >= 0) { + cur->noevict |= 1u << hr; return; + } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register - if(cur->regmap[preferred_reg]==-1) { - cur->regmap[preferred_reg]=reg; - cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg] == -1) { + alloc_set(cur, reg, preferred_reg); return; } r=cur->regmap[preferred_reg]; assert(r < 64); if((cur->u>>r)&1) { - cur->regmap[preferred_reg]=reg; - cur->dirty&=~(1<isconst&=~(1<regmap[hr]=reg; - cur->dirty&=~(1<isconst&=~(1<regmap[hr] < 0) { - cur->regmap[hr]=reg; - cur->dirty&=~(1<isconst&=~(1<regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]); - //printf("hsn(%x): %d %d %d %d %d %d %d\n",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); - if(i>0) { - // Don't evict the cycle count at entry points, otherwise the entry - // stub will have to write it. - if(dops[i].bt&&hsn[CCREG]>2) hsn[CCREG]=2; - if (i>1 && hsn[CCREG] > 2 && dops[i-2].is_jump) hsn[CCREG]=2; - for(j=10;j>=3;j--) - { - // Alloc preferred register if available - if(hsn[r=cur->regmap[preferred_reg]&63]==j) { - for(hr=0;hrregmap[hr]==r) { - cur->regmap[hr]=-1; - cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg; - return; - } - for(r=1;r<=MAXREG;r++) - { - if(hsn[r]==j&&r!=dops[i-1].rs1&&r!=dops[i-1].rs2&&r!=dops[i-1].rt1&&r!=dops[i-1].rt2) { - for(hr=0;hrregmap[hr]==r) { - cur->regmap[hr]=reg; - cur->dirty&=~(1<isconst&=~(1<=0;j--) - { - for(r=1;r<=MAXREG;r++) - { - if(hsn[r]==j) { - for(hr=0;hrregmap[hr]==r) { - cur->regmap[hr]=reg; - cur->dirty&=~(1<isconst&=~(1<regmap[hr]==reg) return; + if (hr != EXCLUDE_REG && cur->regmap[hr] == reg) { + cur->noevict |= 1u << hr; + return; + } } // Try to allocate any available register for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { - cur->regmap[hr]=reg; - cur->dirty&=~(1<isconst&=~(1<u>>r)&1) { if(i==0||((unneeded_reg[i-1]>>r)&1)) { - cur->regmap[hr]=reg; - cur->dirty&=~(1<isconst&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); - if(i>0) { - // Don't evict the cycle count at entry points, otherwise the entry - // stub will have to write it. - if(dops[i].bt&&hsn[CCREG]>2) hsn[CCREG]=2; - if (i>1 && hsn[CCREG] > 2 && dops[i-2].is_jump) hsn[CCREG]=2; - for(j=10;j>=3;j--) - { - for(r=1;r<=MAXREG;r++) - { - if(hsn[r]==j&&r!=dops[i-1].rs1&&r!=dops[i-1].rs2&&r!=dops[i-1].rt1&&r!=dops[i-1].rt2) { - for(hr=0;hr2) { - if(cur->regmap[hr]==r) { - cur->regmap[hr]=reg; - cur->dirty&=~(1<isconst&=~(1<=0;j--) - { - for(r=1;r<=MAXREG;r++) - { - if(hsn[r]==j) { - for(hr=0;hrregmap[hr]==r) { - cur->regmap[hr]=reg; - cur->dirty&=~(1<isconst&=~(1<u>>dops[i].rt1)&1)) { @@ -2106,7 +2058,8 @@ static void load_alloc(struct regstat *current,int i) } } -static void store_alloc(struct regstat *current,int i) +// this may eat up to 7 registers +static void store_alloc(struct regstat *current, int i) { clear_const(current,dops[i].rs2); if(!(dops[i].rs2)) current->u&=~1LL; // Allow allocating r0 if necessary @@ -2121,16 +2074,14 @@ static void store_alloc(struct regstat *current,int i) if (dops[i].opcode == 0x2a || dops[i].opcode == 0x2e) { // SWL/SWL alloc_reg(current,i,FTEMP); } - if (dops[i].may_except) { - alloc_cc(current, i); // for exceptions - dirty_reg(current, CCREG); - } + if (dops[i].may_except) + alloc_cc_optional(current, i); // for exceptions // We need a temporary register for address generation alloc_reg_temp(current,i,-1); cinfo[i].min_free_regs=1; } -static void c2ls_alloc(struct regstat *current,int i) +static void c2ls_alloc(struct regstat *current, int i) { clear_const(current,dops[i].rt1); if(needed_again(dops[i].rs1,i)) alloc_reg(current,i,dops[i].rs1); @@ -2142,10 +2093,8 @@ static void c2ls_alloc(struct regstat *current,int i) if (dops[i].opcode == 0x3a) // SWC2 alloc_reg(current,i,INVCP); #endif - if (dops[i].may_except) { - alloc_cc(current, i); // for exceptions - dirty_reg(current, CCREG); - } + if (dops[i].may_except) + alloc_cc_optional(current, i); // for exceptions // We need a temporary register for address generation alloc_reg_temp(current,i,-1); cinfo[i].min_free_regs=1; @@ -2161,6 +2110,7 @@ static void multdiv_alloc(struct regstat *current,int i) clear_const(current,dops[i].rs1); clear_const(current,dops[i].rs2); alloc_cc(current,i); // for stalls + dirty_reg(current,CCREG); if(dops[i].rs1&&dops[i].rs2) { current->u&=~(1LL<regmap); if (do_oflow) assert(tmp >= 0); - //if (t < 0 && do_oflow) // broken s2 - // t = tmp; + if (t < 0 && do_oflow) + t = tmp; if (t >= 0) { s1 = get_reg(i_regs->regmap, dops[i].rs1); s2 = get_reg(i_regs->regmap, dops[i].rs2); @@ -7190,15 +7140,6 @@ static noinline void pass2_unneeded_regs(int istart,int iend,int r) } } } - else if(dops[i].may_except) - { - // SYSCALL instruction, etc or conditional exception - u=1; - } - else if (dops[i].itype == RFE) - { - u=1; - } //u=1; // DEBUG // Written registers are unneeded u|=1LL<