pCode Register optimization - registers used in only one or two instructions
[fw/sdcc] / src / pic / pcoderegs.c
index efbddfa4ed5fdb012f368a81fa6d5a11f90b024b..5a5ebbff9b316210750f5e5ab0ac6e943f346835 100644 (file)
 #include "pcoderegs.h"
 #include "pcodeflow.h"
 
+extern void pCodeInsertAfter(pCode *pc1, pCode *pc2);
 extern void dbg_dumpregusage(void);
 void unlinkpCode(pCode *pc);
 
+int total_registers_saved=0;
+
 /*-----------------------------------------------------------------*
  * void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
  *-----------------------------------------------------------------*/
@@ -180,6 +183,7 @@ void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
   }
 
 }
+
 /*-----------------------------------------------------------------*
  * void pCodeRegMapLiveRanges(pBlock *pb) 
  *-----------------------------------------------------------------*/
@@ -213,7 +217,7 @@ void pCodeRegMapLiveRanges(pBlock *pb)
 
   }
 
-  //  dbg_dumpregusage();
+  //dbg_dumpregusage();
 
 }
 
@@ -243,7 +247,6 @@ void  RemoveRegsFromSet(set *regset)
       } else {
        pCode *pc;
 
-       //fprintf(stderr," reg %s used only once\n",reg->name);
 
        pc = setFirstItem(reg->reglives.usedpCodes);
        if(isPCI(pc)) {
@@ -251,8 +254,8 @@ void  RemoveRegsFromSet(set *regset)
            pCode *pcn = findNextInstruction(pc->next);
 
            if(pcn && PCI(pcn)->label) {
-             fprintf(stderr,"can't delete instruction with label...\n");
-             pc->print(stderr,pc);
+             //fprintf(stderr,"can't delete instruction with label...\n");
+             //pc->print(stderr,pc);
              continue;
            } 
            /* Move the label to the next instruction */
@@ -264,10 +267,12 @@ void  RemoveRegsFromSet(set *regset)
          if(isPCI_SKIP(pc))
            fprintf(stderr, "WARNING, a skip instruction is being optimized out\n");
 
+         //fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
          unlinkpCode(pc);
          deleteSetItem (&(reg->reglives.usedpCodes),pc);
          reg->isFree = 1;
          reg->wasUsed = 0;
+         total_registers_saved++;  // debugging stats.
        }
       }
     }
