+2005-01-19 Raphael Neider <rneider AT web.de>
+
+ * 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 <vrokas AT otenet.gr>
* device/lib/pic16/libc/stdlib/x_ftoa.c: it defines x_ftoa function
2005-01-08 Raphael Neider <rneider AT web.de>
- * 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 <rneider AT web.de>
- * 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 <rneider AT web.de>
- * 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 <vrokas AT otenet.gr>
#define ZERO 0
#include <limits.h> /* 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
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)
{
int size, i;
sym_link *optype, *rtype;
+ symbol *label;
+ int needLabel=0;
FENTRY;
/* otherwise subtract from zero by taking the 2's complement */
size = AOP_SIZE(IC_LEFT(ic));
-
- for(i=0; i<size; i++) {
- if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
- pic16_emitpcode(POC_COMF, pic16_popGet(AOP(IC_LEFT(ic)),i));
- else {
- pic16_emitpcode(POC_COMFW, pic16_popGet(AOP(IC_LEFT(ic)),i));
- pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),i));
- }
- }
-
- pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),0));
- for(i=1; i<size; i++) {
- emitSKPNZ;
- pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),i));
+ label = newiTempLabel ( NULL );
+
+ if (pic16_sameRegs (AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
+ for (i=size-1; 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 */
/* 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__);
/* 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__);
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:
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 */
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;
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));
}
}
}
} 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));
}
}
}
}
+ // 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
}
}
goto release;
+#endif
}
}
// 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));
}
}
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++;
}
//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);
}
/*-----------------------------------------------------------------*/
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));
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));
}
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++;
}
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 *);
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();
--- /dev/null
+/*-------------------------------------------------------------------------
+
+ 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;
+}
--- /dev/null
+/*-------------------------------------------------------------------------
+
+ 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
{
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; // <OPERAND NAME> --> <PSEUDO BANK NR>
+hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
+hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&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 "<INVALID BANK NR>";
+ 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 <variablename> or MOVLB <banknr>
+ //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 ***/
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);
movf %1,w
}
+replace restart {
+ movf %1,w
+ movf %2,w
+} by {
+ ; peep 12 - Removed redundant move
+ movf %2,w
+}
+