static void FixRegisterBanking(pBlock *pb);
-#if defined(__BORLANDC__) || defined(_MSC_VER)
-#define STRCASECMP stricmp
-#else
-#define STRCASECMP strcasecmp
-#endif
-
/****************************************************************/
/****************************************************************/
void addpCode2pBlock(pBlock *pb, pCode *pc)
{
- if(!pc)
+ if(!pb || !pc)
return;
if(!pb->pcHead) {
//fprintf(stderr,"linkflow \n");
+ if (!pb) return;
+
for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
pcflow != NULL;
pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
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;
+}
+
/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
-static int sameBank(regs *reg, const char *new_bank, const char *cur_bank)
+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;
-
- // XXX: identify '(regname + X)' and '(regname + Y)'
-
- return ((reg && reg->name && !strcmp(reg->name, cur_bank)) || (new_bank && !strcmp(new_bank, cur_bank)));
+ 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
+
+ // 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;
}
/*-----------------------------------------------------------------*/
pCode *pc;
pCodeInstruction *pci;
regs *reg;
+ regs *previous_reg; // contains the previous variable access info
const char *cur_bank, *new_bank;
unsigned cur_mask, new_mask, max_mask;
int allRAMmshared;
max_mask = pic14_getPIC()->bankMask;
cur_mask = max_mask;
cur_bank = NULL;
+ previous_reg = NULL;
allRAMmshared = pic14_allRAMShared();
// this one has a label---might check bank at all jumps here...
if (isPCI(pc) && (PCI(pc)->label || PCI(pc)->op == POC_CALL)) {
addpCodeComment(pc->prev, "BANKOPT3 drop assumptions: PCI with label or call found");
+ previous_reg = NULL;
cur_bank = NULL; // start new flow
cur_mask = max_mask;
}
// this one is/might be a label or BANKSEL---assume nothing
if (isPCL(pc) || isPCASMDIR(pc)) {
addpCodeComment(pc->prev, "BANKOPT4 drop assumptions: label or ASMDIR found");
+ previous_reg = NULL;
cur_bank = NULL;
cur_mask = max_mask;
}
new_mask = 0; // unknown, assume worst case
} else {
assert(!"Could not get register from instruction.");
+ new_bank = "UNKNOWN";
+ new_mask = 0; // unknown, assume worst case
}
// optimizations...
// is in (as well as the previous registers)
cur_mask &= new_mask;
- if (sameBank(reg, new_bank, cur_bank)) {
+ if (sameBank(reg, previous_reg, new_bank, cur_bank, max_mask)) {
// no BANKSEL required
addpCodeComment(pc->prev, "BANKOPT2 BANKSEL dropped; %s present in same bank as %s", new_bank, cur_bank);
continue;
cur_mask = new_mask;
cur_bank = new_bank;
+ previous_reg = reg;
insertBankSel(pci, cur_bank);
} // if
} // if
{
pCode *pc; pCodeLabel *pcl;
- if(!pb)
+ if(!pb || !pb->pcHead)
return;
for(pc = pb->pcHead; (pc=findNextInstruction(pc->next)) != NULL; ) {