* device/lib/mcs51/crtcall.asm: new, added for indirect calls
[fw/sdcc] / src / mcs51 / rtrack.c
index 10882d7fb35b112979b6c95c14a6309f149b38c6..6fbc92b76d5f6b3cb6125a051ff3bddb34b300db 100644 (file)
-/*-------------------------------------------------------------------------
-  rtrack.c - tracking content of registers on an mcs51
-
-  Copyright 2007 Frieder Ferlemann (Frieder Ferlemann AT web.de)
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
--------------------------------------------------------------------------*/
-
-/*-------------------------------------------------------------------------
-  Status:
-    - passes regression test suite, still bugs are likely
-    - only active if environment variable SDCC_RTRACK is set
-
-  Missed opportunities:
-    - does not track symbols as in "mov a,#_my_int" or "mov a,#(_my_int+1)"
-    - only used with moves to acc so chances to use: "inc dptr",
-      "inc r2", "add a,r2" or "mov r2,a" would not be detected)
-    - a label causes loss of tracking (no handling of information of blocks
-      known to follow/preceed the current block)
-    - not used in aopGet or genRet
--------------------------------------------------------------------------*/
-
-
-#include <stdio.h>
-#include <string.h>
-#include "SDCCglobl.h"
-
-#include "common.h"
-#include "ralloc.h"
-#include "gen.h"
-
-#define DEBUG(x)
-//#define DEBUG(x) x
-
-#define D(x) x
-
-#define REGS8051_SET(idx,val) do{ \
-                                  regs8051[idx].value = (val) & 0xff; \
-                                  regs8051[idx].valueKnown = 1; \
-                                  DEBUG(printf("%s:0x%02x\n",regs8051[idx].name, \
-                                                       regs8051[idx].value);) \
-                              } while(0)
-
-#define REGS8051_UNSET(idx)   do{ \
-                                  regs8051[idx].valueKnown = 0; \
-                                  DEBUG(printf("%s:*\n",regs8051[idx].name);) \
-                              } while(0)
-
-/* r0..r7 are not in numerical order in struct regs: r2..r7,r0,r1 */
-#define Rx_NUM_TO_IDX(num) (R2_IDX+((num-2)&0x07))
-
-
-/* move this (or rtrackGetLit() and rtrackMoveALit()
-   elsewhere? stealing emitcode from gen.c */
-void emitcode (const char *inst, const char *fmt,...);
-
-
-static int enable = -1;
-
-/*
-static void dumpAll()
-{
-  unsigned int i;
-  unsigned int nl=0;
-
-  for (i=0; i<END_IDX; i++)
-    {
-       if (regs8051[i].valueKnown)
-         {
-           if (!nl)
-             {
-               DEBUG(printf("know:");)
-             }
-           DEBUG(printf(" %s:0x%02x",regs8051[i].name,regs8051[i].value);)
-           nl = 1;
-         }
-    }
-  if (nl)
-    {
-      DEBUG(printf("\n");)
-    }
-}
-*/
-
-
-static void invalidateAllRx()
-{
-  //DEBUG(dumpAll();)
-  DEBUG(printf("R0..7:*\n");)
-  regs8051[R2_IDX].valueKnown = 0;
-  regs8051[R3_IDX].valueKnown = 0;
-  regs8051[R4_IDX].valueKnown = 0;
-  regs8051[R5_IDX].valueKnown = 0;
-  regs8051[R6_IDX].valueKnown = 0;
-  regs8051[R7_IDX].valueKnown = 0;
-  regs8051[R0_IDX].valueKnown = 0;
-  regs8051[R1_IDX].valueKnown = 0;
-}
-
-static void invalidateAll()
-{
-  DEBUG(printf("All:* ");)
-  invalidateAllRx();
-  regs8051[DPL_IDX].valueKnown = 0;
-  regs8051[DPH_IDX].valueKnown = 0;
-  regs8051[B_IDX].valueKnown = 0;
-  regs8051[A_IDX].valueKnown = 0;
-}
-
-
-/* tracking values within registers by looking
-   at the line passed to the assembler.
-   Tries to keep regs8051[] up to date */
-void rtrackUpdate (const char *line)
-{
-  if (enable == -1)
-    enable = (NULL != getenv("SDCC_RTRACK"));
-
-  if (!enable ||
-      *line == ';' ||                 /* comment */
-      (NULL != strstr( line, "==."))) /* dirty check for _G.debugLine */
-    return;                           /* nothing to do */
-
-  DEBUG(printf("%s\n",line);)
-
-  if (!strncmp (line,"mov",3))
-    {
-      /* check literal mov to accumulator */
-      if(!strncmp (line,"mov\ta,#0x",9))
-        {
-          char *s;
-          int value;
-
-          value = strtol (line+7, &s, 16);
-          if (s != line+7)
-              REGS8051_SET (A_IDX, value); /* valid hex found */
-          else
-              REGS8051_UNSET (A_IDX); /* probably a symbol (not handled) */
-
-          return;
-        }
-
-      if (!strncmp (line,"mov\ta,r",7))
-        {
-          /* handle mov from Rx if Rx is known */
-          char *s;
-          int regNum;
-
-          regNum = strtol (line+7, &s, 16);
-          if (s == line+8)
-            {
-              regs *r = &regs8051[Rx_NUM_TO_IDX(regNum)];
-              if (r->valueKnown)
-                {
-                  REGS8051_SET (A_IDX, r->value);
-                  return;
-                }
-            }
-          REGS8051_UNSET (A_IDX);
-          return;
-        }
-
-      if (!strncmp (line,"mov\ta",5))
-        {
-          REGS8051_UNSET (A_IDX);
-          return;
-        }
-
-      if (!strncmp (line,"movc\ta",6) ||
-          !strncmp (line,"movx\ta",6))
-        {
-          REGS8051_UNSET (A_IDX);
-          return;
-        }
-
-      /* move direct to symbol, do not care */
-      if (!strncmp (line,"mov\t_",5) ||
-          !strncmp (line,"mov\t(_",6))
-        return;
-
-      /* check literal mov to register */
-      if (!strncmp (line,"mov\tr",5))
-        {
-          char *s;
-          int value;
-          int regNum;
-
-          regNum = strtol (line+5, &s, 16);
-          if (s == line+6)
-            {
-              value = strtol (line+8, &s, 16);
-              if ((s != line+8) && !strncmp (line+6,",#0x",4))
-                REGS8051_SET (Rx_NUM_TO_IDX(regNum), value);
-              else
-                REGS8051_UNSET (Rx_NUM_TO_IDX(regNum));
-              return;
-            }
-        }
-
-      /* mov to psw can change register bank */
-      if (!strncmp (line,"mov\tpsw,",8))
-        {
-          invalidateAllRx();
-          return;
-        }
-
-      /* no tracking of these, so we do not care */
-      if (!strncmp (line,"mov\tdptr,#",10) ||
-          !strncmp (line,"mov\tdpl,",8) ||
-          !strncmp (line,"mov\tdph,",8) ||
-          !strncmp (line,"mov\tsp,",7) ||
-          !strncmp (line,"mov\tb,",6))
-        return;
-
-      /* mov to xdata memory does not change registers */
-      if (!strncmp (line,"movx\t@",6))
-        return;
-
-      if (!strncmp (line,"mov\t@",5))
-        {
-          invalidateAllRx();
-          return;
-        }
-    }
-
-  /* no tracking of SP */
-  if (!strncmp (line,"push",4))
-    return;
-
-  if (!strncmp (line,"pop\ta",5))
-    {
-      if (!strncmp (line+4,"acc",3)){ REGS8051_UNSET (A_IDX); return; }
-      if (!strncmp (line+4,"ar2",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (2)); return; }
-      if (!strncmp (line+4,"ar3",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (3)); return; }
-      if (!strncmp (line+4,"ar4",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (4)); return; }
-      if (!strncmp (line+4,"ar5",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (5)); return; }
-      if (!strncmp (line+4,"ar6",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (6)); return; }
-      if (!strncmp (line+4,"ar7",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (7)); return; }
-      if (!strncmp (line+4,"ar0",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (0)); return; }
-      if (!strncmp (line+4,"ar1",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (1)); return; }
-    }
-
-  if (!strncmp (line,"inc",3))
-    {
-      /* no tracking of dptr, ignore */
-      if (!strcmp (line,"inc\tdptr") ||
-          !strcmp (line,"inc\tdph") ||
-          !strcmp (line,"inc\tdpl"))
-        return;
-
-      if (!strcmp (line,"inc\ta"))
-        {
-          if (regs8051[A_IDX].valueKnown)
-            REGS8051_SET (A_IDX, regs8051[A_IDX].value+1);
-          return;
-        }
-
-      if(!strncmp (line,"inc\tr",5))
-        {
-          char *s;
-          int regNum;
-
-          regNum = strtol (line+5, &s, 16);
-          if (s == line+6)
-            {
-              regs *r = &regs8051[Rx_NUM_TO_IDX(regNum)];
-              if (r->valueKnown)
-                {
-                  REGS8051_SET (Rx_NUM_TO_IDX(regNum), r->value+1);
-                }
-              return;
-            }
-        }
-    }
-
-  /* unfortunately the label typically following these
-     will cause loss of tracking */
-  if (!strncmp (line,"jc\t",3) ||
-      !strncmp (line,"jnc\t",4) ||
-      !strncmp (line,"jb\t",3) ||
-      !strncmp (line,"jnb\t",4) ||
-      !strncmp (line,"jbc\t",4))
-    return;
-
-  /* if branch not taken in "cjne r2,#0x08,somewhere" 
-     r2 is known to be 8 */
-  if (!strncmp (line,"cjne",4))
-    return;
-
-  /* acc eventually known to be zero */
-  if (!strncmp (line,"jz\t",3) ||
-      !strncmp (line,"jnz\t",4))
-    return;
-
-  if (!strncmp (line,"djnz\tr",6))
-    {
-      char *s;
-      int regNum;
-
-      regNum = strtol (line+6, &s, 16);
-      if (s == line+7)
-        {
-          REGS8051_UNSET (Rx_NUM_TO_IDX(regNum));
-          // REGS8051_SET (Rx_NUM_TO_IDX(regNum), 0x00); // branch not taken
-          return;
-        }
-    }
-
-  /* only carry bit, so we do not care */
-  if (!strncmp (line,"setb\tc",6) ||
-      !strncmp (line,"clr\tc",5) ||
-      !strncmp (line,"cpl\tc",5))
-    return;
-
-  if (!strncmp (line,"add\ta,",6) ||
-      !strncmp (line,"addc\ta,",7)||
-      !strncmp (line,"subb\ta,",7)||
-      !strncmp (line,"xrl\ta,",6) ||
-      !strncmp (line,"orl\ta,",6) ||
-      !strncmp (line,"anl\ta,",6) ||
-      !strncmp (line,"da\ta",4)   ||
-      !strncmp (line,"rlc\ta,",6) ||
-      !strncmp (line,"rrc\ta,",6) ||
-      !strncmp (line,"setb\ta",6) ||
-      !strncmp (line,"clrb\ta,",7))
-    {
-      /* could also handle f.e. "add a,Rx" if a, Rx are known or "xrl a,#0x08" */
-      REGS8051_UNSET (A_IDX);
-      return;
-    }
-
-
-  if (!strncmp (line,"dec",3))
-    {
-      /* no tracking of dptr, so we would not care */
-      if (!strcmp (line,"dec\tdph") ||
-          !strcmp (line,"dec\tdpl"))
-        return;
-
-      if (!strcmp (line,"dec\ta"))
-        {
-          if (regs8051[A_IDX].valueKnown)
-            REGS8051_SET (A_IDX, regs8051[A_IDX].value-1);
-          return;
-        }
-
-      if(!strncmp (line,"dec\tr",5))
-        {
-          char *s;
-          int regNum;
-
-          regNum = strtol (line+5, &s, 16);
-          if (s == line+6)
-            {
-              regs *r = &regs8051[Rx_NUM_TO_IDX(regNum)];
-              if (r->valueKnown)
-                {
-                  REGS8051_SET (Rx_NUM_TO_IDX(regNum), r->value-1);
-                }
-              return;
-            }
-        }
-    }
-
-
-  if (!strcmp (line,"clr\ta"))
-    {
-      REGS8051_SET (A_IDX, 0);
-      return;
-    }
-
-  if (!strcmp (line,"cpl\ta"))
-    {
-      if (regs8051[A_IDX].valueKnown)
-        REGS8051_SET (A_IDX, ~regs8051[A_IDX].value);
-      return;
-    }
-  if (!strcmp (line,"rl\ta"))
-    {
-      if (regs8051[A_IDX].valueKnown)
-        REGS8051_SET (A_IDX, (regs8051[A_IDX].value<<1) | 
-                             (regs8051[A_IDX].value>>7) );
-      return;
-    }
-  if (!strcmp (line,"rr\ta"))
-    {
-      if (regs8051[A_IDX].valueKnown)
-        REGS8051_SET (A_IDX, (regs8051[A_IDX].value>>1) |
-                             (regs8051[A_IDX].value<<7));
-      return;
-    }
-  if (!strcmp (line,"swap\ta"))
-    {
-      if (regs8051[A_IDX].valueKnown)
-        REGS8051_SET (A_IDX, (regs8051[A_IDX].value>>4) |
-                             (regs8051[A_IDX].value<<4));
-      return;
-    }
-
-  if (!strncmp (line,"mul",3) ||
-      !strncmp (line,"div",3)
-      )
-    {
-      REGS8051_UNSET (A_IDX);
-      REGS8051_UNSET (B_IDX);
-      return;
-    }
-
-  /* assuming these library functions have no side-effects */
-  if (!strcmp (line,"lcall"))
-    {
-      if (!strcmp (line,"lcall\t__gptrput"))
-        {
-          /* invalidate R0..R7 because they might have been changed */
-          invalidateAllRx();
-          return;
-        }
-      if (!strcmp (line,"lcall\t__gptrget"))
-        {
-          REGS8051_UNSET (A_IDX);
-          return;
-        }
-      if (!strcmp (line,"lcall\t__decdptr"))
-        {
-          return;
-        }
-     }
-
-  /* all others unrecognized, invalidate */
-  invalidateAll();
-}
-
-
-/* expects f.e. "#0x01" and returns either "#0x01"
-   if the value is not known to be within registers
-   or "a" or "r0".."r7".
-   (mov a,r7 or add a,r7 need one byte whereas
-    mov a,#0x01 or add a,#0x01 would take two
- */
-char * rtrackGetLit(const char *x)
-{
-  unsigned int i;
-
-  char *s;
-
-  if (enable != 1)
-    return (char *)x;
-
-  /* was it a numerical literal? */
-  if (*x == '#')
-    {
-      int val = strtol (x+1, &s, 16);
-      if (x+1 != s)
-        {
-          /* try to get from acc */
-          regs *r = &regs8051[A_IDX];
-          if (r->valueKnown &&
-              r->value == val)
-            {
-              D(emitcode (";", "genFromRTrack 0x%02x=%s", val, r->name));
-              return r->name;
-            }
-          /* try to get from register R0..R7 */
-          for (i=0; i<8; i++)
-            {
-              regs *r = &regs8051[Rx_NUM_TO_IDX(i)];
-              if (r->valueKnown &&
-                  r->value == val)
-                {
-                  D(emitcode (";", "genFromRTrack 0x%02x=%s", val, r->name));
-                  return r->name;
-                }
-            }
-        }
-      else
-        {
-          /* probably a symbolic literal as in "mov r3,#(_i+1)",
-             not handled... */
-        }
-    }
-
-  return (char *)x;
-}
-
-/* Similar to the above function 
-   As the destination is the accumulator try harder yet and
-   try to generate the result with arithmetic operations */
-int rtrackMoveALit (const char *x)
-{
-
-  if (enable != 1)
-    return 0;
-
-  /* if it is a literal mov try to get it cheaper */
-  if ( *x == '#' )
-    {
-      regs *a = &regs8051[A_IDX];
-
-      char *s;
-      int val = strtol (x+1, &s, 16);
-
-      /* was it a numerical literal? */
-      if (x+1 != s)
-        {
-          /* prefer mov a,#0x00 */
-          if (val == 0 &&
-              ((a->valueKnown && a->value != 0) ||
-               !a->valueKnown))
-            {
-              /* peepholes convert to clr a */
-              emitcode ("mov", "a,#0x00");
-              return 1;
-            }
-
-          if (a->valueKnown)
-            {
-              /* already there? */
-              if (val == a->value)
-                {
-                  D(emitcode (";", "genFromRTrack acc=0x%02x", a->value));
-                  return 1;
-                }
-
-              /* can be calculated with an instruction
-                 that does not change flags from acc itself? */
-              if (val == ((a->value+1) & 0xff) )
-                {
-                  D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+1", val, a->value));
-                  emitcode ("inc", "a");
-                  return 1;
-                }
-              if (val == ((a->value-1) & 0xff) )
-                {
-                  D(emitcode (";", "genFromRTrack 0x%02x=0x%02x-1", val, a->value));
-                  emitcode ("dec", "a");
-                  return 1;
-                }
-              if (val == ((~a->value) & 0xff) )
-                {
-                  D(emitcode (";", "genFromRTrack 0x%02x=~0x%02x", val, a->value));
-                  emitcode ("cpl", "a");
-                  return 1;
-                }
-              if (val == (((a->value>>1) |
-                           (a->value<<7)) & 0xff))
-                {
-                  D(emitcode (";", "genFromRTrack 0x%02x=rr(0x%02x)", val, a->value));
-                  emitcode ("rr", "a");
-                  return 1;
-                }
-              if (val == (((a->value<<1) |
-                           (a->value>>7)) & 0xff ))
-                {
-                  D(emitcode (";", "genFromRTrack 0x%02x=rl(0x%02x)", val, a->value));
-                  emitcode ("rl", "a");
-                  return 1;
-                }
-              if (val == ( ((a->value & 0x0f)<<4) |
-                           ((a->value & 0xf0)>>4) ))
-                {
-                  D(emitcode (";", "genFromRTrack 0x%02x=swap(0x%02x)", val, a->value));
-                  emitcode ("swap", "a");
-                  return 1;
-                }
-              /* Decimal Adjust Accumulator (da a) changes flags so not used */
-            }
-
-
-          {
-            unsigned int i;
-            char *ptr= rtrackGetLit(x);
-
-            if (x != ptr)
-              {
-                /* could get from register, fine */
-                emitcode ("mov", "a,%s", ptr);
-                return 1;
-              }
-
-            /* not yet giving up - try to calculate from register R0..R7 */
-            for (i=0; i<8; i++)
-              {
-                regs *r = &regs8051[Rx_NUM_TO_IDX(i)];
-
-                if (a->valueKnown && r->valueKnown)
-                  {
-                    /* calculate with a single byte instruction from R0..R7? */
-                    if (val == (a->value | r->value))
-                      {
-                        D(emitcode (";", "genFromRTrack 0x%02x=0x%02x|0x%02x",
-                                    val, a->value, r->value));
-                        emitcode ("orl", "a,%s",r->name);
-                        return 1;
-                      }
-                    if (val == (a->value & r->value))
-                      {
-                        D(emitcode (";", "genFromRTrack 0x%02x=0x%02x&0x%02x",
-                                    val, a->value, r->value));
-                        emitcode ("anl", "a,%s", r->name);
-                        return 1;
-                      }
-                    if (val == (a->value ^ r->value))
-                      {
-                        D(emitcode (";", "genFromRTrack 0x%02x=0x%02x^0x%02x",
-                                    val, a->value, r->value));
-                        emitcode ("xrl", "a,%s", r->name);
-                        return 1;
-                      }
-                    /* changes flags (does that matter?)
-                    if (val == (a->value + r->value))
-                      {
-                        D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+%0x02x",
-                                    val, a->value, r->value));
-                        emitcode ("add", "a,%s",r->name);
-                        return 1;
-                      }
-                    so not used */
-                  }
-              }
-          }
-      }
-    }
-
-  return 0;
-}
-
+/*-------------------------------------------------------------------------\r
+  rtrack.c - tracking content of registers on an mcs51\r
+\r
+  Copyright 2007 Frieder Ferlemann (Frieder Ferlemann AT web.de)\r
+\r
+  This program is free software; you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation; either version 2 of the License, or\r
+  (at your option) any later version.\r
+\r
+  This program is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with this program; if not, write to the Free Software\r
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA\r
+-------------------------------------------------------------------------*/\r
+\r
+/*-------------------------------------------------------------------------\r
+  Status:\r
+    - passes regression test suite, still bugs are likely\r
+    - only active if environment variable SDCC_RTRACK is set\r
+\r
+  Missed opportunities:\r
+    - does not track symbols as in "mov a,#_my_int" or "mov a,#(_my_int+1)"\r
+    - only used with moves to acc so chances to use: "inc dptr",\r
+      "inc r2", "add a,r2" or "mov r2,a" would not be detected)\r
+    - a label causes loss of tracking (no handling of information of blocks\r
+      known to follow/preceed the current block)\r
+    - not used in aopGet or genRet\r
+-------------------------------------------------------------------------*/\r
+\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include "SDCCglobl.h"\r
+\r
+#include "common.h"\r
+#include "ralloc.h"\r
+#include "gen.h"\r
+\r
+#define DEBUG(x)\r
+//#define DEBUG(x) x\r
+\r
+#define D(x) x\r
+\r
+#define REGS8051_SET(idx,val) do{ \\r
+                                  regs8051[idx].value = (val) & 0xff; \\r
+                                  regs8051[idx].valueKnown = 1; \\r
+                                  DEBUG(printf("%s:0x%02x\n",regs8051[idx].name, \\r
+                                                       regs8051[idx].value);) \\r
+                              } while(0)\r
+\r
+#define REGS8051_UNSET(idx)   do{ \\r
+                                  regs8051[idx].valueKnown = 0; \\r
+                                  DEBUG(printf("%s:*\n",regs8051[idx].name);) \\r
+                              } while(0)\r
+\r
+/* r0..r7 are not in numerical order in struct regs: r2..r7,r0,r1 */\r
+#define Rx_NUM_TO_IDX(num) (R2_IDX+((num-2)&0x07))\r
+\r
+\r
+/* move this (or rtrackGetLit() and rtrackMoveALit()\r
+   elsewhere? stealing emitcode from gen.c */\r
+void emitcode (const char *inst, const char *fmt,...);\r
+\r
+\r
+static int enable = -1;\r
+\r
+/*\r
+static void dumpAll()\r
+{\r
+  unsigned int i;\r
+  unsigned int nl=0;\r
+\r
+  for (i=0; i<END_IDX; i++)\r
+    {\r
+       if (regs8051[i].valueKnown)\r
+         {\r
+           if (!nl)\r
+             {\r
+               DEBUG(printf("know:");)\r
+             }\r
+           DEBUG(printf(" %s:0x%02x",regs8051[i].name,regs8051[i].value);)\r
+           nl = 1;\r
+         }\r
+    }\r
+  if (nl)\r
+    {\r
+      DEBUG(printf("\n");)\r
+    }\r
+}\r
+*/\r
+\r
+\r
+static void invalidateAllRx()\r
+{\r
+  //DEBUG(dumpAll();)\r
+  DEBUG(printf("R0..7:*\n");)\r
+  regs8051[R2_IDX].valueKnown = 0;\r
+  regs8051[R3_IDX].valueKnown = 0;\r
+  regs8051[R4_IDX].valueKnown = 0;\r
+  regs8051[R5_IDX].valueKnown = 0;\r
+  regs8051[R6_IDX].valueKnown = 0;\r
+  regs8051[R7_IDX].valueKnown = 0;\r
+  regs8051[R0_IDX].valueKnown = 0;\r
+  regs8051[R1_IDX].valueKnown = 0;\r
+}\r
+\r
+static void invalidateAll()\r
+{\r
+  DEBUG(printf("All:* ");)\r
+  invalidateAllRx();\r
+  regs8051[DPL_IDX].valueKnown = 0;\r
+  regs8051[DPH_IDX].valueKnown = 0;\r
+  regs8051[B_IDX].valueKnown = 0;\r
+  regs8051[A_IDX].valueKnown = 0;\r
+}\r
+\r
+static regs * getReg(const char *str)\r
+{\r
+  char *s;\r
+  int regNum;\r
+\r
+  regNum = strtol (str, &s, 16);\r
+  if (s == str+1)\r
+    {\r
+      return &regs8051[Rx_NUM_TO_IDX(regNum)];\r
+    }\r
+  return NULL;\r
+}\r
+\r
+/* tracking values within registers by looking\r
+   at the line passed to the assembler.\r
+   Tries to keep regs8051[] up to date */\r
+void rtrackUpdate (const char *line)\r
+{\r
+  if (enable == -1)\r
+    enable = (NULL != getenv("SDCC_RTRACK"));\r
+\r
+  if (!enable ||\r
+      *line == ';' ||                 /* comment */\r
+      (NULL != strstr( line, "==."))) /* dirty check for _G.debugLine */\r
+    return;                           /* nothing to do */\r
+\r
+  DEBUG(printf("%s\n",line);)\r
+\r
+  if (!strncmp (line,"mov",3))\r
+    {\r
+      /* check literal mov to accumulator */\r
+      if(!strncmp (line,"mov\ta,#0x",9))\r
+        {\r
+          char *s;\r
+          int value;\r
+\r
+          value = strtol (line+7, &s, 16);\r
+          if (s != line+7)\r
+              REGS8051_SET (A_IDX, value); /* valid hex found */\r
+          else\r
+              REGS8051_UNSET (A_IDX); /* probably a symbol (not handled) */\r
+\r
+          return;\r
+        }\r
+\r
+      if (!strncmp (line,"mov\ta,r",7))\r
+        {\r
+          /* handle mov from Rx if Rx is known */\r
+          regs *r = getReg(line+7);\r
+          if (r && r->valueKnown)\r
+            {\r
+              REGS8051_SET (A_IDX, r->value);\r
+              return;\r
+            }\r
+          REGS8051_UNSET (A_IDX);\r
+          return;\r
+        }\r
+\r
+      if (!strncmp (line,"mov\ta",5))\r
+        {\r
+          REGS8051_UNSET (A_IDX);\r
+          return;\r
+        }\r
+\r
+      if (!strncmp (line,"movc\ta",6) ||\r
+          !strncmp (line,"movx\ta",6))\r
+        {\r
+          REGS8051_UNSET (A_IDX);\r
+          return;\r
+        }\r
+\r
+      /* move direct to symbol, do not care */\r
+      if (!strncmp (line,"mov\t_",5) ||\r
+          !strncmp (line,"mov\t(_",6))\r
+        return;\r
+\r
+      /* check literal mov to register */\r
+      if (!strncmp (line,"mov\tr",5))\r
+        {\r
+          char *s;\r
+          int value;\r
+          int regNum;\r
+\r
+          regNum = strtol (line+5, &s, 16);\r
+          if (s == line+6)\r
+            {\r
+              value = strtol (line+8, &s, 16);\r
+              if ((s != line+8) && !strncmp (line+6,",#0x",4))\r
+                REGS8051_SET (Rx_NUM_TO_IDX(regNum), value);\r
+              else\r
+                REGS8051_UNSET (Rx_NUM_TO_IDX(regNum));\r
+              return;\r
+            }\r
+        }\r
+\r
+      /* mov to psw can change register bank */\r
+      if (!strncmp (line,"mov\tpsw,",8))\r
+        {\r
+          invalidateAllRx();\r
+          return;\r
+        }\r
+\r
+      /* no tracking of these, so we do not care */\r
+      if (!strncmp (line,"mov\tdptr,#",10) ||\r
+          !strncmp (line,"mov\tdpl,",8) ||\r
+          !strncmp (line,"mov\tdph,",8) ||\r
+          !strncmp (line,"mov\tsp,",7) ||\r
+          !strncmp (line,"mov\tb,",6))\r
+        return;\r
+\r
+      /* mov to xdata memory does not change registers */\r
+      if (!strncmp (line,"movx\t@",6))\r
+        return;\r
+\r
+      if (!strncmp (line,"mov\t@",5))\r
+        {\r
+          invalidateAllRx();\r
+          return;\r
+        }\r
+    }\r
+\r
+  /* no tracking of SP */\r
+  if (!strncmp (line,"push",4))\r
+    return;\r
+\r
+  if (!strncmp (line,"pop\ta",5))\r
+    {\r
+      if (!strncmp (line+4,"acc",3)){ REGS8051_UNSET (A_IDX); return; }\r
+      if (!strncmp (line+4,"ar2",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (2)); return; }\r
+      if (!strncmp (line+4,"ar3",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (3)); return; }\r
+      if (!strncmp (line+4,"ar4",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (4)); return; }\r
+      if (!strncmp (line+4,"ar5",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (5)); return; }\r
+      if (!strncmp (line+4,"ar6",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (6)); return; }\r
+      if (!strncmp (line+4,"ar7",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (7)); return; }\r
+      if (!strncmp (line+4,"ar0",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (0)); return; }\r
+      if (!strncmp (line+4,"ar1",3)){ REGS8051_UNSET (Rx_NUM_TO_IDX (1)); return; }\r
+    }\r
+\r
+  if (!strncmp (line,"inc",3))\r
+    {\r
+      /* no tracking of dptr, ignore */\r
+      if (!strcmp (line,"inc\tdptr") ||\r
+          !strcmp (line,"inc\tdph") ||\r
+          !strcmp (line,"inc\tdpl"))\r
+        return;\r
+\r
+      if (!strcmp (line,"inc\ta"))\r
+        {\r
+          if (regs8051[A_IDX].valueKnown)\r
+            REGS8051_SET (A_IDX, regs8051[A_IDX].value+1);\r
+          return;\r
+        }\r
+\r
+      if(!strncmp (line,"inc\tr",5))\r
+        {\r
+          regs *r = getReg(line+5);\r
+          if (r && r->valueKnown)\r
+            {\r
+              REGS8051_SET (r->rIdx, r->value+1);\r
+            }\r
+          return;\r
+        }\r
+    }\r
+\r
+  /* some bit in acc is cleared\r
+     MB: I'm too lazy to find out which right now */\r
+  if (!strncmp (line,"jbc\tacc",7))\r
+    {\r
+      REGS8051_UNSET (A_IDX);\r
+      return;\r
+    }\r
+\r
+  /* unfortunately the label typically following these\r
+     will cause loss of tracking */\r
+  if (!strncmp (line,"jc\t",3) ||\r
+      !strncmp (line,"jnc\t",4) ||\r
+      !strncmp (line,"jb\t",3) ||\r
+      !strncmp (line,"jnb\t",4) ||\r
+      !strncmp (line,"jbc\t",4))\r
+    return;\r
+\r
+  /* if branch not taken in "cjne r2,#0x08,somewhere" \r
+     r2 is known to be 8 */\r
+  if (!strncmp (line,"cjne",4))\r
+    {\r
+      if(!strncmp (line,"cjne\ta,#0x",10))\r
+        {\r
+          char *s;\r
+          int value;\r
+\r
+          value = strtol (line+8, &s, 16);\r
+          if (s != line+8)\r
+              REGS8051_SET (A_IDX, value); /* valid hex found */\r
+        }\r
+      if(!strncmp (line,"cjne\tr",6))\r
+        {\r
+          char *s;\r
+          int value;\r
+          regs *r = getReg(line+6);\r
+          value = strtol (line+8, &s, 16);\r
+          if (r && s != line+8)\r
+              REGS8051_SET (r->rIdx, value); /* valid hex found */\r
+        }\r
+      return;\r
+    }\r
+\r
+  /* acc eventually known to be zero */\r
+  if (!strncmp (line,"jz\t",3))\r
+    return;\r
+\r
+  /* acc eventually known to be zero */\r
+  if (!strncmp (line,"jnz\t",4))\r
+    {\r
+      REGS8051_SET (A_IDX, 0x00); // branch not taken\r
+      return;\r
+    }\r
+\r
+  if (!strncmp (line,"djnz\tr",6))\r
+    {\r
+      char *s;\r
+      int regNum;\r
+\r
+      regNum = strtol (line+6, &s, 16);\r
+      if (s == line+7)\r
+        {\r
+          //REGS8051_UNSET (Rx_NUM_TO_IDX(regNum));\r
+          REGS8051_SET (Rx_NUM_TO_IDX(regNum), 0x00); // branch not taken\r
+          return;\r
+        }\r
+    }\r
+\r
+  /* only carry bit, so we do not care */\r
+  if (!strncmp (line,"setb\tc",6) ||\r
+      !strncmp (line,"clr\tc",5) ||\r
+      !strncmp (line,"cpl\tc",5))\r
+    return;\r
+\r
+  if (!strncmp (line,"add\ta,",6) ||\r
+      !strncmp (line,"addc\ta,",7)||\r
+      !strncmp (line,"subb\ta,",7)||\r
+      !strncmp (line,"xrl\ta,",6) ||\r
+      !strncmp (line,"orl\ta,",6) ||\r
+      !strncmp (line,"anl\ta,",6) ||\r
+      !strncmp (line,"da\ta",4)   ||\r
+      !strncmp (line,"rlc\ta,",6) ||\r
+      !strncmp (line,"rrc\ta,",6) ||\r
+      !strncmp (line,"setb\ta",6) ||\r
+      !strncmp (line,"clrb\ta,",7)||\r
+      !strncmp (line,"cpl\tacc",7))\r
+    {\r
+      /* could also handle f.e. "add a,Rx" if a, Rx are known or "xrl a,#0x08" */\r
+      REGS8051_UNSET (A_IDX);\r
+      return;\r
+    }\r
+\r
+\r
+  if (!strncmp (line,"dec",3))\r
+    {\r
+      /* no tracking of dptr, so we would not care */\r
+      if (!strcmp (line,"dec\tdph") ||\r
+          !strcmp (line,"dec\tdpl"))\r
+        return;\r
+\r
+      if (!strcmp (line,"dec\ta"))\r
+        {\r
+          if (regs8051[A_IDX].valueKnown)\r
+            REGS8051_SET (A_IDX, regs8051[A_IDX].value-1);\r
+          return;\r
+        }\r
+\r
+      if(!strncmp (line,"dec\tr",5))\r
+        {\r
+          regs *r = getReg(line+5);\r
+          if (r && r->valueKnown)\r
+            {\r
+              REGS8051_SET (r->rIdx, r->value-1);\r
+            }\r
+          return;\r
+        }\r
+    }\r
+\r
+\r
+  if (!strcmp (line,"clr\ta"))\r
+    {\r
+      REGS8051_SET (A_IDX, 0);\r
+      return;\r
+    }\r
+\r
+  if (!strcmp (line,"cpl\ta"))\r
+    {\r
+      if (regs8051[A_IDX].valueKnown)\r
+        REGS8051_SET (A_IDX, ~regs8051[A_IDX].value);\r
+      return;\r
+    }\r
+  if (!strcmp (line,"rl\ta"))\r
+    {\r
+      if (regs8051[A_IDX].valueKnown)\r
+        REGS8051_SET (A_IDX, (regs8051[A_IDX].value<<1) | \r
+                             (regs8051[A_IDX].value>>7) );\r
+      return;\r
+    }\r
+  if (!strcmp (line,"rr\ta"))\r
+    {\r
+      if (regs8051[A_IDX].valueKnown)\r
+        REGS8051_SET (A_IDX, (regs8051[A_IDX].value>>1) |\r
+                             (regs8051[A_IDX].value<<7));\r
+      return;\r
+    }\r
+  if (!strcmp (line,"swap\ta"))\r
+    {\r
+      if (regs8051[A_IDX].valueKnown)\r
+        REGS8051_SET (A_IDX, (regs8051[A_IDX].value>>4) |\r
+                             (regs8051[A_IDX].value<<4));\r
+      return;\r
+    }\r
+\r
+  if (!strncmp (line,"mul",3) ||\r
+      !strncmp (line,"div",3)\r
+      )\r
+    {\r
+      REGS8051_UNSET (A_IDX);\r
+      REGS8051_UNSET (B_IDX);\r
+      return;\r
+    }\r
+\r
+  /* assuming these library functions have no side-effects */\r
+  if (!strcmp (line,"lcall"))\r
+    {\r
+      if (!strcmp (line,"lcall\t__gptrput"))\r
+        {\r
+          /* invalidate R0..R7 because they might have been changed */\r
+          /* MB: too paranoid ? */\r
+          //invalidateAllRx();\r
+          return;\r
+        }\r
+      if (!strcmp (line,"lcall\t__gptrget"))\r
+        {\r
+          REGS8051_UNSET (A_IDX);\r
+          return;\r
+        }\r
+      if (!strcmp (line,"lcall\t__decdptr"))\r
+        {\r
+          return;\r
+        }\r
+     }\r
+\r
+  if (!strncmp (line,"xch\ta,r",7))\r
+    {\r
+      /* handle xch acc with Rn */\r
+      regs *r = getReg(line+7);\r
+      if (r)\r
+        {\r
+          unsigned swap;\r
+          swap = r->valueKnown;\r
+          r->valueKnown = regs8051[A_IDX].valueKnown;\r
+          regs8051[A_IDX].valueKnown = swap;\r
+\r
+          swap = r->value;\r
+          r->value = regs8051[A_IDX].value;\r
+          regs8051[A_IDX].value = swap;\r
+          return;\r
+        }\r
+    }\r
+\r
+  /* all others unrecognized, invalidate */\r
+  invalidateAll();\r
+}\r
+\r
+\r
+/* expects f.e. "#0x01" and returns either "#0x01"\r
+   if the value is not known to be within registers\r
+   or "a" or "r0".."r7".\r
+   (mov a,r7 or add a,r7 need one byte whereas\r
+    mov a,#0x01 or add a,#0x01 would take two\r
+ */\r
+char * rtrackGetLit(const char *x)\r
+{\r
+  unsigned int i;\r
+\r
+  char *s;\r
+\r
+  if (enable != 1)\r
+    return (char *)x;\r
+\r
+  /* was it a numerical literal? */\r
+  if (*x == '#')\r
+    {\r
+      int val = strtol (x+1, &s, 16);\r
+      if (x+1 != s)\r
+        {\r
+          /* try to get from acc */\r
+          regs *r = &regs8051[A_IDX];\r
+          if (r->valueKnown &&\r
+              r->value == val)\r
+            {\r
+              D(emitcode (";", "genFromRTrack 0x%02x=%s", val, r->name));\r
+              return r->name;\r
+            }\r
+          /* try to get from register R0..R7 */\r
+          for (i=0; i<8; i++)\r
+            {\r
+              regs *r = &regs8051[Rx_NUM_TO_IDX(i)];\r
+              if (r->valueKnown &&\r
+                  r->value == val)\r
+                {\r
+                  D(emitcode (";", "genFromRTrack 0x%02x=%s", val, r->name));\r
+                  return r->name;\r
+                }\r
+            }\r
+        }\r
+      else\r
+        {\r
+          /* probably a symbolic literal as in "mov r3,#(_i+1)",\r
+             not handled... */\r
+        }\r
+    }\r
+\r
+  return (char *)x;\r
+}\r
+\r
+/* Similar to the above function \r
+   As the destination is the accumulator try harder yet and\r
+   try to generate the result with arithmetic operations */\r
+int rtrackMoveALit (const char *x)\r
+{\r
+\r
+  if (enable != 1)\r
+    return 0;\r
+\r
+  /* if it is a literal mov try to get it cheaper */\r
+  if ( *x == '#' )\r
+    {\r
+      regs *a = &regs8051[A_IDX];\r
+\r
+      char *s;\r
+      int val = strtol (x+1, &s, 16);\r
+\r
+      /* was it a numerical literal? */\r
+      if (x+1 != s)\r
+        {\r
+          /* prefer mov a,#0x00 */\r
+          if (val == 0 &&\r
+              ((a->valueKnown && a->value != 0) ||\r
+               !a->valueKnown))\r
+            {\r
+              /* peepholes convert to clr a */\r
+              /* MB: why not here ? */\r
+              emitcode ("mov", "a,#0x00");\r
+              return 1;\r
+            }\r
+\r
+          if (a->valueKnown)\r
+            {\r
+              /* already there? */\r
+              if (val == a->value)\r
+                {\r
+                  D(emitcode (";", "genFromRTrack acc=0x%02x", a->value));\r
+                  return 1;\r
+                }\r
+\r
+              /* can be calculated with an instruction\r
+                 that does not change flags from acc itself? */\r
+              if (val == ((a->value+1) & 0xff) )\r
+                {\r
+                  D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+1", val, a->value));\r
+                  emitcode ("inc", "a");\r
+                  return 1;\r
+                }\r
+              if (val == ((a->value-1) & 0xff) )\r
+                {\r
+                  D(emitcode (";", "genFromRTrack 0x%02x=0x%02x-1", val, a->value));\r
+                  emitcode ("dec", "a");\r
+                  return 1;\r
+                }\r
+              if (val == ((~a->value) & 0xff) )\r
+                {\r
+                  D(emitcode (";", "genFromRTrack 0x%02x=~0x%02x", val, a->value));\r
+                  emitcode ("cpl", "a");\r
+                  return 1;\r
+                }\r
+              if (val == (((a->value>>1) |\r
+                           (a->value<<7)) & 0xff))\r
+                {\r
+                  D(emitcode (";", "genFromRTrack 0x%02x=rr(0x%02x)", val, a->value));\r
+                  emitcode ("rr", "a");\r
+                  return 1;\r
+                }\r
+              if (val == (((a->value<<1) |\r
+                           (a->value>>7)) & 0xff ))\r
+                {\r
+                  D(emitcode (";", "genFromRTrack 0x%02x=rl(0x%02x)", val, a->value));\r
+                  emitcode ("rl", "a");\r
+                  return 1;\r
+                }\r
+              if (val == ( ((a->value & 0x0f)<<4) |\r
+                           ((a->value & 0xf0)>>4) ))\r
+                {\r
+                  D(emitcode (";", "genFromRTrack 0x%02x=swap(0x%02x)", val, a->value));\r
+                  emitcode ("swap", "a");\r
+                  return 1;\r
+                }\r
+              /* Decimal Adjust Accumulator (da a) changes flags so not used */\r
+            }\r
+\r
+\r
+          {\r
+            unsigned int i;\r
+            char *ptr= rtrackGetLit(x);\r
+\r
+            if (x != ptr)\r
+              {\r
+                /* could get from register, fine */\r
+                emitcode ("mov", "a,%s", ptr);\r
+                return 1;\r
+              }\r
+\r
+            /* not yet giving up - try to calculate from register R0..R7 */\r
+            for (i=0; i<8; i++)\r
+              {\r
+                regs *r = &regs8051[Rx_NUM_TO_IDX(i)];\r
+\r
+                if (a->valueKnown && r->valueKnown)\r
+                  {\r
+                    /* calculate with a single byte instruction from R0..R7? */\r
+                    if (val == (a->value | r->value))\r
+                      {\r
+                        D(emitcode (";", "genFromRTrack 0x%02x=0x%02x|0x%02x",\r
+                                    val, a->value, r->value));\r
+                        emitcode ("orl", "a,%s",r->name);\r
+                        return 1;\r
+                      }\r
+                    if (val == (a->value & r->value))\r
+                      {\r
+                        D(emitcode (";", "genFromRTrack 0x%02x=0x%02x&0x%02x",\r
+                                    val, a->value, r->value));\r
+                        emitcode ("anl", "a,%s", r->name);\r
+                        return 1;\r
+                      }\r
+                    if (val == (a->value ^ r->value))\r
+                      {\r
+                        D(emitcode (";", "genFromRTrack 0x%02x=0x%02x^0x%02x",\r
+                                    val, a->value, r->value));\r
+                        emitcode ("xrl", "a,%s", r->name);\r
+                        return 1;\r
+                      }\r
+                    /* changes flags (does that matter?)\r
+                    if (val == (a->value + r->value))\r
+                      {\r
+                        D(emitcode (";", "genFromRTrack 0x%02x=0x%02x+%0x02x",\r
+                                    val, a->value, r->value));\r
+                        emitcode ("add", "a,%s",r->name);\r
+                        return 1;\r
+                      }\r
+                    so not used */\r
+                  }\r
+              }\r
+          }\r
+      }\r
+    }\r
+\r
+  return 0;\r
+}\r
+\r