- int i;
- uint64_t u,gte_u,b,gte_b;
- uint64_t temp_u,temp_gte_u=0;
- uint64_t gte_u_unknown=0;
- if (HACK_ENABLED(NDHACK_GTE_UNNEEDED))
- gte_u_unknown=~0ll;
- if(iend==slen-1) {
- u=1;
- gte_u=gte_u_unknown;
- }else{
- //u=unneeded_reg[iend+1];
- u=1;
- gte_u=gte_unneeded[iend+1];
- }
-
- for (i=iend;i>=istart;i--)
- {
- //printf("unneeded registers i=%d (%d,%d) r=%d\n",i,istart,iend,r);
- if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP)
- {
- // If subroutine call, flag return address as a possible branch target
- if(rt1[i]==31 && i<slen-2) bt[i+2]=1;
-
- if(ba[i]<start || ba[i]>=(start+slen*4))
- {
- // Branch out of this block, flush all regs
- u=1;
- gte_u=gte_u_unknown;
- branch_unneeded_reg[i]=u;
- // Merge in delay slot
- u|=(1LL<<rt1[i+1])|(1LL<<rt2[i+1]);
- u&=~((1LL<<rs1[i+1])|(1LL<<rs2[i+1]));
- u|=1;
- gte_u|=gte_rt[i+1];
- gte_u&=~gte_rs[i+1];
- // If branch is "likely" (and conditional)
- // then we skip the delay slot on the fall-thru path
- if(likely[i]) {
- if(i<slen-1) {
- u&=unneeded_reg[i+2];
- gte_u&=gte_unneeded[i+2];
- }
- else
- {
- u=1;
- gte_u=gte_u_unknown;
- }
- }
- }
- else
- {
- // Internal branch, flag target
- bt[(ba[i]-start)>>2]=1;
- if(ba[i]<=start+i*4) {
- // Backward branch
- if(is_ujump(i))
- {
- // Unconditional branch
- temp_u=1;
- temp_gte_u=0;
- } else {
- // Conditional branch (not taken case)
- temp_u=unneeded_reg[i+2];
- temp_gte_u&=gte_unneeded[i+2];
- }
- // Merge in delay slot
- temp_u|=(1LL<<rt1[i+1])|(1LL<<rt2[i+1]);
- temp_u&=~((1LL<<rs1[i+1])|(1LL<<rs2[i+1]));
- temp_u|=1;
- temp_gte_u|=gte_rt[i+1];
- temp_gte_u&=~gte_rs[i+1];
- // If branch is "likely" (and conditional)
- // then we skip the delay slot on the fall-thru path
- if(likely[i]) {
- if(i<slen-1) {
- temp_u&=unneeded_reg[i+2];
- temp_gte_u&=gte_unneeded[i+2];
- }
- else
- {
- temp_u=1;
- temp_gte_u=gte_u_unknown;
- }
- }
- temp_u|=(1LL<<rt1[i])|(1LL<<rt2[i]);
- temp_u&=~((1LL<<rs1[i])|(1LL<<rs2[i]));
- temp_u|=1;
- temp_gte_u|=gte_rt[i];
- temp_gte_u&=~gte_rs[i];
- unneeded_reg[i]=temp_u;
- gte_unneeded[i]=temp_gte_u;
- // Only go three levels deep. This recursion can take an
- // excessive amount of time if there are a lot of nested loops.
- if(r<2) {
- unneeded_registers((ba[i]-start)>>2,i-1,r+1);
- }else{
- unneeded_reg[(ba[i]-start)>>2]=1;
- gte_unneeded[(ba[i]-start)>>2]=gte_u_unknown;
- }
- } /*else*/ if(1) {
- if (is_ujump(i))
- {
- // Unconditional branch
- u=unneeded_reg[(ba[i]-start)>>2];
- gte_u=gte_unneeded[(ba[i]-start)>>2];
- branch_unneeded_reg[i]=u;
- // Merge in delay slot
- u|=(1LL<<rt1[i+1])|(1LL<<rt2[i+1]);
- u&=~((1LL<<rs1[i+1])|(1LL<<rs2[i+1]));
- u|=1;
- gte_u|=gte_rt[i+1];
- gte_u&=~gte_rs[i+1];
- } else {
- // Conditional branch
- b=unneeded_reg[(ba[i]-start)>>2];
- gte_b=gte_unneeded[(ba[i]-start)>>2];
- branch_unneeded_reg[i]=b;
- // Branch delay slot
- b|=(1LL<<rt1[i+1])|(1LL<<rt2[i+1]);
- b&=~((1LL<<rs1[i+1])|(1LL<<rs2[i+1]));
- b|=1;
- gte_b|=gte_rt[i+1];
- gte_b&=~gte_rs[i+1];
- // If branch is "likely" then we skip the
- // delay slot on the fall-thru path
- if(likely[i]) {
- u=b;
- gte_u=gte_b;
- if(i<slen-1) {
- u&=unneeded_reg[i+2];
- gte_u&=gte_unneeded[i+2];
- }
- } else {
- u&=b;
- gte_u&=gte_b;
- }
- if(i<slen-1) {
- branch_unneeded_reg[i]&=unneeded_reg[i+2];
- } else {
- branch_unneeded_reg[i]=1;
- }
- }
- }
- }
- }
- else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
- {
- // SYSCALL instruction (software interrupt)
- u=1;
- }
- else if(itype[i]==COP0 && (source[i]&0x3f)==0x18)
- {
- // ERET instruction (return from interrupt)
- u=1;
- }
- //u=1; // DEBUG
- // Written registers are unneeded
- u|=1LL<<rt1[i];
- u|=1LL<<rt2[i];
- gte_u|=gte_rt[i];
- // Accessed registers are needed
- u&=~(1LL<<rs1[i]);
- u&=~(1LL<<rs2[i]);
- gte_u&=~gte_rs[i];
- if(gte_rs[i]&&rt1[i]&&(unneeded_reg[i+1]&(1ll<<rt1[i])))
- gte_u|=gte_rs[i]>e_unneeded[i+1]; // MFC2/CFC2 to dead register, unneeded
- // Source-target dependencies
- // R0 is always unneeded
- u|=1;
- // Save it
- unneeded_reg[i]=u;
- gte_unneeded[i]=gte_u;
- /*
- printf("ur (%d,%d) %x: ",istart,iend,start+i*4);
- printf("U:");
- int r;
- for(r=1;r<=CCREG;r++) {
- if((unneeded_reg[i]>>r)&1) {
- if(r==HIREG) printf(" HI");
- else if(r==LOREG) printf(" LO");
- else printf(" r%d",r);
- }
- }
- printf("\n");
- */
- }
-}
-
-// Write back dirty registers as soon as we will no longer modify them,
-// so that we don't end up with lots of writes at the branches.
-void clean_registers(int istart,int iend,int wr)
-{
- int i;
- int r;
- u_int will_dirty_i,will_dirty_next,temp_will_dirty;
- u_int wont_dirty_i,wont_dirty_next,temp_wont_dirty;
- if(iend==slen-1) {
- will_dirty_i=will_dirty_next=0;
- wont_dirty_i=wont_dirty_next=0;
- }else{
- will_dirty_i=will_dirty_next=will_dirty[iend+1];
- wont_dirty_i=wont_dirty_next=wont_dirty[iend+1];
- }
- for (i=iend;i>=istart;i--)
- {
- if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP)
- {
- if(ba[i]<start || ba[i]>=(start+slen*4))
- {
- // Branch out of this block, flush all regs
- if (is_ujump(i))
- {
- // Unconditional branch
- will_dirty_i=0;
- wont_dirty_i=0;
- // Merge in delay slot (will dirty)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if((branch_regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(branch_regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
- if(branch_regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- }
- }
- }
- else
- {
- // Conditional branch
- will_dirty_i=0;
- wont_dirty_i=wont_dirty_next;
- // Merge in delay slot (will dirty)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if(!likely[i]) {
- // Might not dirty if likely branch is not taken
- if((branch_regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(branch_regs[i].regmap[r]==0) will_dirty_i&=~(1<<r);
- if(branch_regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- //if((regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- //if((regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- }
- }
- }
- }
- // Merge in delay slot (wont dirty)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if((regs[i].regmap[r]&63)==rt1[i]) wont_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i]) wont_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) wont_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) wont_dirty_i|=1<<r;
- if(regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i]) wont_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) wont_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) wont_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) wont_dirty_i|=1<<r;
- if(branch_regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
- }
- }
- if(wr) {
- #ifndef DESTRUCTIVE_WRITEBACK
- branch_regs[i].dirty&=wont_dirty_i;
- #endif
- branch_regs[i].dirty|=will_dirty_i;
- }
- }
- else
- {
- // Internal branch
- if(ba[i]<=start+i*4) {
- // Backward branch
- if (is_ujump(i))
- {
- // Unconditional branch
- temp_will_dirty=0;
- temp_wont_dirty=0;
- // Merge in delay slot (will dirty)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if((branch_regs[i].regmap[r]&63)==rt1[i]) temp_will_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) temp_will_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) temp_will_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) temp_will_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)>33) temp_will_dirty&=~(1<<r);
- if(branch_regs[i].regmap[r]<=0) temp_will_dirty&=~(1<<r);
- if(branch_regs[i].regmap[r]==CCREG) temp_will_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i]) temp_will_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i]) temp_will_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) temp_will_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) temp_will_dirty|=1<<r;
- if((regs[i].regmap[r]&63)>33) temp_will_dirty&=~(1<<r);
- if(regs[i].regmap[r]<=0) temp_will_dirty&=~(1<<r);
- if(regs[i].regmap[r]==CCREG) temp_will_dirty|=1<<r;
- }
- }
- } else {
- // Conditional branch (not taken case)
- temp_will_dirty=will_dirty_next;
- temp_wont_dirty=wont_dirty_next;
- // Merge in delay slot (will dirty)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if(!likely[i]) {
- // Will not dirty if likely branch is not taken
- if((branch_regs[i].regmap[r]&63)==rt1[i]) temp_will_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) temp_will_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) temp_will_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) temp_will_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)>33) temp_will_dirty&=~(1<<r);
- if(branch_regs[i].regmap[r]==0) temp_will_dirty&=~(1<<r);
- if(branch_regs[i].regmap[r]==CCREG) temp_will_dirty|=1<<r;
- //if((regs[i].regmap[r]&63)==rt1[i]) temp_will_dirty|=1<<r;
- //if((regs[i].regmap[r]&63)==rt2[i]) temp_will_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) temp_will_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) temp_will_dirty|=1<<r;
- if((regs[i].regmap[r]&63)>33) temp_will_dirty&=~(1<<r);
- if(regs[i].regmap[r]<=0) temp_will_dirty&=~(1<<r);
- if(regs[i].regmap[r]==CCREG) temp_will_dirty|=1<<r;
- }
- }
- }
- }
- // Merge in delay slot (wont dirty)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if((regs[i].regmap[r]&63)==rt1[i]) temp_wont_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i]) temp_wont_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) temp_wont_dirty|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) temp_wont_dirty|=1<<r;
- if(regs[i].regmap[r]==CCREG) temp_wont_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i]) temp_wont_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) temp_wont_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) temp_wont_dirty|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) temp_wont_dirty|=1<<r;
- if(branch_regs[i].regmap[r]==CCREG) temp_wont_dirty|=1<<r;
- }
- }
- // Deal with changed mappings
- if(i<iend) {
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if(regs[i].regmap[r]!=regmap_pre[i][r]) {
- temp_will_dirty&=~(1<<r);
- temp_wont_dirty&=~(1<<r);
- if((regmap_pre[i][r]&63)>0 && (regmap_pre[i][r]&63)<34) {
- temp_will_dirty|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<<r;
- temp_wont_dirty|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<<r;
- } else {
- temp_will_dirty|=1<<r;
- temp_wont_dirty|=1<<r;
- }
- }
- }
- }
- }
- if(wr) {
- will_dirty[i]=temp_will_dirty;
- wont_dirty[i]=temp_wont_dirty;
- clean_registers((ba[i]-start)>>2,i-1,0);
- }else{
- // Limit recursion. It can take an excessive amount
- // of time if there are a lot of nested loops.
- will_dirty[(ba[i]-start)>>2]=0;
- wont_dirty[(ba[i]-start)>>2]=-1;
- }
- }
- /*else*/ if(1)
- {
- if (is_ujump(i))
- {
- // Unconditional branch
- will_dirty_i=0;
- wont_dirty_i=0;
- //if(ba[i]>start+i*4) { // Disable recursion (for debugging)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if(branch_regs[i].regmap[r]==regs[(ba[i]-start)>>2].regmap_entry[r]) {
- will_dirty_i|=will_dirty[(ba[i]-start)>>2]&(1<<r);
- wont_dirty_i|=wont_dirty[(ba[i]-start)>>2]&(1<<r);
- }
- if(branch_regs[i].regmap[r]>=0) {
- will_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(branch_regs[i].regmap[r]&63))&1)<<r;
- wont_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(branch_regs[i].regmap[r]&63))&1)<<r;
- }
- }
- }
- //}
- // Merge in delay slot
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if((branch_regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(branch_regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
- if(branch_regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- }
- }
- } else {
- // Conditional branch
- will_dirty_i=will_dirty_next;
- wont_dirty_i=wont_dirty_next;
- //if(ba[i]>start+i*4) { // Disable recursion (for debugging)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- signed char target_reg=branch_regs[i].regmap[r];
- if(target_reg==regs[(ba[i]-start)>>2].regmap_entry[r]) {
- will_dirty_i&=will_dirty[(ba[i]-start)>>2]&(1<<r);
- wont_dirty_i|=wont_dirty[(ba[i]-start)>>2]&(1<<r);
- }
- else if(target_reg>=0) {
- will_dirty_i&=((unneeded_reg[(ba[i]-start)>>2]>>(target_reg&63))&1)<<r;
- wont_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(target_reg&63))&1)<<r;
- }
- // Treat delay slot as part of branch too
- /*if(regs[i+1].regmap[r]==regs[(ba[i]-start)>>2].regmap_entry[r]) {
- will_dirty[i+1]&=will_dirty[(ba[i]-start)>>2]&(1<<r);
- wont_dirty[i+1]|=wont_dirty[(ba[i]-start)>>2]&(1<<r);
- }
- else
- {
- will_dirty[i+1]&=~(1<<r);
- }*/
- }
- }
- //}
- // Merge in delay slot
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if(!likely[i]) {
- // Might not dirty if likely branch is not taken
- if((branch_regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) will_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(branch_regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
- if(branch_regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- //if((regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- //if((regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- }
- }
- }
- }
- // Merge in delay slot (won't dirty)
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if((regs[i].regmap[r]&63)==rt1[i]) wont_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i]) wont_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i+1]) wont_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i+1]) wont_dirty_i|=1<<r;
- if(regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i]) wont_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i]) wont_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt1[i+1]) wont_dirty_i|=1<<r;
- if((branch_regs[i].regmap[r]&63)==rt2[i+1]) wont_dirty_i|=1<<r;
- if(branch_regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
- }
- }
- if(wr) {
- #ifndef DESTRUCTIVE_WRITEBACK
- branch_regs[i].dirty&=wont_dirty_i;
- #endif
- branch_regs[i].dirty|=will_dirty_i;
- }
- }
- }
- }
- else if(itype[i]==SYSCALL||itype[i]==HLECALL||itype[i]==INTCALL)
- {
- // SYSCALL instruction (software interrupt)
- will_dirty_i=0;
- wont_dirty_i=0;
- }
- else if(itype[i]==COP0 && (source[i]&0x3f)==0x18)
- {
- // ERET instruction (return from interrupt)
- will_dirty_i=0;
- wont_dirty_i=0;
- }
- will_dirty_next=will_dirty_i;
- wont_dirty_next=wont_dirty_i;
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if((regs[i].regmap[r]&63)==rt1[i]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i]) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)>33) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]<=0) will_dirty_i&=~(1<<r);
- if(regs[i].regmap[r]==CCREG) will_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt1[i]) wont_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i]) wont_dirty_i|=1<<r;
- if(regs[i].regmap[r]==CCREG) wont_dirty_i|=1<<r;
- if(i>istart) {
- if(itype[i]!=RJUMP&&itype[i]!=UJUMP&&itype[i]!=CJUMP&&itype[i]!=SJUMP)
- {
- // Don't store a register immediately after writing it,
- // may prevent dual-issue.
- if((regs[i].regmap[r]&63)==rt1[i-1]) wont_dirty_i|=1<<r;
- if((regs[i].regmap[r]&63)==rt2[i-1]) wont_dirty_i|=1<<r;
- }
- }
- }
- }
- // Save it
- will_dirty[i]=will_dirty_i;
- wont_dirty[i]=wont_dirty_i;
- // Mark registers that won't be dirtied as not dirty
- if(wr) {
- /*printf("wr (%d,%d) %x will:",istart,iend,start+i*4);
- for(r=0;r<HOST_REGS;r++) {
- if((will_dirty_i>>r)&1) {
- printf(" r%d",r);
- }
- }
- printf("\n");*/
-
- //if(i==istart||(itype[i-1]!=RJUMP&&itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP)) {
- regs[i].dirty|=will_dirty_i;
- #ifndef DESTRUCTIVE_WRITEBACK
- regs[i].dirty&=wont_dirty_i;
- if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP)
- {
- if (i < iend-1 && !is_ujump(i)) {
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if(regs[i].regmap[r]==regmap_pre[i+2][r]) {
- regs[i+2].wasdirty&=wont_dirty_i|~(1<<r);
- }else {/*printf("i: %x (%d) mismatch(+2): %d\n",start+i*4,i,r);assert(!((wont_dirty_i>>r)&1));*/}
- }
- }
- }
- }
- else
- {
- if(i<iend) {
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- if(regs[i].regmap[r]==regmap_pre[i+1][r]) {
- regs[i+1].wasdirty&=wont_dirty_i|~(1<<r);
- }else {/*printf("i: %x (%d) mismatch(+1): %d\n",start+i*4,i,r);assert(!((wont_dirty_i>>r)&1));*/}
- }
- }
- }
- }
- #endif
- //}
- }
- // Deal with changed mappings
- temp_will_dirty=will_dirty_i;
- temp_wont_dirty=wont_dirty_i;
- for(r=0;r<HOST_REGS;r++) {
- if(r!=EXCLUDE_REG) {
- int nr;
- if(regs[i].regmap[r]==regmap_pre[i][r]) {
- if(wr) {
- #ifndef DESTRUCTIVE_WRITEBACK
- regs[i].wasdirty&=wont_dirty_i|~(1<<r);
- #endif
- regs[i].wasdirty|=will_dirty_i&(1<<r);
- }
- }
- else if(regmap_pre[i][r]>=0&&(nr=get_reg(regs[i].regmap,regmap_pre[i][r]))>=0) {
- // Register moved to a different register
- will_dirty_i&=~(1<<r);
- wont_dirty_i&=~(1<<r);
- will_dirty_i|=((temp_will_dirty>>nr)&1)<<r;
- wont_dirty_i|=((temp_wont_dirty>>nr)&1)<<r;
- if(wr) {
- #ifndef DESTRUCTIVE_WRITEBACK
- regs[i].wasdirty&=wont_dirty_i|~(1<<r);
- #endif
- regs[i].wasdirty|=will_dirty_i&(1<<r);
- }
- }
- else {
- will_dirty_i&=~(1<<r);
- wont_dirty_i&=~(1<<r);
- if((regmap_pre[i][r]&63)>0 && (regmap_pre[i][r]&63)<34) {
- will_dirty_i|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<<r;
- wont_dirty_i|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<<r;
- } else {
- wont_dirty_i|=1<<r;
- /*printf("i: %x (%d) mismatch: %d\n",start+i*4,i,r);assert(!((will_dirty>>r)&1));*/
- }
- }
- }
- }
- }
-}
-
-#ifdef DISASM
- /* disassembly */
-void disassemble_inst(int i)
-{
- if (bt[i]) printf("*"); else printf(" ");
- switch(itype[i]) {
- case UJUMP:
- printf (" %x: %s %8x\n",start+i*4,insn[i],ba[i]);break;
- case CJUMP:
- printf (" %x: %s r%d,r%d,%8x\n",start+i*4,insn[i],rs1[i],rs2[i],i?start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14):*ba);break;
- case SJUMP:
- printf (" %x: %s r%d,%8x\n",start+i*4,insn[i],rs1[i],start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14));break;
- case RJUMP:
- if (opcode[i]==0x9&&rt1[i]!=31)
- printf (" %x: %s r%d,r%d\n",start+i*4,insn[i],rt1[i],rs1[i]);
- else
- printf (" %x: %s r%d\n",start+i*4,insn[i],rs1[i]);
- break;
- case SPAN:
- printf (" %x: %s (pagespan) r%d,r%d,%8x\n",start+i*4,insn[i],rs1[i],rs2[i],ba[i]);break;
- case IMM16:
- if(opcode[i]==0xf) //LUI
- printf (" %x: %s r%d,%4x0000\n",start+i*4,insn[i],rt1[i],imm[i]&0xffff);
- else
- printf (" %x: %s r%d,r%d,%d\n",start+i*4,insn[i],rt1[i],rs1[i],imm[i]);
- break;
- case LOAD:
- case LOADLR:
- printf (" %x: %s r%d,r%d+%x\n",start+i*4,insn[i],rt1[i],rs1[i],imm[i]);
- break;
- case STORE:
- case STORELR:
- printf (" %x: %s r%d,r%d+%x\n",start+i*4,insn[i],rs2[i],rs1[i],imm[i]);
- break;
- case ALU:
- case SHIFT:
- printf (" %x: %s r%d,r%d,r%d\n",start+i*4,insn[i],rt1[i],rs1[i],rs2[i]);
- break;
- case MULTDIV:
- printf (" %x: %s r%d,r%d\n",start+i*4,insn[i],rs1[i],rs2[i]);
- break;
- case SHIFTIMM:
- printf (" %x: %s r%d,r%d,%d\n",start+i*4,insn[i],rt1[i],rs1[i],imm[i]);
- break;
- case MOV:
- if((opcode2[i]&0x1d)==0x10)
- printf (" %x: %s r%d\n",start+i*4,insn[i],rt1[i]);
- else if((opcode2[i]&0x1d)==0x11)
- printf (" %x: %s r%d\n",start+i*4,insn[i],rs1[i]);
- else
- printf (" %x: %s\n",start+i*4,insn[i]);
- break;
- case COP0:
- if(opcode2[i]==0)
- printf (" %x: %s r%d,cpr0[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC0
- else if(opcode2[i]==4)
- printf (" %x: %s r%d,cpr0[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC0
- else printf (" %x: %s\n",start+i*4,insn[i]);
- break;
- case COP1:
- if(opcode2[i]<3)
- printf (" %x: %s r%d,cpr1[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC1
- else if(opcode2[i]>3)
- printf (" %x: %s r%d,cpr1[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC1
- else printf (" %x: %s\n",start+i*4,insn[i]);
- break;
- case COP2:
- if(opcode2[i]<3)
- printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC2
- else if(opcode2[i]>3)
- printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC2
- else printf (" %x: %s\n",start+i*4,insn[i]);
- break;
- case C1LS:
- printf (" %x: %s cpr1[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]);
- break;
- case C2LS:
- printf (" %x: %s cpr2[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]);
- break;
- case INTCALL:
- printf (" %x: %s (INTCALL)\n",start+i*4,insn[i]);
- break;
- default:
- //printf (" %s %8x\n",insn[i],source[i]);
- printf (" %x: %s\n",start+i*4,insn[i]);
- }
-}
-#else
-static void disassemble_inst(int i) {}
-#endif // DISASM
-
-#define DRC_TEST_VAL 0x74657374
-
-static void new_dynarec_test(void)
-{
- int (*testfunc)(void);
- void *beginning;
- int ret[2];
- size_t i;
-
- // check structure linkage
- if ((u_char *)rcnts - (u_char *)&psxRegs != sizeof(psxRegs))
- {
- SysPrintf("linkage_arm* miscompilation/breakage detected.\n");
- }
-
- SysPrintf("testing if we can run recompiled code...\n");
- ((volatile u_int *)out)[0]++; // make cache dirty
-
- for (i = 0; i < ARRAY_SIZE(ret); i++) {
- out = ndrc->translation_cache;
- beginning = start_block();
- emit_movimm(DRC_TEST_VAL + i, 0); // test
- emit_ret();
- literal_pool(0);
- end_block(beginning);
- testfunc = beginning;
- ret[i] = testfunc();
- }
-
- if (ret[0] == DRC_TEST_VAL && ret[1] == DRC_TEST_VAL + 1)
- SysPrintf("test passed.\n");
- else
- SysPrintf("test failed, will likely crash soon (r=%08x %08x)\n", ret[0], ret[1]);
- out = ndrc->translation_cache;
-}
-
-// clear the state completely, instead of just marking
-// things invalid like invalidate_all_pages() does
-void new_dynarec_clear_full(void)
-{
- int n;
- out = ndrc->translation_cache;
- memset(invalid_code,1,sizeof(invalid_code));
- memset(hash_table,0xff,sizeof(hash_table));
- memset(mini_ht,-1,sizeof(mini_ht));
- memset(restore_candidate,0,sizeof(restore_candidate));
- memset(shadow,0,sizeof(shadow));
- copy=shadow;
- expirep=16384; // Expiry pointer, +2 blocks
- pending_exception=0;
- literalcount=0;
- stop_after_jal=0;
- inv_code_start=inv_code_end=~0;
- // TLB
- for(n=0;n<4096;n++) ll_clear(jump_in+n);
- for(n=0;n<4096;n++) ll_clear(jump_out+n);
- for(n=0;n<4096;n++) ll_clear(jump_dirty+n);
-}
-
-void new_dynarec_init(void)
-{
- SysPrintf("Init new dynarec\n");