* src/pic16/device.h,
authorvrokas <vrokas@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Wed, 24 Nov 2004 23:42:58 +0000 (23:42 +0000)
committervrokas <vrokas@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Wed, 24 Nov 2004 23:42:58 +0000 (23:42 +0000)
* src/pic16/genarith.c,
* src/pic16/glue.c,
* src/pic16/main.c,
* src/pic16/pcode.c: applied patches #1068154 and #1070213

git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@3583 4a8a32a2-be11-0410-ad9d-d568d2c75423

ChangeLog
src/pic16/device.h
src/pic16/genarith.c
src/pic16/glue.c
src/pic16/main.c
src/pic16/pcode.c

index 38ba3c009620a63b75a1eb9b2091c6ff632fbd44..8d9e3628ce8be2521d15897520be4e698164ecb5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2004-11-25 Vangelis Rokas <vrokas AT otenet.gr>
+
+       * src/pic16/device.h,
+       * src/pic16/genarith.c,
+       * src/pic16/glue.c,
+       * src/pic16/main.c,
+       * src/pic16/pcode.c: applied patches #1068154 and #1070213
+
 2004-11-24 Vangelis Rokas <vrokas AT otenet.gr>
 
        Large cummulative patch for pic16 port.
index 2906d7bba6b5d898f0def553ee8e2a4a239d0717..92cbe337eb5f8430622843ff2021b40455295b35 100644 (file)
@@ -86,7 +86,8 @@ typedef struct PIC16_device {
 /* Given a pointer to a register, this macro returns the bank that it is in */
 #define REG_ADDR(r)        ((r)->isBitField ? (((r)->address)>>3) : (r)->address)
 
-#define OF_LR_SUPPORT  0x00000001
+#define OF_LR_SUPPORT          0x00000001
+#define OF_OPTIMIZE_GOTO       0x00000002
 
 
 typedef struct {
index f8d34fbd7b57d4dcce5f9d301d1b9916a0375860..a543487350e450115839f46d8d98fd97800fd95e 100644 (file)
@@ -1604,11 +1604,12 @@ void pic16_genUMult8XLit_8 (operand *left,
 {
   unsigned int lit;
   int same;
-
+  int size = AOP_SIZE(result);
+  int i;
 
        DEBUGpic16_emitcode ("; ***","%s  %d",__FUNCTION__,__LINE__);
        DEBUGpic16_pic16_AopType(__LINE__,left,right,result);
-  
+
        if (AOP_TYPE(right) != AOP_LIT){
                fprintf(stderr,"%s %d - right operand is not a literal\n",__FILE__,__LINE__);
                exit(1);
@@ -1623,12 +1624,19 @@ void pic16_genUMult8XLit_8 (operand *left,
        if(same) {
                switch(lit) {
                        case 0:
-                               pic16_emitpcode(POC_CLRF,  pic16_popGet(AOP(result),0));
+                               while (size--) {
+                                 pic16_emitpcode(POC_CLRF,  pic16_popGet(AOP(result),size));
+                               } // while
                                return;
                        case 2:
                                // its faster to left shift
+                               for (i=1; i < size; i++) {
+                                 pic16_emitpcode(POC_CLRF,  pic16_popGet(AOP(result),i));
+                               } // for
                                emitCLRC;
                                pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(left),0));
+                               if (size > 1)
+                                 pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),1));
                                return;
 
                        default:
@@ -1637,18 +1645,32 @@ void pic16_genUMult8XLit_8 (operand *left,
                                pic16_emitpcode(POC_MULLW, pic16_popGetLit(lit));
                                pic16_emitpcode(POC_MOVFF, pic16_popGet2p(pic16_popCopyReg(&pic16_pc_prodl),
                                        pic16_popGet(AOP(result), 0)));
+                               if (size > 1) {
+                                 pic16_emitpcode(POC_MOVFF, pic16_popGet2p(pic16_popCopyReg(&pic16_pc_prodh),
+                                                                           pic16_popGet(AOP(result), 1)));
+                                 for (i=2; i < size; i++) {
+                                   pic16_emitpcode(POC_CLRF,  pic16_popGet(AOP(result),i));
+                                 } // for
+                               } // if
                                return;
                }
        } else {
                // operands different
                switch(lit) {
                        case 0:
-                               pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result), 0));
+                               while (size--) {
+                                 pic16_emitpcode(POC_CLRF,  pic16_popGet(AOP(result),size));
+                               } // while
                                return;
                        case 2:
+                               for (i=1; i < size; i++) {
+                                 pic16_emitpcode(POC_CLRF,  pic16_popGet(AOP(result),i));
+                               } // for
                                emitCLRC;
                                pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(left), 0));
                                pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result), 0));
