case 1:
SAFE_snprintf(&s,&size,"high (%s+%d)",pcop->name, PCOI(pcop)->index);
break;
+ case 2:
+ SAFE_snprintf(&s,&size,"0x%02x",PCOI(pcop)->_const ? GPTRTAG_CODE : GPTRTAG_DATA);
+ break;
default:
fprintf (stderr, "PO_IMMEDIATE/_const/offset=%d\n", PCOI(pcop)->offset);
assert ( !"offset too large" );
case 1:
SAFE_snprintf(&s,&size,"high (%s + %d)",pcop->name, PCOI(pcop)->index);
break;
+ case 2:
+ SAFE_snprintf(&s,&size,"0x%02x",PCOI(pcop)->_const ? GPTRTAG_CODE : GPTRTAG_DATA);
+ break;
default:
fprintf (stderr, "PO_IMMEDIATE/mutable/offset=%d\n", PCOI(pcop)->offset);
assert ( !"offset too large" );
/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
-static int sameBank(regs *reg, const char *new_bank, const char *cur_bank)
+static int sameBank(regs *reg, regs *previous_reg, const char *new_bank, const char *cur_bank, unsigned max_mask)
{
if (!cur_bank) return 0;
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)));
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;
}
// 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
/*-----------------------------------------------------------------*/
/* InitRegReuse - Initialises variables for code analyzer */
/*-----------------------------------------------------------------*/
-
void InitReuseReg(void)
{
/* Find end of statically allocated variables for start idx */
/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
-static unsigned register_reassign(pBlock *pb, unsigned idx)
+static unsigned register_reassign(pBlock *pb, unsigned idx, unsigned level)
{
- pCode *pc;
-
- /* check recursion */
- pc = setFirstItem(pb->function_entries);
- if(!pc)
- return idx;
+ pCode *pc;
- if (pb->visited) {
- /* TODO: Recursion detection missing, should emit a warning as recursive code will fail. */
- return idx;
- }
-
- pb->visited = 1;
-
- DFPRINTF((stderr," reassigning registers for function \"%s\"\n",PCF(pc)->fname));
-
- if (pb->tregisters) {
- regs *r;
- for (r = setFirstItem(pb->tregisters); r; r = setNextItem(pb->tregisters)) {
- if (r->type == REG_GPR) {
- if (!r->isFixed) {
- if (r->rIdx < (int)idx) {
- char s[20];
- r->rIdx = idx++;
- if (peakIdx < idx) peakIdx = idx;
- sprintf(s,"r0x%02X", r->rIdx);
- DFPRINTF((stderr," reassigning register \"%s\" to \"%s\"\n",r->name,s));
- free(r->name);
- r->name = Safe_strdup(s);
- }
- }
- }
+ /* check recursion */
+ pc = setFirstItem(pb->function_entries);
+ if(!pc)
+ return idx;
+
+ if (pb->visited) {
+ /* TODO: Recursion detection missing, should emit a warning as recursive code will fail. */
+ return idx;
+ }
+
+ pb->visited = 1;
+
+ DFPRINTF((stderr," (%u) reassigning registers for function \"%s\"\n",level,PCF(pc)->fname));
+
+ if (pb->tregisters) {
+ regs *r;
+ for (r = setFirstItem(pb->tregisters); r; r = setNextItem(pb->tregisters)) {
+ if (r->type == REG_GPR) {
+ if (!r->isFixed) {
+ if (r->rIdx < (int)idx) {
+ char s[20];
+ set *regset;
+ // make sure, idx is not yet used in this routine...
+ do {
+ regset = pb->tregisters;
+ // do not touch s->curr ==> outer loop!
+ while (regset && ((regs *)regset->item)->rIdx != idx) {
+ regset = regset->next;
+ }
+ if (regset) idx++;
+ } while (regset);
+ r->rIdx = idx++;
+ if (peakIdx < idx) peakIdx = idx;
+ sprintf(s,"r0x%02X", r->rIdx);
+ DFPRINTF((stderr," (%u) reassigning register %p \"%s\" to \"%s\"\n",level,r,r->name,s));
+ free(r->name);
+ r->name = Safe_strdup(s);
+ }
}
+ }
}
- for(pc = setFirstItem(pb->function_calls); pc; pc = setNextItem(pb->function_calls)) {
-
- if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
- char *dest = get_op_from_instruction(PCI(pc));
-
- pCode *pcn = findFunction(dest);
- if(pcn) {
- register_reassign(pcn->pb,idx);
- }
- }
-
+ }
+ for(pc = setFirstItem(pb->function_calls); pc; pc = setNextItem(pb->function_calls)) {
+
+ if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
+ char *dest = get_op_from_instruction(PCI(pc));
+
+ pCode *pcn = findFunction(dest);
+ if(pcn) {
+ /* This index increment from subroutines is not required, as all subroutines
+ * may share registers NOT used by this one (< idx).
+ * BUT if called functions A and B share a register, which gets assigned
+ * rIdx = idx + 4 while analyzing A, we must not assign idx + 4 again while
+ * analyzing B!
+ * As an alternative to this "solution" we could check above whether an
+ * to-be-assigned rIdx is already present in the register set of the
+ * current function. This would increase the reused registers and make this
+ * `idx =' irrelevant.
+ * UPDATE: Implemented above; not fast, but works.
+ * (Problem shown with regression test src/regression/sub2.c)
+ */
+ /*idx = */register_reassign(pcn->pb,idx,level+1);
+ }
}
-
- return idx;
+ }
+
+ return idx;
}
/*------------------------------------------------------------------*/
InitReuseReg();
for(pb = the_pFile->pbHead; pb; pb = pb->next) {
/* Non static functions can be called from other modules so their registers must reassign */
- if (pb->function_entries&&(PCF(setFirstItem(pb->function_entries))->isPublic||!pb->visited))
- register_reassign(pb,peakIdx);
+ if (pb->function_entries && (PCF(setFirstItem(pb->function_entries))->isPublic || !pb->visited))
+ register_reassign(pb,peakIdx,0);
}
}