-/*-------------------------------------------------------------------------\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 ®s8051[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 = ®s8051[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 = ®s8051[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 = ®s8051[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 = ®s8051[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
+/*-------------------------------------------------------------------------
+ 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;
+}
+
+static regs * getReg(const char *str)
+{
+ char *s;
+ int regNum;
+
+ regNum = strtol (str, &s, 16);
+ if (s == str+1)
+ {
+ return ®s8051[Rx_NUM_TO_IDX(regNum)];
+ }
+ return NULL;
+}
+
+/* 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 */
+ regs *r = getReg(line+7);
+ if (r && 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))
+ {
+ regs *r = getReg(line+5);
+ if (r && r->valueKnown)
+ {
+ REGS8051_SET (r->rIdx, r->value+1);
+ }
+ return;
+ }
+ }
+
+ /* some bit in acc is cleared
+ MB: I'm too lazy to find out which right now */
+ if (!strncmp (line,"jbc\tacc",7))
+ {
+ REGS8051_UNSET (A_IDX);
+ 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))
+ {
+ if(!strncmp (line,"cjne\ta,#0x",10))
+ {
+ char *s;
+ int value;
+
+ value = strtol (line+8, &s, 16);
+ if (s != line+8)
+ REGS8051_SET (A_IDX, value); /* valid hex found */
+ }
+ if(!strncmp (line,"cjne\tr",6))
+ {
+ char *s;
+ int value;
+ regs *r = getReg(line+6);
+ value = strtol (line+8, &s, 16);
+ if (r && s != line+8)
+ REGS8051_SET (r->rIdx, value); /* valid hex found */
+ }
+ return;
+ }
+
+ /* acc eventually known to be zero */
+ if (!strncmp (line,"jz\t",3))
+ return;
+
+ /* acc eventually known to be zero */
+ if (!strncmp (line,"jnz\t",4))
+ {
+ REGS8051_SET (A_IDX, 0x00); // branch not taken
+ 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)||
+ !strncmp (line,"cpl\tacc",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))
+ {
+ regs *r = getReg(line+5);
+ if (r && r->valueKnown)
+ {
+ REGS8051_SET (r->rIdx, 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 */
+ /* MB: too paranoid ? */
+ //invalidateAllRx();
+ return;
+ }
+ if (!strcmp (line,"lcall\t__gptrget"))
+ {
+ REGS8051_UNSET (A_IDX);
+ return;
+ }
+ if (!strcmp (line,"lcall\t__decdptr"))
+ {
+ return;
+ }
+ }
+
+ if (!strncmp (line,"xch\ta,r",7))
+ {
+ /* handle xch acc with Rn */
+ regs *r = getReg(line+7);
+ if (r)
+ {
+ unsigned swap;
+ swap = r->valueKnown;
+ r->valueKnown = regs8051[A_IDX].valueKnown;
+ regs8051[A_IDX].valueKnown = swap;
+
+ swap = r->value;
+ r->value = regs8051[A_IDX].value;
+ regs8051[A_IDX].value = swap;
+ 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 = ®s8051[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 = ®s8051[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 = ®s8051[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 */
+ /* MB: why not here ? */
+ 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 = ®s8051[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;
+}
+