+                               if (size > 1)
+                                 pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),1));
                                return;
                        default:
                                if(AOP_TYPE(left) != AOP_ACC)
@@ -1656,6 +1678,14 @@ void pic16_genUMult8XLit_8 (operand *left,
                                pic16_emitpcode(POC_MULLW, pic16_popGetLit(lit));
                                pic16_emitpcode(POC_MOVFF, pic16_popGet2p(pic16_popCopyReg(&pic16_pc_prodl),
                                        pic16_popGet(AOP(result), 0)));
+
+                               if (size > 1) {
+                                 pic16_emitpcode(POC_MOVFF, pic16_popGet2p(pic16_popCopyReg(&pic16_pc_prodh),
+                                                                           pic16_popGet(AOP(result), 1)));
+                                 for (i=2; i < size; i++) {
+                                   pic16_emitpcode(POC_CLRF,  pic16_popGet(AOP(result),i));
+                                 } // for
+                               } // if
                                return;
                }
        }
index f7095b038e5d9b01aebdd25be15d9316a89a5496..9b67242373ec3bacc8a955f5eb9bfad65c112c8d 100644 (file)
@@ -69,6 +69,7 @@ extern DEFSETFUNC (closeTmpFiles);
 extern DEFSETFUNC (rmTmpFiles);
 
 extern void pic16_AnalyzeBanking (void);
+extern void pic16_OptimizeJumps ();
 extern void copyFile (FILE * dest, FILE * src);
 extern void pic16_InlinepCode(void);
 extern void pic16_writeUsedRegs(FILE *);
@@ -1734,6 +1735,11 @@ pic16glue ()
       pic16_OptimizeLocalRegs();
     }
 
+    /* turn GOTOs into BRAs -- added by RN 2004-11-16 */
+    if(pic16_options.opt_flags & OF_OPTIMIZE_GOTO) {
+      pic16_OptimizeJumps();
+    }
+
     /* print the extern variables to this module */
     pic16_printExterns(asmFile);
        
index 0ce3fedb834281cf344278f8d929c71612b60802..ab14e44d2a6341e942ceb0ad7e0f3a420f3b6a26 100644 (file)
@@ -312,6 +312,8 @@ _process_pragma(const char *sz)
 
 #define        OFMSG_LRSUPPORT "--flr-support"
 
+#define OPTIMIZE_GOTO   "--optimize-goto"
+
 char *alt_asm=NULL;
 char *alt_link=NULL;
 
@@ -352,6 +354,7 @@ OPTION pic16_optionsTable[]= {
        { 0,    "--no-crt",     &pic16_options.no_crt,  "do not link any default run-time initialization module"},
        { 0,    "--gstack",     &pic16_options.gstack,  "trace stack pointer push/pop to overflow"},
 //     { 0,    OFMSG_LRSUPPORT,        NULL,           "use support functions for local register store/restore"},
+       { 0,    OPTIMIZE_GOTO,  NULL,                   "try to use (conditional) BRA instead of GOTO"},
        { 0,    NULL,           NULL,   NULL}
        };
 
@@ -442,7 +445,14 @@ _pic16_parseOptions (int *pargc, char **argv, int *i)
       return TRUE;
     }
 #endif
-        
+
+#if 1
+    if (ISOPT(OPTIMIZE_GOTO)) {
+      pic16_options.opt_flags |= OF_OPTIMIZE_GOTO;
+      return TRUE;
+    }
+#endif
+
   return FALSE;
 }
 
