drc: detect unconditional branches early
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / new_dynarec.c
index bd553b8..d6a7603 100644 (file)
@@ -485,6 +485,11 @@ static int is_jump(int i)
   return itype[i] == RJUMP || itype[i] == UJUMP || itype[i] == CJUMP || itype[i] == SJUMP;
 }
 
+static int ds_writes_rjump_rs(int i)
+{
+  return rs1[i] != 0 && (rs1[i] == rt1[i+1] || rs1[i] == rt2[i+1]);
+}
+
 static u_int get_page(u_int vaddr)
 {
   u_int page=vaddr&~0xe0000000;
@@ -1172,7 +1177,7 @@ static void invalidate_page(u_int page)
     inv_debug("INVALIDATE: kill pointer to %x (%p)\n",head->vaddr,head->addr);
     void *host_addr=find_extjump_insn(head->addr);
     mark_clear_cache(host_addr);
-    set_jump_target(host_addr, head->addr);
+    set_jump_target(host_addr, head->addr); // point back to dyna_linker
     next=head->next;
     free(head);
     head=next;
@@ -1321,14 +1326,13 @@ static void do_invstub(int n)
 
 // Add an entry to jump_out after making a link
 // src should point to code by emit_extjump2()
-void add_link(u_int vaddr,void *src)
+void add_jump_out(u_int vaddr,void *src)
 {
   u_int page=get_page(vaddr);
-  inv_debug("add_link: %p -> %x (%d)\n",src,vaddr,page);
+  inv_debug("add_jump_out: %p -> %x (%d)\n",src,vaddr,page);
   check_extjump2(src);
   ll_add(jump_out+page,vaddr,src);
-  //void *ptr=get_pointer(src);
-  //inv_debug("add_link: Pointer is to %p\n",ptr);
+  //inv_debug("add_jump_out:  to %p\n",get_pointer(src));
 }
 
 // If a code block was found to be unmodified (bit was set in
@@ -4965,7 +4969,7 @@ static void do_ccstub(int n)
     if(itype[i]==RJUMP)
     {
       int r=get_reg(branch_regs[i].regmap,rs1[i]);
-      if(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]) {
+      if (ds_writes_rjump_rs(i)) {
         r=get_reg(branch_regs[i].regmap,RTEMP);
       }
       emit_writeword(r,&pcaddr);
@@ -5123,7 +5127,7 @@ static void rjump_assemble(int i,struct regstat *i_regs)
   int ra_done=0;
   rs=get_reg(branch_regs[i].regmap,rs1[i]);
   assert(rs>=0);
-  if(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]) {
+  if (ds_writes_rjump_rs(i)) {
     // Delay slot abuse, make a copy of the branch address register
     temp=get_reg(branch_regs[i].regmap,RTEMP);
     assert(temp>=0);
@@ -5972,7 +5976,7 @@ static void pagespan_assemble(int i,struct regstat *i_regs)
   emit_extjump_ds(branch_addr, target_addr);
   if(compiled_target_addr) {
     set_jump_target(branch_addr, compiled_target_addr);
-    add_link(target_addr,stub);
+    add_jump_out(target_addr,stub);
   }
   else set_jump_target(branch_addr, stub);
   if(likely[i]) {
@@ -5987,7 +5991,7 @@ static void pagespan_assemble(int i,struct regstat *i_regs)
     emit_extjump_ds(branch_addr, target_addr);
     if(compiled_target_addr) {
       set_jump_target(branch_addr, compiled_target_addr);
-      add_link(target_addr,stub);
+      add_jump_out(target_addr,stub);
     }
     else set_jump_target(branch_addr, stub);
   }
@@ -6001,7 +6005,7 @@ static void pagespan_ds()
   u_int page=get_page(vaddr);
   u_int vpage=get_vpage(vaddr);
   ll_add(jump_dirty+vpage,vaddr,(void *)out);
-  do_dirty_stub_ds();
+  do_dirty_stub_ds(slen*4);
   ll_add(jump_in+page,vaddr,(void *)out);
   assert(regs[0].regmap_entry[HOST_CCREG]==CCREG);
   if(regs[0].regmap[HOST_CCREG]!=CCREG)
@@ -7194,18 +7198,18 @@ int new_recompile_block(u_int addr)
         {
           case 0x00: strcpy(insn[i],"BLTZ"); type=SJUMP; break;
           case 0x01: strcpy(insn[i],"BGEZ"); type=SJUMP; break;
-          case 0x02: strcpy(insn[i],"BLTZL"); type=SJUMP; break;
-          case 0x03: strcpy(insn[i],"BGEZL"); type=SJUMP; break;
-          case 0x08: strcpy(insn[i],"TGEI"); type=NI; break;
-          case 0x09: strcpy(insn[i],"TGEIU"); type=NI; break;
-          case 0x0A: strcpy(insn[i],"TLTI"); type=NI; break;
-          case 0x0B: strcpy(insn[i],"TLTIU"); type=NI; break;
-          case 0x0C: strcpy(insn[i],"TEQI"); type=NI; break;
-          case 0x0E: strcpy(insn[i],"TNEI"); type=NI; break;
+          //case 0x02: strcpy(insn[i],"BLTZL"); type=SJUMP; break;
+          //case 0x03: strcpy(insn[i],"BGEZL"); type=SJUMP; break;
+          //case 0x08: strcpy(insn[i],"TGEI"); type=NI; break;
+          //case 0x09: strcpy(insn[i],"TGEIU"); type=NI; break;
+          //case 0x0A: strcpy(insn[i],"TLTI"); type=NI; break;
+          //case 0x0B: strcpy(insn[i],"TLTIU"); type=NI; break;
+          //case 0x0C: strcpy(insn[i],"TEQI"); type=NI; break;
+          //case 0x0E: strcpy(insn[i],"TNEI"); type=NI; break;
           case 0x10: strcpy(insn[i],"BLTZAL"); type=SJUMP; break;
           case 0x11: strcpy(insn[i],"BGEZAL"); type=SJUMP; break;
-          case 0x12: strcpy(insn[i],"BLTZALL"); type=SJUMP; break;
-          case 0x13: strcpy(insn[i],"BGEZALL"); type=SJUMP; break;
+          //case 0x12: strcpy(insn[i],"BLTZALL"); type=SJUMP; break;
+          //case 0x13: strcpy(insn[i],"BGEZALL"); type=SJUMP; break;
         }
         break;
       case 0x02: strcpy(insn[i],"J"); type=UJUMP; break;
@@ -7533,10 +7537,23 @@ int new_recompile_block(u_int addr)
     else if(type==CJUMP||type==SJUMP)
       ba[i]=start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14);
     else ba[i]=-1;
+
+    /* simplify always (not)taken branches */
+    if (type == CJUMP && rs1[i] == rs2[i]) {
+      rs1[i] = rs2[i] = 0;
+      if (!(op & 1)) {
+        itype[i] = type = UJUMP;
+        rs2[i] = CCREG;
+      }
+    }
+    else if (type == SJUMP && rs1[i] == 0 && (op2 & 1))
+      itype[i] = type = UJUMP;
+
+    /* messy cases to just pass over to the interpreter */
     if (i > 0 && is_jump(i-1)) {
       int do_in_intrp=0;
       // branch in delay slot?
-      if(type==RJUMP||type==UJUMP||type==CJUMP||type==SJUMP) {
+      if (is_jump(i)) {
         // don't handle first branch and call interpreter if it's hit
         SysPrintf("branch in delay slot @%08x (%08x)\n", addr + i*4, addr);
         do_in_intrp=1;
@@ -7566,6 +7583,7 @@ int new_recompile_block(u_int addr)
         i--; // don't compile the DS
       }
     }
+
     /* Is this the end of the block? */
     if (i > 0 && is_ujump(i-1)) {
       if(rt1[i-1]==0) { // Continue past subroutine call (JAL)
@@ -7752,7 +7770,7 @@ int new_recompile_block(u_int addr)
           clear_const(&current,rt1[i]);
           alloc_cc(&current,i);
           dirty_reg(&current,CCREG);
-          if(rs1[i]!=rt1[i+1]&&rs1[i]!=rt2[i+1]) {
+          if (!ds_writes_rjump_rs(i)) {
             alloc_reg(&current,i,rs1[i]);
             if (rt1[i]!=0) {
               alloc_reg(&current,i,rt1[i]);
@@ -9249,10 +9267,14 @@ int new_recompile_block(u_int addr)
         literal_pool_jumpover(256);
     }
   }
-  //assert(is_ujump(i-2));
+
+  assert(slen > 0);
+  if (itype[slen-1] == INTCALL) {
+    // no ending needed for this block since INTCALL never returns
+  }
   // If the block did not end with an unconditional branch,
   // add a jump to the next instruction.
-  if(i>1) {
+  else if (i > 1) {
     if(!is_ujump(i-2)&&itype[i-1]!=SPAN) {
       assert(itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP);
       assert(i==slen);
@@ -9332,7 +9354,7 @@ int new_recompile_block(u_int addr)
       emit_extjump(link_addr[i].addr, link_addr[i].target);
       if (addr) {
         set_jump_target(link_addr[i].addr, addr);
-        add_link(link_addr[i].target,stub);
+        add_jump_out(link_addr[i].target,stub);
       }
       else
         set_jump_target(link_addr[i].addr, stub);
@@ -9350,8 +9372,17 @@ int new_recompile_block(u_int addr)
       //#endif
     }
   }
+
+  u_int source_len = slen*4;
+  if (itype[slen-1] == INTCALL && source_len > 4)
+    // no need to treat the last instruction as compiled
+    // as interpreter fully handles it
+    source_len -= 4;
+
+  if ((u_char *)copy + source_len > (u_char *)shadow + sizeof(shadow))
+    copy = shadow;
+
   // External Branch Targets (jump_in)
-  if(copy+slen*4>(void *)shadow+sizeof(shadow)) copy=shadow;
   for(i=0;i<slen;i++)
   {
     if(bt[i]||i==0)
@@ -9366,7 +9397,7 @@ int new_recompile_block(u_int addr)
           assem_debug("%p (%d) <- %8x\n",instr_addr[i],i,start+i*4);
           assem_debug("jump_in: %x\n",start+i*4);
           ll_add(jump_dirty+vpage,vaddr,out);
-          void *entry_point = do_dirty_stub(i);
+          void *entry_point = do_dirty_stub(i, source_len);
           ll_add_flags(jump_in+page,vaddr,state_rflags,entry_point);
           // If there was an existing entry in the hash table,
           // replace it with the new address.
@@ -9389,8 +9420,8 @@ int new_recompile_block(u_int addr)
   #endif
   assert(out - (u_char *)beginning < MAX_OUTPUT_BLOCK_SIZE);
   //printf("shadow buffer: %p-%p\n",copy,(u_char *)copy+slen*4);
-  memcpy(copy,source,slen*4);
-  copy+=slen*4;
+  memcpy(copy, source, source_len);
+  copy += source_len;
 
   end_block(beginning);