* src/SDCCmain.c (linkEdit): do not test for PIC16 target since, PIC16
[fw/sdcc] / src / pic16 / pcoderegs.c
index ad18f83e32c51519b195872d8327a762342d665c..1de9fbe1b0c8b35e7b4cae7be11711a1a00e5e06 100644 (file)
 #include "pcoderegs.h"
 #include "pcodeflow.h"
 
+
+#define DEBUG_REMOVE1PCODE     0
+#define HAVE_DBGREGUSAGE       0
+
+
 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
 extern pCode * pic16_findPrevInstruction(pCode *pci);
 extern pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n);
@@ -66,7 +71,8 @@ void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
 /*-----------------------------------------------------------------*
  * 
  *-----------------------------------------------------------------*/
-#if 0
+
+#if HAVE_DBGREGUSAGE
 static void dbg_regusage(set *fregs)
 {
   regs *reg;
@@ -119,13 +125,13 @@ static void dbg_regusage(set *fregs)
     }
   }
 }
-#endif
 
 /*-----------------------------------------------------------------*
  * 
  *-----------------------------------------------------------------*/
-#if 0
-static void dbg_dumpregusage(void)
+
+//static
+void dbg_dumpregusage(void)
 {
 
   fprintf(stderr,"***  Register Usage  ***\n");
@@ -168,6 +174,7 @@ static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
     reg = pic16_getRegFromInstruction(pc);
 
     if(reg && (reg->type != REG_TMP)) {
+
 #if 0
       fprintf(stderr, "reg= %p\n", reg);
       fprintf(stderr, "flow seq %d, inst seq %d  %s  ",PCODE(pcfl)->seq,pc->seq,reg->name);
@@ -186,7 +193,9 @@ static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
       if(PCC_REGISTER & PCI(pc)->outCond)
        addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
 
-      addSetIfnotP(& (reg->reglives.usedpCodes), pc);
+       addSetIfnotP(& (reg->reglives.usedpCodes), pc);
+
+//    reg->wasUsed=1;
 
 #if 1
        /* check to see if this pCode has 2 memory operands,
@@ -204,6 +213,8 @@ static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
                                        addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
                        
                                addSetIfnotP(& (reg->reglives.usedpCodes), pc);
+                               
+//                             reg->wasUsed=1;
                        }
        }
 #endif
@@ -253,7 +264,9 @@ void pic16_pCodeRegMapLiveRanges(pBlock *pb)
   }
 #endif
 
-//  dbg_dumpregusage();
+#if HAVE_DBGREGUSAGE
+  dbg_dumpregusage();
+#endif
 
 }
 
@@ -270,7 +283,7 @@ static void Remove1pcode(pCode *pc, regs *reg)
 
   deleteSetItem (&(reg->reglives.usedpCodes),pc);
 
-#if 0
+#if DEBUG_REMOVE1PCODE
   fprintf(stderr,"removing instruction:\n");
   pc->print(stderr,pc);
 #endif
@@ -288,8 +301,12 @@ static void Remove1pcode(pCode *pc, regs *reg)
 
     if(pcn) {
       if(PCI(pcn)->cline) {
-       //fprintf(stderr, "source line has been optimized completely out\n");
-       //pc->print(stderr,pc);
+
+#if DEBUG_REMOVE1PCODE
+       fprintf(stderr, "source line has been optimized completely out\n");
+       pc->print(stderr,pc);
+#endif
+
       } else {
        PCI(pcn)->cline = PCI(pc)->cline;
       }
@@ -321,7 +338,7 @@ static void  RemoveRegsFromSet(set *regset)
 
       if(used == 0) {
 
-//     fprintf(stderr,"%s:%d: getting rid of reg %s\n",__FILE__, __LINE__, reg->name);
+//  fprintf(stderr,"%s:%d: getting rid of reg %s\n",__FILE__, __LINE__, reg->name);
 
        reg->isFree = 1;
        reg->wasUsed = 0;
@@ -358,9 +375,6 @@ static void  RemoveRegsFromSet(set *regset)
            fprintf(stderr,"reg %s, type =%d\n",r->name, r->type);
          }
 
-         fprintf(stderr,"%s:%d: removing reg %s because it is used only once\n",__FILE__, __LINE__, reg->name);
-
-
          Remove1pcode(pc, reg);
          /*
            pic16_unlinkpCode(pc);
@@ -396,6 +410,68 @@ void pic16_RemoveUnusedRegisters(void)
        fprintf(stderr, " *** Saved %d registers ***\n", total_registers_saved);
 }
 
+static int insideLRBlock(pCode *pc)
+{
+  pCode *pc1;
+  int t1=-1, t2=-1;
+
+    pc1 = pc->prev;
+    while(pc1) {
+      if(isPCINFO(pc1) && (PCINF(pc1)->type == INF_LOCALREGS)) {
+        t1 = PCOLR (PCINF (pc1)->oper1)->type;
+        break;
+      }
+      pc1 = pc1->prev;
+    }
+    
+    pc1 = pc->next;
+    while(pc1) {
+      if(isPCINFO(pc1) && (PCINF(pc1)->type == INF_LOCALREGS)) {
+        t2 = PCOLR (PCINF (pc1)->oper1)->type;
+        break;
+      }
+      pc1 = pc1->next;
+    }
+    
+    if((t1 == LR_ENTRY_BEGIN && t2 == LR_ENTRY_END)
+      || (t1 == LR_EXIT_BEGIN && t2 == LR_EXIT_END))
+        return 1;
+
+  return 0;
+}
+
+    
+static void RemoveRegFromLRBlock(regs *reg)
+{
+  if(elementsInSet(reg->reglives.usedpCodes) == 2) {
+    pCode *pc1;
+
+      /* only continue if there are just 2 uses of the register,
+       * in in the local *entry* block and one in the local *exit* block */
+        
+      /* search for entry block */
+      pc1 = indexSet(reg->reglives.usedpCodes, 1);
+
+      if(insideLRBlock( pc1 )) {
+        fprintf(stderr, "usedpCodes[0] inside LR block\n");
+        deleteSetItem(&pc1->pb->tregisters, PCOR(PCI(pc1)->pcop)->r);
+        Remove1pcode(pc1, reg);
+      }
+
+      pc1 = indexSet(reg->reglives.usedpCodes, 0);
+      if(insideLRBlock( pc1 )) {
+        fprintf(stderr, "usedpCodes[1] inside LR block\n");
+        deleteSetItem(&pc1->pb->tregisters, PCOR(PCI(pc1)->pcop)->r);
+        Remove1pcode(pc1, reg);
+      }
+        
+      /* remove r0x00 */
+      reg->isFree = 1;
+      reg->wasUsed = 0;
+  }
+}
+
+        
 
 /*-----------------------------------------------------------------*
  *
@@ -426,6 +502,15 @@ static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg, int
   }
 
   pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
+  
+#if 1
+//  fprintf(stderr, "register %s is used in %d pCodes, assigned in %d pCodes\n", reg->name,
+//      elementsInSet(reg->reglives.usedpCodes),
+//      elementsInSet(reg->reglives.assignedpFlows));
+  
+  RemoveRegFromLRBlock(reg);
+#endif
+  
 }
 
 /*-----------------------------------------------------------------*
@@ -442,6 +527,13 @@ static int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg)
       return 1;
     }
 
+    if(PCI(pc1)->is2MemOp) {
+      testreg = pic16_getRegFromInstruction2(pc1);
+      if(testreg && (testreg->rIdx == reg->rIdx)) {
+        return 1;
+      }
+    }
+
     pc1 = pic16_findNextInstruction(pc1->next);
 
   } while (pc1 && (pc1 != pc2) && (i++ < 100)) ;
@@ -470,6 +562,8 @@ static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *re
 
   int t = total_registers_saved;
 
+  if(reg->type == REG_SFR)return 0;
+
   if(pc2->seq < pc1->seq) {
     pct1 = pc2;
     pc2 = pc1;
@@ -508,7 +602,27 @@ static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *re
     PCI(newpc)->pcflow = PCFL(pcfl_used);
     newpc->seq = pc2->seq;
 
-    Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
+    /* take care if register is used after pc2, if yes, then don't delete
+     * clrf reg, because, reg should be initialized with zero */
+    {
+      pCode *spc;
+      int maxSeq=0;
+
+        for(spc=setFirstItem(reg->reglives.usedpCodes);spc;spc=setNextItem(reg->reglives.usedpCodes)) {
+          if(maxSeq < spc->seq)maxSeq = spc->seq;
+        }
+
+//        fprintf(stderr, "pc1->seq = %d\tpc2->seq = %d\tspc->seq = %d\n", pc1->seq, pc2->seq, maxSeq);
+
+        if(maxSeq > pc2->seq) {
+          /* this means that a pCode uses register after pc2, then
+           * we can't delete pc1 pCode */
+          Remove2pcodes(pcfl_used, NULL, pc2, reg, can_free);
+        } else {
+          /* we can remove both pCodes */
+          Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
+        }
+    }
     total_registers_saved++;  // debugging stats.
 
   } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
