From d10151253d907646b1040f76f9b152f2f9d25835 Mon Sep 17 00:00:00 2001 From: tecodev Date: Wed, 19 Jan 2005 16:48:36 +0000 Subject: [PATCH] * src/SDCCglobl.h: ensure that PATH_MAX >= 2048 to guarantee cmdLine buffers (used when calling sdcpp...) are large enough (MAX_PATH=256 truncates arguments leading to system halts when used in MinGW...) * src/pic16/gen.c (pic16_sameRegs): relaxed size criterion * (genUminus): rewritten to for efficiency * (genNearPointer[GS]et): enforce reloading of FSR0 (was still used uninitialized in some cases) * (genCast): upcasting a 16bit int to a 24bit GPOINTER may not copy the third byte from the int -- now assumes 0x80 (data memory) * src/pic16/genarith.c (pic16_genPlus): fixed bug when swapping operands (genAddLit expects the iCode's operands to swapped as well), fixed leftover bytes (crashed for short left operands) * (pic16_genMinusDec): performance improvements, removed false PIC14 emitSKPNCs * (pic16_genMinus): fixed to cope with differently sized operands * src/pic16/glue.c (pic16_glue): added new banksel optimization for --obanksel > 1 * src/pic16/pcode.c: implemented (first phase of) banksel optimization * src/pic16/graph.[ch]: implementation of directed graphs, used by new banksel optimization * src/pic16/pcoderegs.c (pCodeRegMapLiveRangesInFlow): prevented analysis for temporary registers (segfaults...) * src/pic16/peeph.def: added rule git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@3640 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- ChangeLog | 43 ++- src/SDCCglobl.h | 5 +- src/pic16/gen.c | 58 ++-- src/pic16/genarith.c | 228 +++++++++------ src/pic16/glue.c | 6 + src/pic16/graph.c | 180 ++++++++++++ src/pic16/graph.h | 113 ++++++++ src/pic16/pcode.c | 660 ++++++++++++++++++++++++++++++++++++++++++ src/pic16/pcoderegs.c | 2 +- src/pic16/peeph.def | 8 + 10 files changed, 1190 insertions(+), 113 deletions(-) create mode 100755 src/pic16/graph.c create mode 100755 src/pic16/graph.h diff --git a/ChangeLog b/ChangeLog index 98ab9338..72426368 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2005-01-19 Raphael Neider + + * src/SDCCglobl.h: ensure that PATH_MAX >= 2048 to guarantee + cmdLine buffers (used when calling sdcpp...) are large enough + (MAX_PATH=256 truncates arguments leading to system halts when + used in MinGW...) + * src/pic16/gen.c (pic16_sameRegs): relaxed size criterion + * (genUminus): rewritten to for efficiency + * (genNearPointer[GS]et): enforce reloading of FSR0 (was still + used uninitialized in some cases) + * (genCast): upcasting a 16bit int to a 24bit GPOINTER may not + copy the third byte from the int -- now assumes 0x80 (data memory) + * src/pic16/genarith.c (pic16_genPlus): fixed bug when swapping + operands (genAddLit expects the iCode's operands to swapped as + well), fixed leftover bytes (crashed for short left operands) + * (pic16_genMinusDec): performance improvements, removed false + PIC14 emitSKPNCs + * (pic16_genMinus): fixed to cope with differently sized operands + * src/pic16/glue.c (pic16_glue): added new banksel optimization + for --obanksel > 1 + * src/pic16/pcode.c: implemented (first phase of) banksel optimization + * src/pic16/graph.[ch]: implementation of directed graphs, used by + new banksel optimization + * src/pic16/pcoderegs.c (pCodeRegMapLiveRangesInFlow): prevented + analysis for temporary registers (segfaults...) + * src/pic16/peeph.def: added rule + 2005-01-18 Vangelis Rokas * device/lib/pic16/libc/stdlib/x_ftoa.c: it defines x_ftoa function @@ -46,28 +73,28 @@ 2005-01-08 Raphael Neider - * src/pic16/device.c (pic16_dump_usection) changed naming scheme for + * src/pic16/device.c (pic16_dump_usection): changed naming scheme for udata sections to fix bug #1097823 2005-01-05 Raphael Neider - * src/pic16/gen.c (genGenericShift) added handling of differently + * src/pic16/gen.c (genGenericShift): added handling of differently sized left operand and result 2005-01-04 Raphael Neider - * src/pic16/gen.c (genIfxJump) fixed inverted skips on CARRY - * (genIfx) fixed (?) read from uninitialized SPIL_LOC (now assumes CARRY + * src/pic16/gen.c (genIfxJump): fixed inverted skips on CARRY + * (genIfx): fixed (?) read from uninitialized SPIL_LOC (now assumes CARRY to hold the condition bit) * added new version of genCmp (old code available via #define) * added new version of genShiftLeft/genShiftRight in a generic way, now supports shifting by negative values - * (genLeftShiftLiteral, genRightShiftLiteral) use absolute value of + * (genLeftShiftLiteral, genRightShiftLiteral): use absolute value of shiftCount (expected by genGenericShift) - * src/pic16/genarith.c (genPlus) added code for adding CARRY+literal - * src/pic16/pcode.c (pic16_OptimizeJumps) removed annoying statistics + * src/pic16/genarith.c (genPlus): added code for adding CARRY+literal + * src/pic16/pcode.c (pic16_OptimizeJumps): removed annoying statistics dump - * (pic16_newpCodeOpLit) changed to cast to unsigned char (as e.g. -32766 + * (pic16_newpCodeOpLit): changed to cast to unsigned char (as e.g. -32766 is an invalid literal too...) 2005-01-04 Vangelis Rokas diff --git a/src/SDCCglobl.h b/src/SDCCglobl.h index 850c0633..b60bc26d 100644 --- a/src/SDCCglobl.h +++ b/src/SDCCglobl.h @@ -38,8 +38,9 @@ #define ZERO 0 #include /* PATH_MAX */ -#ifndef PATH_MAX /* POSIX, but not required */ -# define PATH_MAX 255 /* define a reasonable value */ +#if !defined(PATH_MAX) || (PATH_MAX < 2048) +# undef PATH_MAX +# define PATH_MAX 2048 /* define a reasonable value */ #endif #define MAX_REG_PARMS 1 diff --git a/src/pic16/gen.c b/src/pic16/gen.c index fc6eb6f8..e9b64a78 100644 --- a/src/pic16/gen.c +++ b/src/pic16/gen.c @@ -1069,10 +1069,12 @@ bool pic16_sameRegs (asmop *aop1, asmop *aop2 ) aop2->type != AOP_REG ) return FALSE ; + /* This is a bit too restrictive if one is a subset of the other... if (aop1->size != aop2->size ) return FALSE ; + */ - for (i = 0 ; i < aop1->size ; i++ ) { + for (i = 0 ; i < min(aop1->size, aop2->size) ; i++ ) { // if(aop1->aopu.aop_reg[i]->type != aop2->aopu.aop_reg[i]->type)return FALSE; // if(aop1->aopu.aop_reg[i]->type == AOP_REG) @@ -2680,6 +2682,8 @@ static void genUminus (iCode *ic) { int size, i; sym_link *optype, *rtype; + symbol *label; + int needLabel=0; FENTRY; @@ -2708,21 +2712,33 @@ static void genUminus (iCode *ic) /* otherwise subtract from zero by taking the 2's complement */ size = AOP_SIZE(IC_LEFT(ic)); - - for(i=0; i 0; i--) { + pic16_emitpcode (POC_COMF, pic16_popGet (AOP(IC_LEFT(ic)), i)); + } // for + pic16_emitpcode (POC_NEGF, pic16_popGet (AOP(IC_LEFT(ic)), 0)); + for (i=1; i < size; i++) { + if (i == size - 1) { emitSKPNZ; } else { pic16_emitpcode (POC_BNZ, pic16_popGetLabel (label->key)); needLabel++; } + pic16_emitpcode (POC_INCF, pic16_popGet (AOP(IC_LEFT(ic)), i)); + } // for + } else { + for (i=size-1; i >= 0; i--) { + pic16_emitpcode (POC_COMFW, pic16_popGet (AOP(IC_LEFT(ic)), i)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP(IC_RESULT(ic)), i)); + } // for + if (size > 1) { + for (i=0; i < size-2; i++) { + pic16_emitpcode (POC_INCF, pic16_popGet (AOP(IC_RESULT(ic)),i)); + pic16_emitpcode (POC_BNZ, pic16_popGetLabel (label->key)); needLabel++; + } // for + pic16_emitpcode (POC_INFSNZ, pic16_popGet (AOP(IC_RESULT(ic)), size-2)); + } // if + pic16_emitpcode (POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)), size-1)); } + if (needLabel) + pic16_emitpLabel (label->key); release: /* release the aops */ @@ -11059,7 +11075,7 @@ static void genNearPointerGet (operand *left, /* if the value is already in a pointer register * then don't need anything more */ - if (!AOP_INPREG(AOP(left))) { + if (1 || !AOP_INPREG(AOP(left))) { // AOP_INPREG(AOP(left)) is not always correct... /* otherwise get a free pointer register */ DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); @@ -11946,7 +11962,7 @@ static void genNearPointerSet (operand *right, /* if the value is already in a pointer register * then don't need anything more */ - if (!AOP_INPREG(AOP(result))) { + if (1 || !AOP_INPREG(AOP(result))) { // AOP_INPREG(AOP(result)) is not always correct... /* otherwise get a free pointer register */ DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); @@ -13274,7 +13290,13 @@ static void genCast (iCode *ic) break; case GPOINTER: - pic16_emitpcode(POC_MOVFF, pic16_popGet2(AOP(right), AOP(result), GPTRSIZE-1)); + if (GPTRSIZE > AOP_SIZE(right)) { + // assume data pointer... THIS MIGHT BE WRONG! + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0x80)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result), GPTRSIZE - 1)); + } else { + pic16_emitpcode(POC_MOVFF, pic16_popGet2(AOP(right), AOP(result), GPTRSIZE-1)); + } break; default: diff --git a/src/pic16/genarith.c b/src/pic16/genarith.c index ff6e1d62..39f3dcbd 100644 --- a/src/pic16/genarith.c +++ b/src/pic16/genarith.c @@ -767,8 +767,8 @@ void pic16_genPlus (iCode *ic) if ( (AOP_TYPE(left) == AOP_LIT) || (pic16_sameRegs(AOP(right), AOP(result))) ) { operand *t = right; - right = left; - left = t; + right = IC_RIGHT(ic) = left; + left = IC_LEFT(ic) = t; } /* if both left & right are in bit space */ @@ -809,12 +809,12 @@ void pic16_genPlus (iCode *ic) if (pic16_genPlusIncr (ic) == TRUE) goto release; - size = pic16_getDataSize(IC_RESULT(ic)); + size = pic16_getDataSize(result); - if(AOP(IC_RIGHT(ic))->type == AOP_LIT) { + if(AOP(right)->type == AOP_LIT) { /* Add a literal to something else */ //bool know_W=0; - unsigned lit = (unsigned) floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit); + unsigned lit = (unsigned) floatFromVal(AOP(right)->aopu.aop_lit); //unsigned l1=0; //offset = 0; @@ -823,55 +823,55 @@ void pic16_genPlus (iCode *ic) genAddLit (ic, lit); goto release; - } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) { + } else if(AOP_TYPE(right) == AOP_CRY) { - pic16_emitcode(";bitadd","right is bit: %s",pic16_aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE)); - pic16_emitcode(";bitadd","left is bit: %s",pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); - pic16_emitcode(";bitadd","result is bit: %s",pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + pic16_emitcode(";bitadd","right is bit: %s",pic16_aopGet(AOP(right),0,FALSE,FALSE)); + pic16_emitcode(";bitadd","left is bit: %s",pic16_aopGet(AOP(left),0,FALSE,FALSE)); + pic16_emitcode(";bitadd","result is bit: %s",pic16_aopGet(AOP(result),0,FALSE,FALSE)); /* here we are adding a bit to a char or int */ if(size == 1) { - if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + if (pic16_sameRegs(AOP(left), AOP(result)) ) { - pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0)); - pic16_emitpcode(POC_INCF , pic16_popGet(AOP(IC_RESULT(ic)),0)); + pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_INCF , pic16_popGet(AOP(result),0)); pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", - AOP(IC_RIGHT(ic))->aopu.aop_dir, - AOP(IC_RIGHT(ic))->aopu.aop_dir); - pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(result),0,FALSE,FALSE)); } else { // not same - if(AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) { - pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0)); + if(AOP_TYPE(left) == AOP_ACC) { + pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(right),0)); pic16_emitpcode(POC_XORLW , pic16_popGetLit(1)); pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", - AOP(IC_RIGHT(ic))->aopu.aop_dir, - AOP(IC_RIGHT(ic))->aopu.aop_dir); + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); pic16_emitcode(" xorlw","1"); } else { - pic16_mov2w(AOP(IC_LEFT(ic)),0); - pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0)); - pic16_emitpcode(POC_INCFW , pic16_popGet(AOP(IC_LEFT(ic)),0)); + pic16_mov2w(AOP(left),0); + pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_INCFW , pic16_popGet(AOP(left),0)); - pic16_emitcode("movf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + pic16_emitcode("movf","%s,w", pic16_aopGet(AOP(left),0,FALSE,FALSE)); pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", - AOP(IC_RIGHT(ic))->aopu.aop_dir, - AOP(IC_RIGHT(ic))->aopu.aop_dir); - pic16_emitcode(" incf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + pic16_emitcode(" incf","%s,w", pic16_aopGet(AOP(left),0,FALSE,FALSE)); } - if(AOP_TYPE(IC_RESULT(ic)) != AOP_ACC) { + if(AOP_TYPE(result) != AOP_ACC) { - if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) { + if(AOP_TYPE(result) == AOP_CRY) { pic16_emitpcode(POC_ANDLW , pic16_popGetLit(1)); - pic16_emitpcode(POC_BCF , pic16_popGet(AOP(IC_RESULT(ic)),0)); + pic16_emitpcode(POC_BCF , pic16_popGet(AOP(result),0)); emitSKPZ; - pic16_emitpcode(POC_BSF , pic16_popGet(AOP(IC_RESULT(ic)),0)); + pic16_emitpcode(POC_BSF , pic16_popGet(AOP(result),0)); } else { - pic16_emitpcode(POC_MOVWF , pic16_popGet(AOP(IC_RESULT(ic)),0)); - pic16_emitcode("movwf","%s", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + pic16_emitpcode(POC_MOVWF , pic16_popGet(AOP(result),0)); + pic16_emitcode("movwf","%s", pic16_aopGet(AOP(result),0,FALSE,FALSE)); } } } @@ -879,39 +879,39 @@ void pic16_genPlus (iCode *ic) } else { int offset = 1; DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); - if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + if (pic16_sameRegs(AOP(left), AOP(result)) ) { emitCLRZ; - pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_RIGHT(ic)),0)); - pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),0)); + pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0)); pic16_emitcode("clrz",""); pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", - AOP(IC_RIGHT(ic))->aopu.aop_dir, - AOP(IC_RIGHT(ic))->aopu.aop_dir); - pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(result),0,FALSE,FALSE)); } else { emitCLRZ; // needed here as well: INCFW is not always executed, Z is undefined then - pic16_mov2w(AOP(IC_LEFT(ic)),0); - pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_RIGHT(ic)),0)); - pic16_emitpcode(POC_INCFW, pic16_popGet(AOP(IC_LEFT(ic)),0)); - //pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE)); - emitMOVWF(IC_RIGHT(ic),0); + pic16_mov2w(AOP(left),0); + pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_INCFW, pic16_popGet(AOP(left),0)); + //pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(right),0,FALSE,FALSE)); + emitMOVWF(right,0); - pic16_emitcode("movf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + pic16_emitcode("movf","%s,w", pic16_aopGet(AOP(left),0,FALSE,FALSE)); pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", - AOP(IC_RIGHT(ic))->aopu.aop_dir, - AOP(IC_RIGHT(ic))->aopu.aop_dir); - pic16_emitcode(" incf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); - pic16_emitcode("movwf","%s", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + pic16_emitcode(" incf","%s,w", pic16_aopGet(AOP(left),0,FALSE,FALSE)); + pic16_emitcode("movwf","%s", pic16_aopGet(AOP(result),0,FALSE,FALSE)); } while(--size){ emitSKPZ; - pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),offset++)); - //pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(IC_RIGHT(ic)),offset++,FALSE,FALSE)); + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),offset++)); + //pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(right),offset++,FALSE,FALSE)); } } @@ -1017,6 +1017,50 @@ void pic16_genPlus (iCode *ic) } } + // add leftover bytes + // either left or right is too short + for (i=size; i < AOP_SIZE(result); i++) { + fprintf (stderr, "%s:%d: new code...\n", __FUNCTION__, __LINE__); + pic16_emitcode ("; ", "new arithmetics... test me..."); + // get right operand into WREG + if (i < AOP_SIZE(right)) { + pic16_mov2w (AOP(right), i); + } else { + pic16_emitcode ("; =##", "right too short"); + // right is too short + pic16_emitpcode (POC_CLRF, pic16_popCopyReg (&pic16_pc_wreg)); + if (!SPEC_USIGN(getSpec(operandType(right)))) { + pic16_emitcode ("; =##", "right signed"); + // right operand is signed + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),AOP_SIZE(right)-1,FALSE,FALSE),7,0, PO_GPR_REGISTER)); + pic16_emitpcode(POC_COMF, pic16_popCopyReg (&pic16_pc_wreg)); + } + } + + // get left+WREG+CARRY into result + if (i < AOP_SIZE(left)) { + if (pic16_sameRegs (AOP(left), AOP(result))) { + pic16_emitpcode (POC_ADDWFC, pic16_popGet (AOP(result), i)); + } else { + pic16_emitpcode (POC_ADDFWC, pic16_popGet (AOP(left), i)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),i)); + } + } else { + pic16_emitcode ("; =##", "left too short"); + // left is too short + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP(result), i)); + if (!SPEC_USIGN(getSpec(operandType(left)))) { + pic16_emitcode ("; =##", "left signed"); + // left operand is signed + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),AOP_SIZE(left)-1,FALSE,FALSE),7,0, PO_GPR_REGISTER)); + pic16_emitpcode(POC_COMF, pic16_popGet (AOP(result), i)); + } + pic16_emitpcode (POC_ADDWFC, pic16_popGet (AOP(result), i)); + } + } // for i + goto release; + +#if 0 // add leftover bytes if (SPEC_USIGN(getSpec(operandType(right)))) { // right is unsigned @@ -1052,6 +1096,7 @@ void pic16_genPlus (iCode *ic) } } goto release; +#endif } } @@ -1060,32 +1105,32 @@ void pic16_genPlus (iCode *ic) // TODO: anything from here to before "release:" is probably obsolete and should be removed // when the regression tests are stable - if (AOP_SIZE(IC_RESULT(ic)) > AOP_SIZE(IC_RIGHT(ic))) { - int sign = !(SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))) | - SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))) ); + if (AOP_SIZE(result) > AOP_SIZE(right)) { + int sign = !(SPEC_USIGN(getSpec(operandType(left))) | + SPEC_USIGN(getSpec(operandType(right))) ); /* Need to extend result to higher bytes */ - size = AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_RIGHT(ic)) - 1; + size = AOP_SIZE(result) - AOP_SIZE(right) - 1; /* First grab the carry from the lower bytes */ - pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); - pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offset)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),offset)); if(sign) { /* Now this is really horrid. Gotta check the sign of the addends and propogate * to the result */ - pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_LEFT(ic)),offset-1,FALSE,FALSE),7,0, PO_GPR_REGISTER)); - pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); - pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_RIGHT(ic)),offset-1,FALSE,FALSE),7,0, PO_GPR_REGISTER)); - pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),offset-1,FALSE,FALSE),7,0, PO_GPR_REGISTER)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),offset)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),offset-1,FALSE,FALSE),7,0, PO_GPR_REGISTER)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),offset)); /* if chars or ints or being signed extended to longs: */ if(size) { pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0)); - pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE),7,0, PO_GPR_REGISTER)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(result),offset,FALSE,FALSE),7,0, PO_GPR_REGISTER)); pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0xff)); } } @@ -1094,9 +1139,9 @@ void pic16_genPlus (iCode *ic) while(size--) { if(sign) - pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); else - pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offset)); offset++; } @@ -1106,9 +1151,9 @@ void pic16_genPlus (iCode *ic) //adjustArithmeticResult(ic); release: - pic16_freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); - pic16_freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); - pic16_freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); + pic16_freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + pic16_freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + pic16_freeAsmop(result,NULL,ic,TRUE); } /*-----------------------------------------------------------------*/ @@ -1142,8 +1187,7 @@ bool pic16_genMinusDec (iCode *ic) if(size == 2) { pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),LSB)); - pic16_emitpcode(POC_INCFSZW, pic16_popGet(AOP(IC_RESULT(ic)),LSB)); - pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),MSB16)); + emitSKPC; pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),MSB16)); pic16_emitcode("decf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)); @@ -1151,27 +1195,24 @@ bool pic16_genMinusDec (iCode *ic) pic16_emitcode(" decf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)); } else { /* size is 3 or 4 */ - pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0xff)); - pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_RESULT(ic)),LSB)); - emitSKPNC; - pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_RESULT(ic)),MSB16)); - emitSKPNC; - pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_RESULT(ic)),MSB24)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),LSB)); + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(&pic16_pc_wreg)); + pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),MSB16)); + pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),MSB24)); pic16_emitcode("movlw","0xff"); pic16_emitcode("addwf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)); - emitSKPNC; + //emitSKPNC; pic16_emitcode("addwf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)); - emitSKPNC; + //emitSKPNC; pic16_emitcode("addwf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE)); if(size > 3) { - emitSKPNC; - pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_RESULT(ic)),MSB32)); + pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),MSB32)); pic16_emitcode("skpnc",""); - emitSKPNC; + //emitSKPNC; pic16_emitcode("addwf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),MSB32,FALSE,FALSE)); } @@ -1528,13 +1569,32 @@ void pic16_genMinus (iCode *ic) size--; while(size--){ - if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) { + if (offset < AOP_SIZE(IC_RIGHT(ic))) pic16_mov2w(AOP(IC_RIGHT(ic)),offset); - pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + else { + pic16_emitpcode (POC_CLRF, pic16_popCopyReg (&pic16_pc_wreg)); + if (!SPEC_USIGN(operandType(IC_RIGHT(ic)))) { + // signed -- sign extend the right operand + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_RIGHT(ic)),AOP_SIZE(IC_RIGHT(ic))-1,FALSE,FALSE),7,0, PO_GPR_REGISTER)); + pic16_emitpcode (POC_COMF, pic16_popCopyReg (&pic16_pc_wreg)); + } + } + if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) { + pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),offset)); } else { - pic16_mov2w(AOP(IC_RIGHT(ic)),offset); - pic16_emitpcode(POC_SUBWFB_D0, pic16_popGet(AOP(IC_LEFT(ic)),offset)); - pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + if (offset < AOP_SIZE(IC_LEFT(ic))) { + pic16_emitpcode(POC_SUBWFB_D0, pic16_popGet(AOP(IC_LEFT(ic)),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + } else { + // zero extend the left operand + pic16_emitpcode (POC_CLRF, pic16_popGet(AOP(IC_RESULT(ic)), offset)); + if (!SPEC_USIGN(operandType(IC_LEFT(ic)))) { + // signed -- sign extend the left operand + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_LEFT(ic)),AOP_SIZE(IC_LEFT(ic))-1,FALSE,FALSE),7,0, PO_GPR_REGISTER)); + pic16_emitpcode (POC_COMF, pic16_popGet(AOP(IC_RESULT(ic)), offset)); // keep CARRY/#BORROW bit intact! + } + pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + } } offset++; } diff --git a/src/pic16/glue.c b/src/pic16/glue.c index 7109fd18..7f32b210 100644 --- a/src/pic16/glue.c +++ b/src/pic16/glue.c @@ -70,6 +70,7 @@ extern DEFSETFUNC (rmTmpFiles); extern void pic16_AnalyzeBanking (void); extern void pic16_OptimizeJumps (); +extern void pic16_OptimizeBanksel (); extern void copyFile (FILE * dest, FILE * src); extern void pic16_InlinepCode(void); extern void pic16_writeUsedRegs(FILE *); @@ -1703,6 +1704,11 @@ pic16glue () pic16_OptimizeLocalRegs(); } + /* remove redundant BANKSELs -- added by RN 2005-01-17 */ + if(pic16_options.opt_banksel > 1) { + pic16_OptimizeBanksel(); + } + /* turn GOTOs into BRAs -- added by RN 2004-11-16 */ if(pic16_options.opt_flags & OF_OPTIMIZE_GOTO) { pic16_OptimizeJumps(); diff --git a/src/pic16/graph.c b/src/pic16/graph.c new file mode 100755 index 00000000..4f5ca4f8 --- /dev/null +++ b/src/pic16/graph.c @@ -0,0 +1,180 @@ +/*------------------------------------------------------------------------- + + graph.c - implementation of general graphs + + Written By - Raphael Neider rneider@web.de (2005) + + 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, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +-------------------------------------------------------------------------*/ + +/* $Id$ */ + +#include "graph.h" + +/* === helpers ====================================================== */ + +int default_compare (void *data1, void *data2) +{ + return (data1 == data2); +} + +/* === GraphEdge ==================================================== */ + +GraphEdge *newGEdge (GraphNode *src, GraphNode *dest, unsigned int weight) { + GraphEdge *edge = (GraphEdge *)Safe_calloc (1, sizeof (GraphEdge)); + edge->src = src; + edge->node = dest; + edge->weight = weight; + return edge; +} + +GraphEdge *deleteGEdge (GraphEdge *edge) { + GraphEdge *head; + // remove edge from list + if (edge->next) edge->next->prev = edge->prev; + if (edge->prev) edge->prev->next = edge->next; + + if (edge->prev) head = edge->prev; else head = edge->next; + Safe_free (edge); + return head; +} + +/* === GraphNode ==================================================== */ + +GraphNode *newGNode (void *data, hash_t hash) { + GraphNode *node = (GraphNode*)Safe_calloc (1, sizeof (GraphNode)); + node->data = data; + node->hash = hash; + return node; +} + +GraphNode * deleteGNode (GraphNode *node) { + GraphNode *head; + + if (!node) return NULL; + + // delete all edges + while (node->edge) { + node->edge = deleteGEdge (node->edge); + } // while + + // remove node from list + if (node->next) node->next->prev = node->prev; + if (node->prev) node->prev->next = node->next; + + if (node->prev) head = node->prev; else head = node->next; + Safe_free (node); + return head; +} + +GraphEdge *addGEdge (GraphNode *from, GraphNode *to, unsigned int weight) { + GraphEdge *edge = getGEdge (from, to); + if (edge == NULL) { + edge = newGEdge (from, to, weight); + // insert edge into list + if (from->edge) from->edge->prev = edge; + edge->next = from->edge; + from->edge = edge; + } else + edge->weight += weight; + + assert (edge->src == from && edge->node == to); + return edge; +} + +void addGEdge2 (GraphNode *from, GraphNode *to, unsigned int weight, unsigned int weight_back) { + addGEdge (from, to, weight); + addGEdge (to, from, weight_back); +} + +void remGEdge (GraphNode *from, GraphNode *to) { + GraphEdge *curr = from->edge; + while (curr && curr->node != to) curr = curr->next; + + if (!curr) return; + + if (from->edge == curr) + from->edge = deleteGEdge (curr); + else + deleteGEdge (curr); +} + +GraphEdge *getGEdge (GraphNode *from, GraphNode *to) { + GraphEdge *curr = from->edge; + while (curr && curr->node != to) { + assert (curr->src == from); + curr = curr->next; + } + return curr; +} + +/* === Graph ======================================================== */ + +Graph *newGraph (Graph_compareData *compare) { + Graph *graph = (Graph*) Safe_calloc (1, sizeof (Graph)); + graph->compare = compare; + if (!compare) graph->compare = default_compare; + + return graph; +} + +void deleteGraph (Graph *graph) { + // remove all nodes + while (graph->node) { + graph->node = deleteGNode (graph->node); + } // while + + Safe_free (graph); +} + +GraphNode *addGNode (Graph *graph, void *data, hash_t hash) { + GraphNode *node = newGNode (data, hash); + if (graph->node) graph->node->prev = node; + node->next = graph->node; + graph->node = node; + return node; +} + +void remGNode (Graph *graph, void *data, hash_t hash) { + GraphNode *curr = graph->node; + while (curr && ((curr->hash != hash) || (!graph->compare(curr->data, data)))) { + curr = curr->next; + } // while + + if (!curr) return; + + if (graph->node == curr) + graph->node = deleteGNode (curr); + else + deleteGNode (curr); +} + +GraphNode *getGNode (Graph *graph, void *data, hash_t hash) { + GraphNode *curr = graph->node; + while (curr && ((curr->hash != hash) || (!graph->compare(curr->data, data)))) { + curr = curr->next; + } // while + + return curr; +} + +GraphNode *getOrAddGNode (Graph *graph, void *data, hash_t hash) { + GraphNode *curr = getGNode (graph, data, hash); + if (!curr) + curr = addGNode (graph, data, hash); + + assert (curr != NULL); + return curr; +} diff --git a/src/pic16/graph.h b/src/pic16/graph.h new file mode 100755 index 00000000..527ddbd3 --- /dev/null +++ b/src/pic16/graph.h @@ -0,0 +1,113 @@ +/*------------------------------------------------------------------------- + + graph.h - header file for graph.c + + Written By - Raphael Neider rneider@web.de (2005) + + 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, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +-------------------------------------------------------------------------*/ + +/* $Id$ */ + +#ifndef __GRAPH_H__ +#define __GRAPH_H__ + +#include "../common.h" + +typedef unsigned int hash_t; + +struct GraphNode; + +typedef struct GraphEdge { + struct GraphNode *src; // starting node of this edge + struct GraphNode *node; // other end of this edge + unsigned int weight; // weight assigned to this edge + struct GraphEdge *prev; // link to previous edge + struct GraphEdge *next; // link to next edge +} GraphEdge; + +typedef struct GraphNode { + void *data; // data stored in this node + hash_t hash; // hash value for "data" + + GraphEdge *edge; // first edge leaving this node + struct GraphNode *prev; // link to previous node + struct GraphNode *next; // link to next edge +} GraphNode; + +// compare function, returns 0 for different items and 1 for equal items +typedef int Graph_compareData(void *item1, void *item2); + +typedef struct { + GraphNode *node; // first node in this graph + Graph_compareData *compare; // function used to compare two data items +} Graph; + +/* Create a new edge from src to dest. + * Returns a pointer to the new edge. */ +GraphEdge *newGEdge (GraphNode *src, GraphNode *dest, unsigned int weight); + +/* Delete an edge and remove it from the containing list. + * Returns a pointer to the previous edge or (if there is NULL) to its successor. */ +GraphEdge *deleteGEdge (GraphEdge *edge); + + + +/* Create a new node. */ +GraphNode *newGNode (void *data, hash_t hash); + +/* Delete a node and all its edges. this also removes the node + * from its containing list. + * Returns the previous node in the list or (if there is NULL) + * its successor. */ +GraphNode *deleteGNode (GraphNode *node); + +/* Adds an edge with the given weight. If the edge already exists, + * its weight its increased instead! */ +GraphEdge *addGEdge (GraphNode *from, GraphNode *to, unsigned int weight); + +/* Adds the edges (from,to) and (to,from) with the specified weights. */ +void addGEdge2 (GraphNode *from, GraphNode *to, unsigned int weight, unsigned int weight_back); + +/* Remove an edge from the node. This deletes the edge and updates the + * list of edges attached to the "from" node. */ +void remGEdge (GraphNode *from, GraphNode *to); + +/* Returns the edge (from,to) or NULL if no such edge exists. */ +GraphEdge *getGEdge (GraphNode *from, GraphNode *to); + + + +/* Create a new graph which uses the given compare function to test + * its nodes' data for equality. */ +Graph *newGraph (Graph_compareData *compare); + +/* Delete a graph, all its contained nodes and their edges. */ +void deleteGraph (Graph *graph); + +/* Add a node to the graph. */ +GraphNode *addGNode (Graph *graph, void *data, hash_t hash); + +/* Remove a node from the graph. This also deletes the node and all + * its associated (outbound) edges. */ +void remGNode (Graph *graph, void *data, hash_t hash); + +/* Returns the specified node or NULL if no such node exists. */ +GraphNode *getGNode (Graph *graph, void *data, hash_t hash); + +/* Returns the specified node (after creating it if neccessary). */ +GraphNode *getOrAddGNode (Graph *graph, void *data, hash_t hash); + +#endif diff --git a/src/pic16/pcode.c b/src/pic16/pcode.c index ab167c78..7d04d89d 100644 --- a/src/pic16/pcode.c +++ b/src/pic16/pcode.c @@ -8532,3 +8532,663 @@ char *dumpPicOptype(PIC_OPTYPE type) { return (pic_optype_names[ type ]); } + + +/*** BEGIN of stuff belonging to the BANKSEL optimization ***/ +#include "graph.h" + +#define MAX_COMMON_BANK_SIZE 32 +#define FIRST_PSEUDO_BANK_NR 1000 + +hTab *sym2bank = NULL; // --> +hTab *bank2sym = NULL; // --> +hTab *coerce = NULL; // --> <&PSEUDOBANK> +Graph *adj = NULL; + +typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr; + +typedef struct { + pseudoBankNr bank; // number assigned to this pseudoBank + unsigned int size; // number of operands assigned to this bank + unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection) +} pseudoBank; + +/*----------------------------------------------------------------------*/ +/* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */ +/*----------------------------------------------------------------------*/ +unsigned int hashSymbol (const char *str) +{ + unsigned int res = 0; + if (!str) return 0; + + while (*str) { + res ^= (*str); + res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4)); + str++; + } // while + + return res; +} + +/*-----------------------------------------------------------------------*/ +/* compareSymbol - return 1 iff sym1 equals sym2 */ +/*-----------------------------------------------------------------------*/ +int compareSymbol (const void *sym1, const void *sym2) +{ + char *s1 = (char*) sym1; + char *s2 = (char*) sym2; + + return (strcmp (s1,s2) == 0); +} + +/*-----------------------------------------------------------------------*/ +/* comparePre - return 1 iff p1 == p2 */ +/*-----------------------------------------------------------------------*/ +int comparePtr (const void *p1, const void *p2) +{ + return (p1 == p2); +} + +/*----------------------------------------------------------*/ +/* getSymbolFromOperand - return a pointer to the symbol in */ +/* the given operand and its length */ +/*----------------------------------------------------------*/ +char *getSymbolFromOperand (char *op, unsigned int *len) +{ + char *sym, *curr; + *len = 0; + + if (!op) return NULL; + + // we recognize two forms of operands: SYMBOL and (SYMBOL + offset) + sym = op; + if (*sym == '(') sym++; + + curr = sym; + while (((*curr >= 'A') && (*curr <= 'Z')) + || ((*curr >= 'a') && (*curr <= 'z')) + || ((curr != sym) && (*curr >= '0') && (*curr <= '9')) + || (*curr == '_')) { + // find end of symbol [A-Za-z_]?[A-Za-z0-9]* + curr++; + (*len)++; + } // while + + return sym; +} + +/*--------------------------------------------------------------------------*/ +/* getSymFromBank - get (one) name of a symbol assigned to the given bank */ +/*--------------------------------------------------------------------------*/ +char *getSymFromBank (pseudoBankNr bank) +{ + assert (bank2sym); + + if (bank < 0) return ""; + return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr); +} + +/*-----------------------------------------------------------------------*/ +/* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */ +/* bank number (uses hTab sym2bank), if the */ +/* symbol is not yet assigned a pseudo bank it */ +/* is assigned one here */ +/*-----------------------------------------------------------------------*/ +pseudoBankNr getPseudoBankNrFromOperand (const char *op) +{ + static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR; + pseudoBankNr bank; + unsigned int hash; + + assert (sym2bank); + + hash = hashSymbol (op) % sym2bank->size; + bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol); + if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK; + + if (bank == UNKNOWN_BANK) { + // create a pseudo bank for the operand + bank = next_bank++; + hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank); + hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op); + getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet + //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank); + } else { + //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank); + } // if + + assert (bank >= 0); + + return bank; +} + +/*--------------------------------------------------------------------*/ +/* isBanksel - check whether the given pCode is a BANKSEL instruction */ +/*--------------------------------------------------------------------*/ +int isBanksel (pCode *pc) +{ + if (!pc) return 0; + + if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) { + // BANKSEL or MOVLB + //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg); + return 1; + } + + // check for inline assembler BANKSELs + if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 || + STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) { + //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg); + return 1; + } + + // assume pc is no BANKSEL instruction + return 0; +} + +/*---------------------------------------------------------------------------------*/ +/* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */ +/* This method can not guarantee to find all modifications of the */ +/* BSR (e.g. via INDirection registers) but covers all compiler */ +/* generated plus some cases. */ +/*---------------------------------------------------------------------------------*/ +int invalidatesBSR(pCode *pc) +{ + // assembler directives invalidate BSR (well, they might, we don't know) + if (isPCAD(pc)) return 1; + + // only ASMDIRs and pCodeInstructions can invalidate BSR + if (!isPCI(pc)) return 0; + + // we have a pCodeInstruction + + // check for BSR modifying instructions + switch (PCI(pc)->op) { + case POC_CALL: + case POC_RCALL: + case POC_MOVLB: + case POC_RETFIE: // might be used as CALL replacement + case POC_RETLW: // might be used as CALL replacement + case POC_RETURN: // might be used as CALL replacement + case POC_BANKSEL: + return 1; + break; + + default: // other instruction do not change BSR unless BSR is an explicit operand! + // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...! + break; + } // switch + + // no change of BSR possible/probable + return 0; +} + +/*------------------------------------------------------------*/ +/* getBankFromBanksel - return the pseudo bank nr assigned to */ +/* the symbol referenced in this BANKSEL */ +/*------------------------------------------------------------*/ +pseudoBankNr getBankFromBanksel (pCode *pc) +{ + char *sym; + int data = (int)NULL; + + if (!pc) return INVALID_BANK; + + if (isPCAD(pc) && PCAD(pc)->directive) { + if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) { + // get symbolname from PCAD(pc)->arg + //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg); + sym = PCAD(pc)->arg; + data = getPseudoBankNrFromOperand (sym); + //fprintf (stderr, "symbol: %s, data=%i\n", sym, data); + } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) { + // get (literal) bank number from PCAD(pc)->arg + fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg); + assert (0 && "not yet implemented - turn off banksel optimization for now"); + } + } else if (isPCI(pc)) { + if (PCI(pc)->op == POC_BANKSEL) { + // get symbolname from PCI(pc)->pcop->name (?) + //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name); + sym = PCI(pc)->pcop->name; + data = getPseudoBankNrFromOperand (sym); + //fprintf (stderr, "symbol: %s, data=%i\n", sym, data); + } else if (PCI(pc)->op == POC_MOVLB) { + // get (literal) bank number from PCI(pc)->pcop->name + fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name); + assert (0 && "not yet implemented - turn off banksel optimization for now"); + } + } + + if (data == 0) + // no assigned bank could be found + return UNKNOWN_BANK; + else + return data; +} + +/*------------------------------------------------------------------------------*/ +/* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */ +/*------------------------------------------------------------------------------*/ +pseudoBankNr getEffectiveBank (pseudoBankNr bank) +{ + pseudoBank *data; + + if (bank < FIRST_PSEUDO_BANK_NR) return bank; + + do { + //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank); + data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr); + if (data) { + if (data->bank != bank) + bank = data->bank; + else + data = NULL; + } + } while (data); + + //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank); + return bank; +} + +/*------------------------------------------------------------------*/ +/* attachBsrInfo2pBlock - create a look-up table as to which pseudo */ +/* bank is selected at a given pCode */ +/*------------------------------------------------------------------*/ + +/* Create a graph with pseudo banks as its nodes and switches between + * these as edges (with the edge weight representing the absolute + * number of BANKSELs from one to the other). + * Removes redundand BANKSELs instead iff mod == 1. + * BANKSELs update the pseudo BSR, labels invalidate the current BSR + * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the + * pseudo BSR. + * TODO: check ALL instructions operands if they modify BSR directly... + * + * pb - the pBlock to annotate + * mod - select either graph creation (0) or BANKSEL removal (1) + */ +unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod) +{ + pCode *pc, *pc_next; + unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK; + int isBankselect = 0; + unsigned int banksels=0; + + if (!pb) return 0; + + pc = pic16_findNextInstruction(pb->pcHead); + while (pc) { + isBankselect = isBanksel (pc); + pc_next = pic16_findNextInstruction (pc->next); + + if (!hasNoLabel (pc)) { + // we don't know our predecessors -- assume different BSRs + prevBSR = UNKNOWN_BANK; + pseudoBSR = UNKNOWN_BANK; + //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc); + } // if + + // check if this is a BANKSEL instruction + if (isBankselect) { + pseudoBSR = getEffectiveBank (getBankFromBanksel(pc)); + //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc); + if (mod) { + if (prevBSR == pseudoBSR && pseudoBSR >= 0) { + //fprintf (stderr, "removing redundant "); pc->print (stderr, pc); + if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL")); + pic16_unlinkpCode (pc); + banksels++; + } + } else { + addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0); + banksels++; + } + } // if + + if (!isBankselect && invalidatesBSR(pc)) { + // check if this instruction invalidates the pseudoBSR + pseudoBSR = UNKNOWN_BANK; + //fprintf (stderr, "invalidated via "); pc->print (stderr, pc); + } // if + + prevBSR = pseudoBSR; + pc = pc_next; + } // while + + return banksels; +} + +/*------------------------------------------------------------------------------------*/ +/* assignToSameBank - returns 0 on success or an error code */ +/* 1 - common bank would be too large */ +/* 2 - assignment to fixed (absolute) bank not performed */ +/* */ +/* This functions assumes that unsplittable operands are already assigned to the same */ +/* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */ +/* bank so that we can make sure the bytes are laid out sequentially in memory) */ +/* TODO: Symbols with an abslute address must be handled specially! */ +/*------------------------------------------------------------------------------------*/ +int assignToSameBank (int bank0, int bank1, int doAbs) +{ + int eff0, eff1, dummy; + pseudoBank *pbank0, *pbank1; + hashtItem *hitem; + + eff0 = getEffectiveBank (bank0); + eff1 = getEffectiveBank (bank1); + + //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs); + + // nothing to do if already same bank + if (eff0 == eff1) return 0; + + if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR)) + return 2; + + // ensure eff0 < eff1 + if (eff0 > eff1) { + // swap eff0 and eff1 + dummy = eff0; + eff0 = eff1; + eff1 = dummy; + dummy = bank0; + bank0 = bank1; + bank1 = dummy; + } // if + + // now assign bank eff1 to bank eff0 + pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *) eff0, &comparePtr); + if (!pbank0) { + pbank0 = Safe_calloc (1, sizeof (pseudoBank)); + pbank0->bank = eff0; + pbank0->size = 1; + pbank0->ref = 1; + hTabAddItemLong (&coerce, eff0 % coerce->size, (void *) eff0, (void *) pbank0); + } // if + + pbank1 = NULL; + hitem = hTabSearch (coerce, eff1 % coerce->size); + while (hitem && hitem->pkey != (void *)eff1) + hitem = hitem->next; + + if (hitem) pbank1 = (pseudoBank *) hitem->item; + +#if 0 + fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1, + pbank0->bank, pbank0->size, + getSymFromBank (eff0), getSymFromBank (eff1)); +#endif + + if (pbank1) { + if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) { +#if 0 + fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n", + pbank0->bank, pbank0->size, pbank1->bank, pbank1->size, + pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE, + getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank)); +#endif + return 1; + } // if + pbank0->size += pbank1->size; + pbank1->ref--; + if (pbank1->ref == 0) Safe_free (pbank1); + } else { + pbank0->size++; + } // if + + if (hitem) + hitem->item = pbank0; + else + hTabAddItemLong (&coerce, eff1 % coerce->size, (void *) eff1, (void *) pbank0); + pbank0->ref++; + + //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__); + + return 0; +} + +/*----------------------------------------------------------------*/ +/* mergeGraphNodes - combines two nodes into one and modifies all */ +/* edges to and from the nodes accordingly */ +/* This method needs complete backedges, i.e. if (A,B) is an edge */ +/* then also (B,A) must be an edge (possibly with weight 0). */ +/*----------------------------------------------------------------*/ +void mergeGraphNodes (GraphNode *node1, GraphNode *node2) +{ + GraphEdge *edge, *backedge, *nextedge; + GraphNode *node; + int backweight; + + assert (node1 && node2); + assert (node1 != node2); + + // add all edges starting at node2 to node1 + edge = node2->edge; + while (edge) { + nextedge = edge->next; + node = edge->node; + backedge = getGEdge (node, node2); + if (backedge) + backweight = backedge->weight; + else + backweight = 0; + // insert edges (node1,node) and (node,node1) + addGEdge2 (node1, node, edge->weight, backweight); + // remove edges (node, node2) and (node2, node) + remGEdge (node2, node); + remGEdge (node, node2); + edge = nextedge; + } // while + + // now node2 should not be referenced by any other GraphNode... + //remGNode (adj, node2->data, node2->hash); +} + +/*----------------------------------------------------------------*/ +/* showGraph - dump the current BANKSEL graph as a node/edge list */ +/*----------------------------------------------------------------*/ +void showGraph (Graph *g) +{ + GraphNode *node; + GraphEdge *edge; + pseudoBankNr bankNr; + pseudoBank *pbank; + unsigned int size; + + node = g->node; + while (node) { + edge = node->edge; + bankNr = getEffectiveBank (node->hash); + assert (bankNr >= 0); + pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr); + if (pbank) { + bankNr = pbank->bank; + size = pbank->size; + } else { + size = 1; + } + + fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size); + + while (edge) { + if (edge->weight > 0) + fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash)); + edge = edge->next; + } // while (edge) + node = node->next; + } // while (node) +} + +/*---------------------------------------------------------------*/ +/* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */ +/*---------------------------------------------------------------*/ +void pic16_OptimizeBanksel () +{ + GraphNode *node, *node1, *node1next; + +#if 0 + // needed for more effective bank assignment (needs adjusted pic16_emit_usection()) + GraphEdge *edge, *backedge; + GraphEdge *max; + int maxWeight, weight, mergeMore, absMaxWeight; + pseudoBankNr curr0, curr1; +#endif + pseudoBank *pbank; + pseudoBankNr bankNr; + char *base_symbol0, *base_symbol1; + int len0, len1; + pBlock *pb; + set *set; + regs *reg; + unsigned int bankselsTotal = 0, bankselsRemoved = 0; + + //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__); + + if (!the_pFile || !the_pFile->pbHead) return; + + adj = newGraph (NULL); + sym2bank = newHashTable ( 255 ); + bank2sym = newHashTable ( 255 ); + coerce = newHashTable ( 255 ); + + // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A) + for (pb = the_pFile->pbHead; pb; pb = pb->next) { + bankselsTotal += attachBsrInfo2pBlock (pb, 0); + } // for pb + +#if 1 + // assign symbols with absolute addresses to their respective bank nrs + set = pic16_fix_udata; + for (reg = setFirstItem (set); reg; reg = setNextItem (set)) { + bankNr = reg->address >> 8; + node = getOrAddGNode (adj, NULL, bankNr); + bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name)); + assignToSameBank (node->hash, bankNr, 1); + + assert (bankNr >= 0); + pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr); + if (!pbank) { + pbank = Safe_calloc (1, sizeof (pseudoBank)); + pbank->bank = reg->address >> 8; //FIXED_BANK; + pbank->size = 1; + pbank->ref = 1; + hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank); + } else { + assert (pbank->bank == (reg->address >> 8)); + pbank->bank = reg->address >> 8; //FIXED_BANK; + } + //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr); + } // for reg +#endif + +#if 1 + // assign operands referring to the same symbol (which is not given an absolute address) to the same bank + //fprintf (stderr, "assign operands with the same symbol to the same bank\n"); + node = adj->node; + while (node) { + if (node->hash < 0) { node = node->next; continue; } + base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0); + node1 = node->next; + while (node1) { + if (node1->hash < 0) { node1 = node1->next; continue; } + node1next = node1->next; + base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1); + if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) { + // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries! + //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash))); + if (assignToSameBank (node->hash, node1->hash, 0)) { + fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1); + assert (0 && "Could not assign a symbol to a bank!"); + } + mergeGraphNodes (node, node1); + /* + if (node->hash < node1->hash) + mergeGraphNodes (node, node1); + else + mergeGraphNodes (node1, node); // this removes node so node->next will fail... + */ + } // if + node1 = node1next; + } // while (node1) + node = node->next; + } // while (node) +#endif + +#if 0 + // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<< + // assign tightly coupled operands to the same (pseudo) bank + //fprintf (stderr, "assign tightly coupled operands to the same bank\n"); + mergeMore = 1; + absMaxWeight = 0; + while (mergeMore) { + node = adj->node; + max = NULL; + maxWeight = 0; + while (node) { + curr0 = getEffectiveBank (node->hash); + if (curr0 < 0) { node = node->next; continue; } + edge = node->edge; + while (edge) { + assert (edge->src == node); + backedge = getGEdge (edge->node, edge->src); + weight = edge->weight + (backedge ? backedge->weight : 0); + curr1 = getEffectiveBank (edge->node->hash); + if (curr1 < 0) { edge = edge->next; continue; } + + // merging is only useful if the items are not assigned to the same bank already... + if (curr0 != curr1 && weight > maxWeight) { + if (maxWeight > absMaxWeight) absMaxWeight = maxWeight; + maxWeight = weight; + max = edge; + } // if + edge = edge->next; + } // while + node = node->next; + } // while + + if (maxWeight > 0) { +#if 1 + fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight, + max->src->hash, getSymFromBank (max->src->hash), + max->node->hash, getSymFromBank (max->node->hash)); +#endif + + node = getGNode (adj, max->src->data, max->src->hash); + node1 = getGNode (adj, max->node->data, max->node->hash); + + if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) { + if (max->src->hash < max->node->hash) + mergeGraphNodes (node, node1); + else + mergeGraphNodes (node1, node); + } else { + remGEdge (node, node1); + remGEdge (node1, node); + //mergeMore = 0; + } + + } else { + mergeMore = 0; + } + } // while +#endif + +#if 1 + // remove redundant BANKSELs + //fprintf (stderr, "removing redundant BANKSELs\n"); + for (pb = the_pFile->pbHead; pb; pb = pb->next) { + bankselsRemoved += attachBsrInfo2pBlock (pb, 1); + } // for pb +#endif + +#if 0 + fprintf (stderr, "display graph\n"); + showGraph (); +#endif + + deleteGraph (adj); + fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal); +} + +/*** END of stuff belonging to the BANKSEL optimization ***/ diff --git a/src/pic16/pcoderegs.c b/src/pic16/pcoderegs.c index df21a9a0..ad18f83e 100644 --- a/src/pic16/pcoderegs.c +++ b/src/pic16/pcoderegs.c @@ -167,7 +167,7 @@ static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl) reg = pic16_getRegFromInstruction(pc); - if(reg) { + if(reg && (reg->type != REG_TMP)) { #if 0 fprintf(stderr, "reg= %p\n", reg); fprintf(stderr, "flow seq %d, inst seq %d %s ",PCODE(pcfl)->seq,pc->seq,reg->name); diff --git a/src/pic16/peeph.def b/src/pic16/peeph.def index 511e2efb..9819a946 100644 --- a/src/pic16/peeph.def +++ b/src/pic16/peeph.def @@ -285,3 +285,11 @@ replace restart { movf %1,w } +replace restart { + movf %1,w + movf %2,w +} by { + ; peep 12 - Removed redundant move + movf %2,w +} + -- 2.47.2