@@ -280,23 +285,248 @@ void  RemoveRegsFromSet(set *regset)
  *-----------------------------------------------------------------*/
 void RemoveUnusedRegisters(void)
 {
+  /* First, get rid of registers that are used only one time */
 
 
-  //fprintf(stderr,"InternalRegs:\n");
   RemoveRegsFromSet(dynInternalRegs);
-  //fprintf(stderr,"AllocRegs:\n");
   RemoveRegsFromSet(dynAllocRegs);
-  //fprintf(stderr,"StackRegs:\n");
   RemoveRegsFromSet(dynStackRegs);
-
   /*
     don't do DirectRegs yet - there's a problem with arrays
-  //fprintf(stderr,"DirectRegs:\n");
   RemoveRegsFromSet(dynDirectRegs);
   */
-  //fprintf(stderr,"DirectBitRegs:\n");
   RemoveRegsFromSet(dynDirectBitRegs);
 
+  if(total_registers_saved) fprintf(stderr, " *** Saved %d registers ***\n", total_registers_saved);
+}
+
+
+/*-----------------------------------------------------------------*
+ *
+ *-----------------------------------------------------------------*/
+static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg)
+{
+
+  deleteSetItem (&(reg->reglives.usedpCodes),pc1);
+  deleteSetItem (&(reg->reglives.usedpCodes),pc2);
+  deleteSetItem (&(PCFL(pcflow)->registers), reg);
+
+  pc1->destruct(pc1);
+  pc2->destruct(pc2);
+
+  reg->isFree = 1;
+  reg->wasUsed = 0;
+  pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
+}
+
+/*-----------------------------------------------------------------*
+ *
+ *-----------------------------------------------------------------*/
+int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg)
+{
+  int i=0;
+  regs *testreg;
+
+  do {
+    testreg = getRegFromInstruction(pc1);
+    if(testreg && (testreg->rIdx == reg->rIdx)) {
+      return 1;
+    }
+
+    pc1 = findNextInstruction(pc1->next);
+
+  } while (pc1 && (pc1 != pc2) && (i++ < 100)) ;
+
+  if(i >= 100)
+    fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
+
+  return 0;
+}
+
+/*-----------------------------------------------------------------*
+ * void pCodeRegOptimeRegUsage(pBlock *pb) 
+ *-----------------------------------------------------------------*/
+void OptimizeRegUsage(set *fregs)
+{
+  regs *reg;
+  int used;
+
+
+  while(fregs) {
+
+    /* Step through the set by directly accessing the 'next' pointer.
+     * We could also step through by using the set API, but the 
+     * the (debug) calls to print instructions affect the state
+     * of the set pointers */
+
+    reg = fregs->item;
+    fregs = fregs->next;
+
+    used = elementsInSet(reg->reglives.usedpCodes);
+
+    if(used == 2) { 
+
+      pCode *pcfl_used, *pcfl_assigned;
+      pCode *pc1, *pc2;
+      pCode *t;
+
+      /* This register has only been used twice. Chances are we can
+        get rid of it */
+/*
+      fprintf (stderr, "OptimizeRegUsage: %s  addr=0x%03x rIdx=0x%03x  used=%d\n",
+              reg->name,
+              reg->address,
+              reg->rIdx, used);
+*/
+      pcfl_used = setFirstItem(reg->reglives.usedpFlows);
+      pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
+
+      pc1 = setFirstItem(reg->reglives.usedpCodes);
+      pc2 = setNextItem(reg->reglives.usedpCodes);
+
+      if(pcfl_used && pcfl_assigned) {
+
+       /* 
+          expected case - the register has been assigned a value and is
+          subsequently used 
+       */
+       //fprintf(stderr," used only twice\n");
+       if(pcfl_used->seq == pcfl_assigned->seq) {
+
+         //fprintf(stderr, "  and used in same flow\n");
+         if(pc2->seq < pc1->seq) {
+           t = pc2;
+           pc2 = pc1;
+           pc1 = t;
+         }
+
+         //pc1->print(stderr,pc1);
+         //pc2->print(stderr,pc2);
+
+
+         /* ADHOC pattern checking */
+         if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
+           pCode *newpc;
+           //fprintf(stderr, "   CLRF/MOVFW. instruction after MOVFW is:\n");
+           t = findNextInstruction(pc2->next);
+           //t->print(stderr,t);
+
+           if(PCI(t)->op == POC_MOVWF) {
+             newpc = newpCode(POC_CLRF, PCI(t)->pcop);
+           } else {
+             newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
+           }
+
+           PCI(newpc)->pcflow = PCFL(pcfl_used);
+           newpc->seq = t->seq;
+
+           pCodeInsertAfter(t, newpc);
+
+           t->destruct(t);
+           Remove2pcodes(pcfl_used, pc1, pc2, reg);
+           total_registers_saved++;  // debugging stats.
+
+         } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
+           //fprintf(stderr, "   CLRF/IORWF.\n");
+
+           Remove2pcodes(pcfl_used, pc1, pc2, reg);
+           total_registers_saved++;  // debugging stats.
+
+         }  else if((PCI(pc1)->op == POC_MOVWF) && (PCI(pc2)->op == POC_MOVFW) ){
+           //fprintf(stderr, "   MOVWF/MOVFW. instruction after MOVFW is:\n");
+           t = findNextInstruction(pc2->next);
+           // t->print(stderr,t);
+
+           if(PCI(t)->op == POC_MOVWF) {
+             regs *nextreg = getRegFromInstruction(t);
+             if(nextreg && !regUsedinRange(pc1,pc2,nextreg)) {
+               t->seq = pc1->seq;
+               unlinkpCode(t);
+               pCodeInsertAfter(pc1,t);
+               Remove2pcodes(pcfl_used, pc1, pc2, reg);
+               total_registers_saved++;  // debugging stats.
+             }
+           }
+         }
+
+       } else {
+         // fprintf(stderr, "  and used in different flows\n");
+
+         //pc1->print(stderr,pc1);
+         //pc2->print(stderr,pc2);
+       }
+
+      } else if(pcfl_used) {
+
+       /*
+         register has been used twice without ever being assigned */
+       fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
+      } else {
+       fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
+      }
+    } else {
+      //if(used) fprintf (stderr, "  over used OptimizeRegUsage: %s  used=%d\n", reg->name, used);
+
+    }
+
+  }
+
+#if 0
+    pcfl = setFirstItem(reg->reglives.usedpFlows);
+    if(pcfl)
+      fprintf(stderr, "\n   used in seq");
+
+    while(pcfl) {
+      fprintf(stderr," 0x%03x",pcfl->seq);
+      pcfl = setNextItem(reg->reglives.usedpFlows);
+    }
+
+    pcfl = setFirstItem(reg->reglives.assignedpFlows);
+    if(pcfl)
+      fprintf(stderr, "\n   assigned in seq");
+
+    while(pcfl) {
+      fprintf(stderr," 0x%03x",pcfl->seq);
+      pcfl = setNextItem(reg->reglives.assignedpFlows);
+    }
+
+    pc = setFirstItem(reg->reglives.usedpCodes);
+    if(pc)
+      fprintf(stderr, "\n   used in instructions ");
+
+    while(pc) {
+      pcfl = PCODE(PCI(pc)->pcflow);
+      if(pcfl)
+       fprintf(stderr," 0x%03x:",pcfl->seq);
+      fprintf(stderr,"0x%03x",pc->seq);
+
+      pc = setNextItem(reg->reglives.usedpCodes);
+    }
+
+    fprintf(stderr, "\n");
+
+  }
+#endif
+}
+/*-----------------------------------------------------------------*
+ * void pCodeRegOptimeRegUsage(pBlock *pb) 
+ *-----------------------------------------------------------------*/
+void pCodeRegOptimizeRegUsage(void)
+{
+
+  int passes = 4;
+  int saved = 0;
+
+  do {
+    saved = total_registers_saved;
+
+    /* Identify registers used in one flow sequence */
+    OptimizeRegUsage(dynAllocRegs);
+
+    if(total_registers_saved != saved)
+      fprintf(stderr, " *** Saved %d registers, total saved %d ***\n", total_registers_saved-saved,total_registers_saved);
+
 
+  } while( passes-- && (total_registers_saved != saved));
 
 }