@@ -569,19 +683,19 @@ static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *re
 
            if(usesW(pct3))
              ; // Remove2pcodes(pcfl_used, pc1, NULL, reg, can_free);
-           else
+           else {
              Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
-
-           total_registers_saved++;  // debugging stats.
-           return 1;
-           } else {
-             //fprintf(stderr,"didn't optimize because Z bit is used\n");
-           }
+             total_registers_saved++;  // debugging stats.
+             return 1;
+            }
+          } else {
+//            fprintf(stderr,"didn't optimize because Z bit is used\n");
+         }
        }
 #if 0
        fprintf(stderr, " couldn't optimize\n");
        if(reg2)
-         fprintf(stderr, " %s is used in range\n",reg2->name);
+         fprintf(stderr, " %s is used in range\n", reg2->name);
        else
          fprintf(stderr, " reg2 is NULL\n");
 #endif
@@ -596,10 +710,11 @@ static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *re
 
        reg1 = pic16_getRegFromInstruction(pct1);
        if(reg1 && !regUsedinRange(pc1,pc2,reg1)) {
-         /*
+         
+#if 0
            fprintf(stderr, "   MOVF/MOVFW. \n");
            fprintf(stderr, "     ...optimizing\n");
-         */
+#endif
 
          /*
            Change:
@@ -722,7 +837,7 @@ static void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_l
        */
 
        //fprintf(stderr," used only twice\n");
-       if(pcfl_used->seq == pcfl_assigned->seq) {
+       if(pcfl_used->seq == pcfl_assigned->seq && !(setNextItem(reg->reglives.usedpFlows)) && !(setNextItem(reg->reglives.assignedpFlows))) {
 
          //fprintf(stderr, "  and used in same flow\n");
 
@@ -825,41 +940,44 @@ void pic16_pCodeRegOptimizeRegUsage(int level)
   int saved = 0;
   int t = total_registers_saved;
 
-  if(!register_optimization)
-    return;
-#define OPT_PASSES 4
-  passes = OPT_PASSES;
+    if(getenv("NO_REG_OPT"))
+      return;
 
-  do {
-    saved = total_registers_saved;
+    if(!register_optimization)
+      return;
 
-    /* Identify registers used in one flow sequence */
-    OptimizeRegUsage(pic16_dynAllocRegs,level, (OPT_PASSES-passes));
-    OptimizeRegUsage(pic16_dynStackRegs,level, (OPT_PASSES-passes));
-    OptimizeRegUsage(pic16_dynDirectRegs,0, (OPT_PASSES-passes));
+#define OPT_PASSES 8
+    passes = OPT_PASSES;
 
-    if((total_registers_saved != saved)
-       && (pic16_pcode_verbose))
-      fprintf(stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", 
-             (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved);
-      
-    passes--;
+    do {
+      saved = total_registers_saved;
 
-  } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
+      /* Identify registers used in one flow sequence */
+      OptimizeRegUsage(pic16_dynAllocRegs,level, (OPT_PASSES-passes));
+      OptimizeRegUsage(pic16_dynStackRegs,level, (OPT_PASSES-passes));
+      OptimizeRegUsage(pic16_dynDirectRegs,0, (OPT_PASSES-passes));
 
-  if(total_registers_saved == t) 
+      if((total_registers_saved != saved)
+        && (pic16_pcode_verbose))
+          fprintf(stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", 
+            (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved);
+      
+          passes--;
+
+    } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
 
-  if(pic16_debug_verbose)
-    fprintf(stderr, "No registers saved on this pass\n");
+    if(total_registers_saved == t) 
+      if(pic16_debug_verbose)
+        fprintf(stderr, "No registers saved on this pass\n");
 
 
 #if 0
-  fprintf(stderr,"dynamically allocated regs:\n");
-  dbg_regusage(pic16_dynAllocRegs);
-  fprintf(stderr,"stack regs:\n");
-  dbg_regusage(pic16_dynStackRegs);
-  fprintf(stderr,"direct regs:\n");
-  dbg_regusage(pic16_dynDirectRegs);
+    fprintf(stderr,"dynamically allocated regs:\n");
+    dbg_regusage(pic16_dynAllocRegs);
+    fprintf(stderr,"stack regs:\n");
+    dbg_regusage(pic16_dynStackRegs);
+    fprintf(stderr,"direct regs:\n");
+    dbg_regusage(pic16_dynDirectRegs);
 #endif
 }
 
@@ -875,7 +993,6 @@ static void  RegsSetUnMapLiveRanges(set *regset)
   while(regset) {
     reg = regset->item;
     regset = regset->next;
-
     
     deleteSet(&reg->reglives.usedpCodes);
     deleteSet(&reg->reglives.usedpFlows);
@@ -887,12 +1004,10 @@ static void  RegsSetUnMapLiveRanges(set *regset)
 
 void  pic16_RegsUnMapLiveRanges(void)
 {
-
   RegsSetUnMapLiveRanges(pic16_dynAllocRegs);
   RegsSetUnMapLiveRanges(pic16_dynStackRegs);
   RegsSetUnMapLiveRanges(pic16_dynDirectRegs);
   RegsSetUnMapLiveRanges(pic16_dynProcessorRegs);
   RegsSetUnMapLiveRanges(pic16_dynDirectBitRegs);
   RegsSetUnMapLiveRanges(pic16_dynInternalRegs);
-
 }