* src/SDCCmain.c (linkEdit): do not test for PIC16 target since, PIC16
[fw/sdcc] / src / pic16 / pcoderegs.c
index 2c66a5527205a3da6cd4282fdee6415e950cc6cb..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");
@@ -167,17 +173,18 @@ static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
 
     reg = pic16_getRegFromInstruction(pc);
 
-    if(reg) {
+    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);
-      fprintf(stderr, "addr = 0x%03x, type = %d  rIdx=0x%03x",
+      fprintf(stderr, "addr = 0x%03x, type = %d  rIdx=0x%03x ",
              reg->address,reg->type,reg->rIdx);
       fprintf(stderr, "command = %s\n", PCI(pc)->mnemonic);
              
 #endif
 
+//      fprintf(stderr, "%s:%d: trying to get first operand from pCode reg= %s\n", __FILE__, __LINE__, reg->name);
       addSetIfnotP(& (PCFL(pcfl)->registers), reg);
 
       if((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond)
@@ -186,25 +193,29 @@ 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,
           and set up the second operand too */
        if(PCI(pc)->is2MemOp) {
                        reg = pic16_getRegFromInstruction2(pc);
-
-//                     fprintf(stderr, "trying to get second operand from pCode reg= %s\n", reg->name);
-                       addSetIfnotP(& (PCFL(pcfl)->registers), reg);
-
-                       if((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond)
-                               addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
-
-                       if(PCC_REGISTER & PCI(pc)->outCond)
-                               addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
+                       if(reg) {
+//                             fprintf(stderr, "%s:%d: trying to get second operand from pCode reg= %s\n", __FILE__, __LINE__, reg->name);
+                               addSetIfnotP(& (PCFL(pcfl)->registers), reg);
+
+                               if((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond)
+                                       addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
+                                       
+                               if((PCC_REGISTER | PCC_REGISTER2) & PCI(pc)->outCond)
+                                       addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
                        
-                       addSetIfnotP(& (reg->reglives.usedpCodes), pc);
-
+                               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;
       }
@@ -318,8 +335,11 @@ static void  RemoveRegsFromSet(set *regset)
     if(used <= 1) {
 
 //     fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
+
       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;
       } else {
@@ -329,11 +349,10 @@ static void  RemoveRegsFromSet(set *regset)
        pc = setFirstItem(reg->reglives.usedpCodes);
 
        if(reg->type == REG_SFR) {
-               fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name);
+               fprintf(stderr, "not removing SFR reg %s even though used only once\n", reg->name);
          continue;
        }
 
-
        if(isPCI(pc)) {
          if(PCI(pc)->label) {
            pCode *pcn = pic16_findNextInstruction(pc->next);
@@ -355,7 +374,7 @@ static void  RemoveRegsFromSet(set *regset)
            pc->print(stderr,pc);
            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);
@@ -391,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;
+  }
+}
+
+        
 
 /*-----------------------------------------------------------------*
  *
@@ -400,6 +481,12 @@ static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg, int
   if(!reg)
     return;
 
+#if 0
+  fprintf(stderr,"removing 2 instructions:\n");
+  pc1->print(stderr,pc1);
+  pc2->print(stderr,pc2);
+#endif
+
   if(pc1)
     Remove1pcode(pc1, reg);
 
@@ -415,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
+  
 }
 
 /*-----------------------------------------------------------------*
@@ -431,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)) ;
@@ -459,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;
@@ -497,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) ){
@@ -516,13 +641,18 @@ static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *re
 
   }  else if(PCI(pc1)->op == POC_MOVWF) {
 
+    reg1 = pic16_getRegFromInstruction(pc1);
+
+    if(reg1->type == REG_SFR)return (total_registers_saved != t);
+
     pct2 = pic16_findNextInstruction(pc2->next);
 
     if(PCI(pc2)->op == POC_MOVFW) {
-      /*
+
+#if 0
        fprintf(stderr, "   MOVWF/MOVFW. instruction after MOVFW is:\n");
        pct2->print(stderr,pct2);
-      */
+#endif
 
       if(PCI(pct2)->op == POC_MOVWF) {
        /*
@@ -540,8 +670,8 @@ static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *re
            
        */
        reg2 = pic16_getRegFromInstruction(pct2);
-       //if(reg2 && !regUsedinRange(pc1,pc2,reg2) && (reg2->type != REG_SFR)) {
-       if(reg2 && !regUsedinRange(pc1,pc2,reg2)) {
+       if(reg2 && !regUsedinRange(pc1,pc2,reg2) && (reg2->type != REG_SFR)) {
+//     if(reg2 && !regUsedinRange(pc1,pc2,reg2)) 
 
          if(pic16_pCodeSearchCondition(pct2, PCC_Z) < 1) {
            pCode *pct3 = pic16_findNextInstruction(pct2->next);
@@ -553,22 +683,22 @@ 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
       }
     }
 
@@ -580,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:
@@ -631,7 +762,9 @@ static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *re
        }
       } else if ( (PCI(pct1)->op == POC_MOVWF) &&
           (PCI(pc2)->op == POC_MOVFW)) {
-       //fprintf(stderr,"movwf MOVWF/MOVFW\n");
+
+//        fprintf(stderr,"movwf MOVWF/MOVFW\n");
+
        if(optimize_level > 1 && can_free) {
          pct2 = pic16_newpCode(POC_MOVFW, PCI(pc1)->pcop);
          pic16_pCodeInsertAfter(pc2, pct2);
@@ -704,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");
 
@@ -733,7 +866,7 @@ static void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_l
       if(used && !pcfl_used && pcfl_assigned) {
        pCode *pc;
 
-//             fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
+               fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
 
        pc = setFirstItem(reg->reglives.usedpCodes);
        while(pc) {
@@ -807,42 +940,45 @@ 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--;
 
-  if(pic16_debug_verbose)
-    fprintf(stderr, "No registers saved on this pass\n");
+    } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
 
+    if(total_registers_saved == t) 
+      if(pic16_debug_verbose)
+        fprintf(stderr, "No registers saved on this pass\n");
 
-/*
-  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);
-*/
+
+#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);
+#endif
 }
 
 
@@ -857,7 +993,6 @@ static void  RegsSetUnMapLiveRanges(set *regset)
   while(regset) {
     reg = regset->item;
     regset = regset->next;
-
     
     deleteSet(&reg->reglives.usedpCodes);
     deleteSet(&reg->reglives.usedpFlows);
@@ -869,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);
-
 }