drc: try to avoid full constant reload
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index ce77e00..353179a 100644 (file)
@@ -59,6 +59,8 @@ struct regstat
   uint64_t uu;
   u_int wasconst;
   u_int isconst;
+  u_int loadedconst;             // host regs that have constants loaded
+  u_int waswritten;              // MIPS regs that were used as store base before
   uint64_t constmap[HOST_REGS];
 };
 
@@ -3298,7 +3300,7 @@ void store_assemble(int i,struct regstat *i_regs)
     jaddr=0;
   }
 #endif
-  if(!using_tlb) {
+  if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))) {
     if(!c||memtarget) {
       #ifdef DESTRUCTIVE_SHIFT
       // The x86 shift operation is 'destructive'; it overwrites the
@@ -3572,7 +3574,7 @@ void storelr_assemble(int i,struct regstat *i_regs)
   }
   if(!c||!memtarget)
     add_stub(STORELR_STUB,jaddr,(int)out,i,(int)i_regs,temp,ccadj[i],reglist);
-  if(!using_tlb) {
+  if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))) {
     #ifdef RAM_OFFSET
     int map=get_reg(i_regs->regmap,ROREG);
     if(map<0) map=HOST_TEMPREG;
@@ -3750,7 +3752,7 @@ void c1ls_assemble(int i,struct regstat *i_regs)
     emit_writedword_indexed_tlb(th,tl,0,offset||c||s<0?temp:s,map,temp);
     type=STORED_STUB;
   }
-  if(!using_tlb) {
+  if(!using_tlb&&!(i_regs->waswritten&(1<<rs1[i]))) {
     if (opcode[i]==0x39||opcode[i]==0x3D) { // SWC1/SDC1
       #ifndef DESTRUCTIVE_SHIFT
       temp=offset||c||s<0?ar:s;
@@ -3869,7 +3871,7 @@ void c2ls_assemble(int i,struct regstat *i_regs)
   }
   if(jaddr2)
     add_stub(type,jaddr2,(int)out,i,ar,(int)i_regs,ccadj[i],reglist);
-  if (opcode[i]==0x3a) { // SWC2
+  if (!(i_regs->waswritten&(1<<rs1[i]))&&opcode[i]==0x3a) { // SWC2
 #if defined(HOST_IMM8)
     int ir=get_reg(i_regs->regmap,INVCP);
     assert(ir>=0);
@@ -4257,6 +4259,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
                  (using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000))
               #endif
               emit_movimm(constmap[i][rs]+offset,ra);
+              regs[i].loadedconst|=1<<ra;
             }
           } // else did it in the previous cycle
         } // else load_consts already did it
@@ -4317,6 +4320,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[])
              (using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000))
           #endif
           emit_movimm(constmap[i+1][rs]+offset,ra);
