From: frief Date: Thu, 15 Feb 2007 11:23:10 +0000 (+0000) Subject: * src/mcs51/rtrack.h, X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=411659c52d5ed92288a8ffedf34226f61b291315;p=fw%2Fsdcc * src/mcs51/rtrack.h, * src/mcs51/rtrack.c: added register tracking for the mcs51 port, by checking the strings passed by emitcode() to the assembler. Feel free to change. This in part addresses RFE #482179. Set environment variable SDCC_RTRACK to enable. * src/mcs51/gen.c: inserted hooks * src/mcs51/ralloc.h: added two members to struct regs * support/regression/tests/regtrack.c: added git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@4634 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/ChangeLog b/ChangeLog index 8b7ca7b2..3104599e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2007-02-15 Frieder Ferlemann + + * src/mcs51/rtrack.h, + * src/mcs51/rtrack.c: added register tracking for the mcs51 port, + by checking the strings passed by emitcode() to the assembler. + Feel free to change. This in part addresses RFE #482179. + Set environment variable SDCC_RTRACK to enable. + * src/mcs51/gen.c: inserted hooks + * src/mcs51/ralloc.h: added two members to struct regs + * support/regression/tests/regtrack.c: added + 2007-02-14 Borut Razem * src/SDCC.y: fixed bug #1291133: duplicate members across enum(s) diff --git a/src/mcs51/gen.c b/src/mcs51/gen.c index cfb3e44b..b476551b 100644 --- a/src/mcs51/gen.c +++ b/src/mcs51/gen.c @@ -41,6 +41,7 @@ #include "common.h" #include "SDCCpeeph.h" #include "ralloc.h" +#include "rtrack.h" #include "gen.h" #include "dbuf_string.h" @@ -149,7 +150,7 @@ static unsigned char SRMask[] = /*-----------------------------------------------------------------*/ /* emitcode - writes the code into a file : for now it is simple */ /*-----------------------------------------------------------------*/ -static void +void emitcode (const char *inst, const char *fmt,...) { va_list ap; @@ -184,6 +185,8 @@ emitcode (const char *inst, const char *fmt,...) if (lbp && *lbp) { + rtrackUpdate (lbp); + lineCurr = (lineCurr ? connectLine (lineCurr, newLineNode (lb)) : (lineHead = newLineNode (lb))); @@ -227,6 +230,11 @@ mova (const char *x) if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4)) return; + /* if it is a literal mov try to get it cheaper */ + if (*x == '#' && + rtrackMoveALit(x)) + return; + emitcode("mov", "a,%s", x); } @@ -240,6 +248,13 @@ movb (const char *x) if (!strncmp(x, "b", 2)) return; + /* if it is a literal mov try to get it cheaper */ + if (*x == '#') + { + emitcode("mov","b,%s", rtrackGetLit(x)); + return; + } + emitcode("mov","b,%s", x); } @@ -4960,7 +4975,7 @@ genMultOneByte (operand * left, { /* moving to accumulator first helps peepholes */ MOVA (aopGet (left, 0, FALSE, FALSE)); - emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE)); + MOVB (aopGet (right, 0, FALSE, FALSE)); } else { @@ -5235,7 +5250,7 @@ genDivOneByte (operand * left, if (lUnsigned && rUnsigned) { /* unsigned is easy */ - emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE)); + MOVB (aopGet (right, 0, FALSE, FALSE)); MOVA (aopGet (left, 0, FALSE, FALSE)); emitcode ("div", "ab"); aopPut (result, "a", 0); @@ -5549,7 +5564,7 @@ genModOneByte (operand * left, if (lUnsigned && rUnsigned) { /* unsigned is easy */ - emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE)); + MOVB (aopGet (right, 0, FALSE, FALSE)); MOVA (aopGet (left, 0, FALSE, FALSE)); emitcode ("div", "ab"); aopPut (result, "b", 0); diff --git a/src/mcs51/ralloc.h b/src/mcs51/ralloc.h index cfb9584d..7153faa9 100644 --- a/src/mcs51/ralloc.h +++ b/src/mcs51/ralloc.h @@ -56,6 +56,8 @@ typedef struct regs char *base; /* base address */ short offset; /* offset from the base */ unsigned isFree:1; /* is currently unassigned */ + unsigned char value; /* from rtrack.c only valid when valueKnown is set */ + short valueKnown; } regs; extern regs regs8051[]; diff --git a/src/mcs51/rtrack.c b/src/mcs51/rtrack.c new file mode 100644 index 00000000..10882d7f --- /dev/null +++ b/src/mcs51/rtrack.c @@ -0,0 +1,638 @@ +/*------------------------------------------------------------------------- + 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 +#include +#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; ivalueKnown) + { + 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 = ®s8051[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 = ®s8051[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 = ®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 */ + 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; +} + diff --git a/src/mcs51/rtrack.h b/src/mcs51/rtrack.h new file mode 100644 index 00000000..8a329d6c --- /dev/null +++ b/src/mcs51/rtrack.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + rtrack.h - header file for 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 +-------------------------------------------------------------------------*/ + +void rtrackUpdate (const char *line); + +char * rtrackGetLit(const char *x); + +int rtrackMoveALit (const char *x);