drc: prefer callee-saved regs on alloc
authornotaz <notasas@gmail.com>
Sun, 28 Nov 2021 22:03:20 +0000 (00:03 +0200)
committernotaz <notasas@gmail.com>
Sun, 28 Nov 2021 23:14:21 +0000 (01:14 +0200)
reduces amount of saved/restored regs (random game):
arm32: ~45%
arm64: ~80%

libpcsxcore/new_dynarec/assem_arm.c
libpcsxcore/new_dynarec/assem_arm.h
libpcsxcore/new_dynarec/assem_arm64.c
libpcsxcore/new_dynarec/assem_arm64.h
libpcsxcore/new_dynarec/new_dynarec.c

index 87490c6..23d3b7f 100644 (file)
 #include "pcnt.h"
 #include "arm_features.h"
 
-#ifndef __MACH__
-#define CALLER_SAVE_REGS 0x100f
-#else
-#define CALLER_SAVE_REGS 0x120f
-#endif
-
 #define unused __attribute__((unused))
 
 #ifdef DRC_DBG
index 9b3a1e1..75273aa 100644 (file)
@@ -1,8 +1,3 @@
-#define HOST_REGS 13
-#define HOST_CCREG 10
-#define HOST_BTREG 8
-#define EXCLUDE_REG 11
-
 #define HOST_IMM8 1
 #define HAVE_CMOV_IMM 1
 #define HAVE_CONDITIONAL_CALL 1
    r14 = lr (link register)
    r15 = pc (program counter) */
 
+#define HOST_REGS 13
+#define HOST_CCREG 10
+#define HOST_BTREG 8
+#define EXCLUDE_REG 11
+
+// Note: FP is set to &dynarec_local when executing generated code.
+// Thus the local variables are actually global and not on the stack.
 #define FP 11
 #define LR 14
 #define HOST_TEMPREG 14
 
-// Note: FP is set to &dynarec_local when executing generated code.
-// Thus the local variables are actually global and not on the stack.
+#ifndef __MACH__
+#define CALLER_SAVE_REGS 0x100f
+#else
+#define CALLER_SAVE_REGS 0x120f
+#endif
+#define PREFERRED_REG_FIRST 4
+#define PREFERRED_REG_LAST  9
 
 extern char *invc_ptr;
 
index 431805d..1c52c3e 100644 (file)
@@ -23,8 +23,6 @@
 #include "pcnt.h"
 #include "arm_features.h"
 
-#define CALLER_SAVE_REGS 0x0007ffff
-
 #define unused __attribute__((unused))
 
 void do_memhandler_pre();
@@ -1599,7 +1597,6 @@ static void do_writestub(int n)
     emit_jmp(stubs[n].retaddr); // return address (invcode check)
   set_jump_target(handler_jump, out);
 
-  // TODO FIXME: regalloc should prefer callee-saved regs
   if(!regs_saved)
     save_regs(reglist);
   void *handler=NULL;
index 1aeee0b..c5fcadf 100644 (file)
@@ -1,13 +1,13 @@
-#define HOST_REGS 29
-#define HOST_BTREG 27
-#define EXCLUDE_REG -1
-
 #define HOST_IMM8 1
 
 /* calling convention:
    r0 -r17: caller-save
    r19-r29: callee-save */
 
+#define HOST_REGS 29
+#define HOST_BTREG 27
+#define EXCLUDE_REG -1
+
 #define SP 31
 #define WZR SP
 #define XZR SP
 #define HOST_CCREG 28
 #define rCC w28
 
+#define CALLER_SAVE_REGS 0x0007ffff
+#define PREFERRED_REG_FIRST 19
+#define PREFERRED_REG_LAST  27
+
 // stack space
 #define SSP_CALLEE_REGS (8*12)
 #define SSP_CALLER_REGS (8*20)
index 921a2ed..5041066 100644 (file)
@@ -1364,9 +1364,11 @@ void clean_blocks(u_int page)
 static void alloc_reg(struct regstat *cur,int i,signed char reg)
 {
   int r,hr;
-  int preferred_reg = (reg&7);
-  if(reg==CCREG) preferred_reg=HOST_CCREG;
-  if(reg==PTEMP||reg==FTEMP) preferred_reg=12;
+  int preferred_reg = PREFERRED_REG_FIRST
+    + reg % (PREFERRED_REG_LAST - PREFERRED_REG_FIRST + 1);
+  if (reg == CCREG) preferred_reg = HOST_CCREG;
+  if (reg == PTEMP || reg == FTEMP) preferred_reg = 12;
+  assert(PREFERRED_REG_FIRST != EXCLUDE_REG && EXCLUDE_REG != HOST_REGS);
 
   // Don't allocate unused registers
   if((cur->u>>reg)&1) return;
@@ -1410,28 +1412,47 @@ static void alloc_reg(struct regstat *cur,int i,signed char reg)
       if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;}
     }
   }
+
   // Try to allocate any available register, but prefer
   // registers that have not been used recently.
-  if(i>0) {
-    for(hr=0;hr<HOST_REGS;hr++) {
-      if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
-        if(regs[i-1].regmap[hr]!=dops[i-1].rs1&&regs[i-1].regmap[hr]!=dops[i-1].rs2&&regs[i-1].regmap[hr]!=dops[i-1].rt1&&regs[i-1].regmap[hr]!=dops[i-1].rt2) {
+  if (i > 0) {
+    for (hr = PREFERRED_REG_FIRST; ; ) {
+      if (cur->regmap[hr] < 0) {
+        int oldreg = regs[i-1].regmap[hr];
+        if (oldreg < 0 || (oldreg != dops[i-1].rs1 && oldreg != dops[i-1].rs2
+             && oldreg != dops[i-1].rt1 && oldreg != dops[i-1].rt2))
+        {
           cur->regmap[hr]=reg;
           cur->dirty&=~(1<<hr);
           cur->isconst&=~(1<<hr);
           return;
         }
       }
+      hr++;
+      if (hr == EXCLUDE_REG)
+        hr++;
+      if (hr == HOST_REGS)
+        hr = 0;
+      if (hr == PREFERRED_REG_FIRST)
+        break;
     }
   }
+
   // Try to allocate any available register
-  for(hr=0;hr<HOST_REGS;hr++) {
-    if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
+  for (hr = PREFERRED_REG_FIRST; ; ) {
+    if (cur->regmap[hr] < 0) {
       cur->regmap[hr]=reg;
       cur->dirty&=~(1<<hr);
       cur->isconst&=~(1<<hr);
       return;
     }
+    hr++;
+    if (hr == EXCLUDE_REG)
+      hr++;
+    if (hr == HOST_REGS)
+      hr = 0;
+    if (hr == PREFERRED_REG_FIRST)
+      break;
   }
 
   // Ok, now we have to evict someone