+          regs[i+1].loadedconst|=1<<ra;
         }
       }
       else if(rs1[i+1]==0) {
@@ -4385,22 +4389,51 @@ int get_final_value(int hr, int i, int *value)
 // Load registers with known constants
 void load_consts(signed char pre[],signed char regmap[],int is32,int i)
 {
-  int hr;
+  int hr,hr2;
+  // propagate loaded constant flags
+  if(i==0||bt[i])
+    regs[i].loadedconst=0;
+  else {
+    for(hr=0;hr<HOST_REGS;hr++) {
+      if(hr!=EXCLUDE_REG&&regmap[hr]>=0&&((regs[i-1].isconst>>hr)&1)&&pre[hr]==regmap[hr]
+         &&regmap[hr]==regs[i-1].regmap[hr]&&((regs[i-1].loadedconst>>hr)&1))
+      {
+        regs[i].loadedconst|=1<<hr;
+      }
+    }
+  }
   // Load 32-bit regs
   for(hr=0;hr<HOST_REGS;hr++) {
     if(hr!=EXCLUDE_REG&&regmap[hr]>=0) {
       //if(entry[hr]!=regmap[hr]) {
-      if(i==0||!((regs[i-1].isconst>>hr)&1)||pre[hr]!=regmap[hr]||bt[i]) {
+      if(!((regs[i].loadedconst>>hr)&1)) {
         if(((regs[i].isconst>>hr)&1)&&regmap[hr]<64&&regmap[hr]>0) {
-          int value;
+          int value,similar=0;
           if(get_final_value(hr,i,&value)) {
-            if(value==0) {
+            // see if some other register has similar value
+            for(hr2=0;hr2<HOST_REGS;hr2++) {
+              if(hr2!=EXCLUDE_REG&&((regs[i].loadedconst>>hr2)&1)) {
+                if(is_similar_value(value,constmap[i][hr2])) {
+                  similar=1;
+                  break;
+                }
+              }
+            }
+            if(similar) {
+              int value2;
+              if(get_final_value(hr2,i,&value2)) // is this needed?
+                emit_movimm_from(value2,hr2,value,hr);
+              else
+                emit_movimm(value,hr);
+            }
+            else if(value==0) {
               emit_zeroreg(hr);
             }
             else {
               emit_movimm(value,hr);
             }
           }
+          regs[i].loadedconst|=1<<hr;
         }
       }
     }
@@ -8787,6 +8820,7 @@ int new_recompile_block(int addr)
   dirty_reg(&current,CCREG);
   current.isconst=0;
   current.wasconst=0;
+  current.waswritten=0;
   int ds=0;
   int cc=0;
   int hr=-1;
@@ -8815,6 +8849,7 @@ int new_recompile_block(int addr)
         if(current.regmap[hr]==0) current.regmap[hr]=-1;
       }
       current.isconst=0;
+      current.waswritten=0;
     }
     if(i>1)
     {
@@ -8879,6 +8914,7 @@ int new_recompile_block(int addr)
     regs[i].wasconst=current.isconst;
     regs[i].was32=current.is32;
     regs[i].wasdirty=current.dirty;
+    regs[i].loadedconst=0;
     #if defined(DESTRUCTIVE_WRITEBACK) && !defined(FORCE32)
     // To change a dirty register from 32 to 64 bits, we must write
     // it out during the previous cycle (for branches, 2 cycles)
@@ -9441,6 +9477,14 @@ int new_recompile_block(int addr)
       }
       memcpy(regs[i].regmap,current.regmap,sizeof(current.regmap));
     }
+
+    if(i>0&&(itype[i-1]==STORE||itype[i-1]==STORELR||(itype[i-1]==C2LS&&opcode[i-1]==0x3a))&&(u_int)imm[i-1]<0x800)
+      current.waswritten|=1<<rs1[i-1];
+    current.waswritten&=~(1<<rt1[i]);
+    current.waswritten&=~(1<<rt2[i]);
+    if((itype[i]==STORE||itype[i]==STORELR||(itype[i]==C2LS&&opcode[i]==0x3a))&&(u_int)imm[i]>=0x800)
+      current.waswritten&=~(1<<rs1[i]);
+
     /* Branch post-alloc */
     if(i>0)
     {
@@ -9736,6 +9780,11 @@ int new_recompile_block(int addr)
       cc=0;
     }
 #ifdef PCSX
+    else if(itype[i]==C2OP&&gte_cycletab[source[i]&0x3f]>2)
+    {
+      // GTE runs in parallel until accessed, divide by 2 for a rough guess
+      cc+=gte_cycletab[source[i]&0x3f]/2;
+    }
     else if(/*itype[i]==LOAD||*/itype[i]==STORE||itype[i]==C1LS) // load causes weird timing issues
     {
       cc+=2; // 2 cycle penalty (after CLOCK_DIVIDER)
@@ -9765,6 +9814,7 @@ int new_recompile_block(int addr)
       }
     }
     if(current.regmap[HOST_BTREG]==BTREG) current.regmap[HOST_BTREG]=-1;
+    regs[i].waswritten=current.waswritten;
   }
   
   /* Pass 4 - Cull unused host registers */