+2007-01-31 Raphael Neider <rneider AT web.de>
+
+ * src/pic/pcode.c (isValidIdChar,bankCompare): fuzzy matching of
+ operand names, handles name and (name + n) for all n,
+ (sameBank): restructured, also check bank allocation policy,
+ * src/pic/glue.c (emitPseudoStack): fixed printf arguments,
+ (pic14_operandsAllocatedInSameBank): check whether to operands
+ will be allocated into the same bank (i.e., section) to reduce
+ BANKSEL overhead, queried from pcode.c:sameBank,
+ (pic14printLocals): reintroduced clustering registers into a single
+ section: all compiler generated symbols will now reside in one
+ bank (per file), reducing BANKSEL overhead and code size,
+ (showAllMemmaps): use local dbuf where possible
+
2007-01-29 Raphael Neider <rneider AT web.de>
* src/pic/gen.c (popGetExternal): simplified, mark symbol as used,
of string literals (still incomplete),
(picglue): removed symbol emission, moved into showAllMemmaps,
(emitSymbolSet): new workhorse for symbol output,
- (pic14emitMaps,pic14printPublics,pic14printExterns): commented out,
+ (pic14emitMaps,pic14printPublics,pic14printExterns): commented out
2007-01-29 Borut Razem <borut.razem AT siol.net>
/* dbufs for initialized data (idata and code sections),
* extern, and global declarations */
-struct dbuf_s *ivalBuf, *ivalCodeBuf, *extBuf, *gloBuf, *gloDefBuf, *locBuf;
+struct dbuf_s *ivalBuf, *extBuf, *gloBuf, *gloDefBuf;
static set *emitted = NULL;
int pic14_stringInSet(const char *str, set **world, int autoAdd);
for (i = size - 4; i >= 0; i--) {
dbuf_printf (oBuf, "\tglobal STK%02d\n", i);
} // for i
- dbuf_printf (oBuf, "\n", i);
+ dbuf_printf (oBuf, "\n");
// 16f84 has no SHAREBANK (in linkerscript) but memory aliased in two
// banks, sigh...
pic14_stringInSet(&buffer[0], &emitted, 1);
} // for i
}
- dbuf_printf (oBuf, "\n", i);
+ dbuf_printf (oBuf, "\n");
}
static int
}
#endif
+/*
+ * Interface to BANKSEL generation.
+ * This function should return != 0 iff str1 and str2 denote operands that
+ * are known to be allocated into the same bank. Consequently, there will
+ * be no BANKSEL emitted if str2 is accessed while str1 has been used to
+ * select the current bank just previously.
+ *
+ * If in doubt, return 0.
+ */
+int
+pic14_operandsAllocatedInSameBank(const char *str1, const char *str2) {
+ // see pic14printLocals
+
+ if (getenv("SDCC_PIC14_SPLIT_LOCALS")) {
+ // no clustering applied, each register resides in its own bank
+ } else {
+ // check whether BOTH names are local registers
+ // XXX: This is some kind of shortcut, should be safe...
+ // In this model, all r0xXXXX are allocated into a single section
+ // per file, so no BANKSEL required if accessing a r0xXXXX after a
+ // (different) r0xXXXX. Works great for multi-byte operands.
+ if (str1 && str2 && str1[0] == 'r' && str2[0] == 'r') return (1);
+ } // if
+
+ // assume operands in different banks
+ return (0);
+}
+
static void
pic14printLocals (struct dbuf_s *oBuf)
{
set *allregs[6] = { dynAllocRegs/*, dynStackRegs, dynProcessorRegs*/,
dynDirectRegs, dynDirectBitRegs/*, dynInternalRegs */ };
regs *reg;
- int i;
+ int i, is_first = 1;
static unsigned sectionNr = 0;
/* emit all registers from all possible sets */
if (!pic14_stringInSet(reg->name, &emitted, 1)) {
if (reg->isFixed) {
// Should not happen, really...
+ assert ( !"Compiler-assigned variables should not be pinned... This is a bug." );
dbuf_printf(oBuf, "UDL_%s_%u\tudata\t0x%04X\n%s\tres\t%d\n",
moduleName, sectionNr++, reg->address, reg->name, reg->size);
} else {
- dbuf_printf(oBuf, "UDL_%s_%u\tudata\n%s\tres\t%d\n",
- moduleName, sectionNr++, reg->name, reg->size);
+ if (getenv("SDCC_PIC14_SPLIT_LOCALS")) {
+ // assign each local register into its own section
+ dbuf_printf(oBuf, "UDL_%s_%u\tudata\n%s\tres\t%d\n",
+ moduleName, sectionNr++, reg->name, reg->size);
+ } else {
+ // group all local registers into a single section
+ // This should greatly improve BANKSEL generation...
+ if (is_first) {
+ dbuf_printf(oBuf, "UDL_%s_%u\tudata\n", moduleName, sectionNr++);
+ is_first = 0;
+ }
+ dbuf_printf(oBuf, "%s\tres\t%d\n", reg->name, reg->size);
+ }
}
}
}
static void
showAllMemmaps(FILE *of)
{
+ struct dbuf_s locBuf;
memmap *maps[] = {
xstack, istack, code, data, pdata, xdata, xidata, xinit,
idata, bit, statsg, c_abs, x_abs, i_abs, d_abs,
if (!gloBuf) gloBuf = dbuf_new(1024);
if (!gloDefBuf) gloDefBuf = dbuf_new(1024);
if (!ivalBuf) ivalBuf = dbuf_new(1024);
- if (!locBuf) locBuf = dbuf_new(1024);
+ dbuf_init(&locBuf, 1024);
dbuf_printf (extBuf, "%s; external declarations\n%s", iComments2, iComments2);
dbuf_printf (gloBuf, "%s; global declarations\n%s", iComments2, iComments2);
dbuf_printf (gloDefBuf, "%s; global definitions\n%s", iComments2, iComments2);
dbuf_printf (ivalBuf, "%s; initialized data\n%s", iComments2, iComments2);
- dbuf_printf (locBuf, "%s; compiler-defined variables\n%s", iComments2, iComments2);
+ dbuf_printf (&locBuf, "%s; compiler-defined variables\n%s", iComments2, iComments2);
for (i = 0; i < sizeof(maps) / sizeof (memmap *); i++) {
map = maps[i];
emitPseudoStack(gloBuf, extBuf);
pic14_constructAbsMap(gloDefBuf, gloBuf);
- pic14printLocals (locBuf);
+ pic14printLocals (&locBuf);
dbuf_write_and_destroy(extBuf, of);
dbuf_write_and_destroy(gloBuf, of);
dbuf_write_and_destroy(gloDefBuf, of);
- dbuf_write_and_destroy(locBuf, of);
+ dbuf_write_and_destroy(&locBuf, of);
dbuf_write_and_destroy(ivalBuf, of);
- extBuf = gloBuf = gloDefBuf = locBuf = ivalBuf = NULL;
+ extBuf = gloBuf = gloDefBuf = ivalBuf = NULL;
}
insertPCodeInstruction(pci, PCI(new_pc));
}
+/*
+ * isValidIdChar - check if c may be present in an identifier
+ */
+static int isValidIdChar (char c)
+{
+ if (c >= 'a' && c <= 'z') return 1;
+ if (c >= 'A' && c <= 'Z') return 1;
+ if (c >= '0' && c <= '9') return 1;
+ if (c == '_') return 1;
+ return 0;
+}
+
+/*
+ * bankcompare - check if two operand string refer to the same register
+ * This functions handles NAME and (NAME + x) in both operands.
+ * Returns 1 on same register, 0 on different (or unknown) registers.
+ */
+static int bankCompare(const char *op1, const char *op2)
+{
+ int i;
+
+ if (!op1 && !op2) return 0; // both unknown, might be different though!
+ if (!op1 || !op2) return 0;
+
+ // find start of operand name
+ while (op1[0] == '(' || op1[0] == ' ') op1++;
+ while (op2[0] == '(' || op2[0] == ' ') op2++;
+
+ // compare till first non-identifier character
+ for (i = 0; (op1[i] == op2[i]) && isValidIdChar(op1[i]); i++);
+ if (!isValidIdChar(op1[i]) && !isValidIdChar(op2[i])) return 1;
+
+ // play safe---assume different operands
+ return 0;
+}
+
/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
+extern int pic14_operandsAllocatedInSameBank(const char *str1, const char *str2);
static int sameBank(regs *reg, regs *previous_reg, const char *new_bank, const char *cur_bank, unsigned max_mask)
{
if (!cur_bank) return 0;
- // identify '(regname + X)' and 'regname'
- if (reg && reg->name && reg->name[0] == '(' && !strncmp(®->name[1], cur_bank, strlen(cur_bank))) return 1;
- if (new_bank && new_bank[0] == '(' && !strncmp(&new_bank[1], cur_bank, strlen(cur_bank))) return 1;
- if (cur_bank[0] == '(' && reg && reg->name && !strncmp(reg->name, &cur_bank[1], strlen(reg->name))) return 1;
- if (cur_bank[0] == '(' && new_bank && !strncmp(new_bank, &cur_bank[1], strlen(new_bank))) return 1;
-
if (previous_reg && reg && previous_reg->isFixed && reg->isFixed && ((previous_reg->address & max_mask) == (reg->address & max_mask))) // only if exists
return 1; // if we have address info, we use it for banksel optimization
- // XXX: identify '(regname + X)' and '(regname + Y)'
-
- return ((reg && reg->name && !strcmp(reg->name, cur_bank)) || (new_bank && !strcmp(new_bank, cur_bank)));
+ // regard '(regname + X)' and '(regname + Y)' as equal
+ if (reg && reg->name && bankCompare(reg->name, cur_bank)) return 1;
+ if (new_bank && bankCompare(new_bank, cur_bank)) return 1;
+
+ // check allocation policy from glue.c
+ if (reg && reg->name && pic14_operandsAllocatedInSameBank(reg->name, cur_bank)) return 1;
+ if (new_bank && pic14_operandsAllocatedInSameBank(new_bank, cur_bank)) return 1;
+
+ // seems to be a different operand--might be a different bank
+ //printf ("BANKSEL from %s to %s/%s\n", cur_bank, reg->name, new_bank);
+ return 0;
}
/*-----------------------------------------------------------------*/