index 93f4a9b8ba078f5644c223f4fda570be4eafc689..d7d6eaf3ba62199698010a15308b4da8e38b5bf6 100644 (file)
@@ -6332,7 +6332,7 @@ static void insertBankSwitch(unsigned char position, pCode *pc)
                                pic16_pCodeInsertAfter(ppc, npci);
                                
                                /* extra instructions to handle invertion */
-                               pcnext = pic16_newpCode(POC_GOTO, pic16_popGetLabel(tlbl->key));
+                               pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
                                pic16_pCodeInsertAfter(npci, pcnext);
                                pic16_pCodeInsertAfter(pc->prev, new_pc);
                                
@@ -6883,7 +6883,345 @@ loop:
        } while (pc);
 }
 
+/** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
 
+/* Returns the (maximum of the) number of bytes used by the specified pCode. */
+int instrSize (pCode *pc)
+{
+  if (!pc) return 0;
+
+  if (isPCAD(pc)) {
+    if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
+    return 4; // assumes only regular instructions using <= 4 bytes
+  }
+
+  if (isPCI(pc)) return PCI(pc)->isize;
+
+  return 0;
+}
+
+/* Returns 1 if pc is referenced by the given label (either
+ * pc is the label itself or is an instruction with an attached
+ * label).
+ * Returns 0 if pc is not preceeded by the specified label.
+ */
+int isLabel (pCode *pc, char *label)
+{
+  if (isPCI(pc) || isPCAD(pc)) {
+    pBranch *lab = NULL;
+    if (isPCI(pc)) lab = PCI(pc)->label;
+    else if (isPCAD(pc)) lab = PCAD(pc)->pci.label;
+
+    while (lab) {
+      if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
+       return 1;
+      }
+      lab = lab->next;
+    } // while
+  }
+  if (isPCL(pc)) {
+      if (strcmp(PCL(pc)->label,label) == 0) {
+      return 1;
+    }
+  }
+  // no label/no label attached/wrong label(s)
+  return 0;
+}
+
+/* Returns the distance to the given label in terms of words.
+ * Labels are searched only within -max .. max words from pc.
+ * Returns max if the label could not be found or
+ * its distance from pc in (-max..+max).
+ */
+int findpCodeLabel (pCode *pc, char *label, int max) {
+  int dist = instrSize(pc);
+  pCode *curr = pc;
+
+  // search backwards
+  while (dist < max && curr && !isLabel (curr, label)) {
+    curr = curr->prev;
+    dist += instrSize(curr); // sizeof (instruction)
+  } // while
+  if (curr && dist < max) return -dist;
+
+  dist = 0;
+  curr = pic16_findNextInstruction (pc->next);
+  //search forwards
+  while (dist < max && curr && !isLabel (curr, label)) {
+    dist += instrSize(curr); // sizeof (instruction)
+    curr = curr->next;
+  } // while
+  if (curr && dist < max) return dist;
+
+  return max;
+}
+
+/* Returns 0 if the pCode pc is known to NOT be in a jumptable.
+ * If in doubt (or sure that pc is part of a jumptable), 1 is returned.
+ */
+int isJumptable (pCode *pc, pCode *prev, pCode *next)
+{
+  // we might be the last item in a jump table or not in
+  // jumptable at all -- then we don't care
+  if (!next || !isPCI(next) || PCI(next)->op != POC_GOTO)
+    return 0;
+
+  // preceding instruction is a skip instruction (cannot be jumptable)
+  if (prev && isPCI(prev) && (isPCI_SKIP(prev)))
+    return 0;
+
+  // GOTOs within a jumptable are unlabelled...
+  if (next && isPCI(next) && PCI(next)->op == POC_GOTO && PCI(next)->label)
+    return 0;
+  
+  // if in doubt: assume we are in a jumptable
+  return 1;
+}
+
+/* Returns -1 if pc does NOT denote an instruction like
+ * BTFS[SC] STATUS,i
+ * Otherwise we return 
+ *   (a) 0x10 + i for BTFSS
+ *   (b) 0x00 + i for BTFSC
+ */
+int isSkipOnStatus (pCode *pc)
+{
+  int res = -1;
+  pCodeOp *pcop;
+  if (!pc || !isPCI(pc)) return -1;
+  if (PCI(pc)->op == POC_BTFSS) res = 0x10;
+  else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
+  else return -1;
+
+  pcop = PCI(pc)->pcop;
+
+  if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
+    return res + ((pCodeOpRegBit *)pcop)->bit;
+  }
+
+  return -1;
+}
+
+/* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
+ * returns 0 otherwise. */
+int isConditionalBranch (pCode *pc)
+{
+  if (!pc || !isPCI_BRANCH(pc)) return 0;
+
+  switch (PCI(pc)->op) {
+  case POC_BC:
+  case POC_BZ:
+  case POC_BOV:
+  case POC_BN:
+  case POC_BNC:
+  case POC_BNZ:
+  case POC_BNOV:
+  case POC_BNN:
+    return 1;
+
+  default:
+    break;
+  } // switch
+
+  return 0;
+}
+
+/* Returns 1 if pc has a label attached to it.
+ * This can be either a label stored in the pCode itself (.label)
+ * or a label making up its own pCode preceding this pc.
+ * Returns 0 if pc cannot be reached directly via a label.
+ */
+int hasNoLabel (pCode *pc)
+{
+  pCode *prev;
+  if (!pc) return 1;
+
+  // has labels attached?
+  if (isPCI(pc) && PCI(pc)->label) return 0;
+  
+  // are there any label pCodes between pc and the previous instruction?
+  prev = pic16_findPrevInstruction (pc->prev);
+  pc = pc->prev;
+  while (pc && pc != prev) {
+    if (isPCW(pc) && PCW(pc)->label) return 0;
+    if (isPCL(pc)) return 0;
+    pc = pc->prev;
+  } // if
+
+  // no label found
+  return 1;
+}
+
+#define MAX_DIST_BRA 1020
+#define MAX_DIST_BCC 120
+#define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO))
+
+/* Turn GOTOs into BRAs if distance between GOTO and label
+ * is less than 1024 bytes.
+ *
+ * This method is especially useful if GOTOs after BTFS[SC]
+ * can be turned into BRAs as GOTO would cost another NOP
+ * if skipped.
+ */
+void pic16_OptimizeJumps ()
+{
+  pCode *pc;
+  pCode *pc_prev = NULL;
+  pCode *pc_next = NULL;
+  pBlock *pb;
+  int opt=0, toofar=0, jumptabs=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0;
+  
+  if (!the_pFile) return;
+  
+  for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
+    pc = pic16_findNextInstruction (pb->pcHead);
+    
+    while (pc) {
+      pc_next = pic16_findNextInstruction (pc->next);
+      // turn GOTOs into BRAs (if absolute distance to label < 1024)
+      if (IS_GOTO(pc)) {
+       char *label = PCI(pc)->pcop->name;
+       int condBraType = isSkipOnStatus(pc_prev);
+       int dist = findpCodeLabel(pc, label, MAX_DIST_BRA);
+       if (dist < 0) dist = -dist;
+       int isHandled = 0;
+       //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
+
+       if (condBraType != -1 && hasNoLabel(pc)) {
+         if (dist < MAX_DIST_BCC) {
+           pCode *bcc = NULL;
+           switch (condBraType) {
+           case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
+             // no BDC on DIGIT CARRY available
+           case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
+           case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
+           case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
+           case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
+             // no BNDC on DIGIT CARRY available
+           case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
+           case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
+           case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
+           default:
+             // no replacement possible
+             bcc = NULL;
+             break;
+           } // switch
+           if (bcc) {
+             // ATTENTION: keep labels attached to BTFSx!
+             // HINT: GOTO is label free (checked above)
+             isHandled = 1;
+             PCI(bcc)->label = PCI(pc_prev)->label;
+             PCI(pc_prev)->label = NULL;
+             pic16_pCodeInsertAfter (pc, bcc);
+             pic16_pCodeInsertAfter(pc_prev, pic16_newpCodeCharP("goto-optimization 1"));
+             pc_prev->destruct(pc_prev);
+             pc->destruct(pc);
+             pc = bcc;
+             opt_cond++;
+           } // if
+         } else {
+           //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
+           cond_toofar++;
+         } // if
+       } // if
+
+       if (!isHandled) {
+         // eliminate the following (common) tripel:
+         //           <pred.>;
+         //  labels1: Bcc label2;
+         //           GOTO somewhere;    ; <-- instruction referenced by pc
+         //  label2:  <cont.>
+         // and replace it by
+         //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
+         //  label2:  <cont.>
+         // ATTENTION: all labels pointing to "Bcc label2" must be attached
+         //            to <cont.> instead
+         // ATTENTION: This optimization is only valid if <pred.> is
+         //            not a skip operation!
+         // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
+         // ATTENTION: no label may be attached to the GOTO instruction!
+         if (isConditionalBranch(pc_prev)
+             && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
+             && (dist < MAX_DIST_BCC)
+             && isLabel(pc_next,PCI(pc_prev)->pcop->name)
+             && hasNoLabel(pc)) {
+           pCode *newBcc = NULL;
+           switch (PCI(pc_prev)->op) {
+           case POC_BC:   newBcc = pic16_newpCode (POC_BNC , PCI(pc)->pcop); break;
+           case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , PCI(pc)->pcop); break;
+           case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop); break;
+           case POC_BN:   newBcc = pic16_newpCode (POC_BNN , PCI(pc)->pcop); break;
+           case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , PCI(pc)->pcop); break;
+           case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , PCI(pc)->pcop); break;
+           case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , PCI(pc)->pcop); break;
+           case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , PCI(pc)->pcop); break;
+           default:
+             newBcc = NULL;
+           }
+           
+           if (newBcc) {
+             PCI(newBcc)->label = PCI(pc_prev)->label;
+             PCI(pc_prev)->label = NULL;
+            
+             pic16_pCodeInsertAfter(pc_prev, newBcc);
+             pic16_pCodeInsertAfter(pc_prev, pic16_newpCodeCharP("goto-optimization 2"));
+             pc->destruct(pc);
+             pc->destruct(pc_prev);
+             pc = newBcc;
+             isHandled = 1;
+             opt_reorder++;
+           }
+         }
+       }
+
+       if (!isHandled) {
+         // now just turn GOTO into BRA
+         if (!isJumptable(pc, pc_prev, pc_next)) {
+           if (dist < MAX_DIST_BRA) {
+             isHandled = 1;
+             pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
+             PCI(newBra)->label = PCI(pc)->label;
+             pic16_pCodeInsertAfter (pc, newBra);
+             pic16_pCodeInsertAfter(pc_prev, pic16_newpCodeCharP("goto-optimization 3"));
+             pc->destruct(pc);
+             pc = newBra;
+             opt++;
+           } else {
+             //fprintf (stderr, "(%d, too far for BRA)\n", dist);
+             toofar++;
+           }
+         } else {
+           //fprintf (stderr, "(in jumptable)\n");
+           jumptabs++;
+         }
+       } // if (!isHandled)
+      } // if
+
+      pc_prev = pc;
+      pc = pc_next;
+    } // while (pc)
+  } // for (pb)
+  
+  // emit some statistics concerning goto-optimization
+  // (maybe this should be moved to the general statistics?)
+  fprintf (stderr, "optimize-goto: %d GOTO->BRA; (%d GOTOs too far and "
+          "%d GOTOs in jumptables ignored); "
+          "%d BTFSx, GOTO->Bcc (%d too far), %d jumps reordered\n",
+          opt, toofar, jumptabs, opt_cond, cond_toofar, opt_reorder);
+  /*
+  fprintf (stderr, "saved %d + %d + %d = %d bytes in program memory\n",
+          (4 - 2) * opt,
+          (6 - 2) * opt_cond,
+          (6 - 2) * opt_reorder,
+          (4 - 2) * opt +  (6 - 2) * opt_cond + (6 - 2) * opt_reorder);
+  */
+}
+
+#undef IS_GOTO
+#undef MAX_DIST_BRA
+#undef MAX_DIST_BCC
+
+/** END OF RAPHAEL NEIDER'S ADDITIONS **/
 
 static void pBlockDestruct(pBlock *pb)
 {