/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
-static void insertBankSel(pCodeInstruction *pci, const char *name)
+static int insertBankSel(pCodeInstruction *pci, const char *name)
{
pCode *new_pc;
pCodeOp *pcop;
// Never BANKSEL STATUS, this breaks all kinds of code (e.g., interrupt handlers).
- if (!strcmp("STATUS", name) || !strcmp("_STATUS", name)) return;
+ if (!strcmp("STATUS", name) || !strcmp("_STATUS", name)) return 0;
pcop = popCopyReg(PCOR(pci->pcop));
pcop->type = PO_GPR_REGISTER; // Sometimes the type is set to legacy 8051 - so override it
new_pc = newpCode(POC_BANKSEL, pcop);
insertPCodeInstruction(pci, PCI(new_pc));
+ return 1;
}
/*
// XXX: We can do better with fixed registers.
if (allRAMmshared && reg && (reg->type != REG_SFR) && (!reg->isFixed)) {
// no BANKSEL required
- addpCodeComment(pc->prev, "BANKOPT1b BANKSEL dropped; %s present in all of %s's banks", new_bank, cur_bank);
+ addpCodeComment(pc->prev, "BANKOPT1b BANKSEL dropped; %s present in all (of %s's) banks", new_bank, cur_bank);
continue;
}
- // restrict cur_mask to cover only the banks this register
- // is in (as well as the previous registers)
- cur_mask &= new_mask;
-
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);
}
} // if
- cur_mask = new_mask;
- cur_bank = new_bank;
- previous_reg = reg;
- insertBankSel(pci, cur_bank);
+ if (insertBankSel(pci, new_bank)) {
+ cur_mask = new_mask;
+ cur_bank = new_bank;
+ previous_reg = reg;
+ } // if
} // if
} // if
} // for
/*-----------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
-static unsigned register_reassign(pBlock *pb, unsigned idx, unsigned level)
+static unsigned
+register_reassign(pBlock *pb, unsigned startIdx, unsigned level)
{
- pCode *pc;
+ pCode *pc;
+ unsigned temp;
+ unsigned idx = startIdx;
- /* check recursion */
- pc = setFirstItem(pb->function_entries);
- if(!pc)
- return idx;
+ /* 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;
- }
+ if (pb->visited)
+ {
+ set *regset;
+ /* TODO: Recursion detection missing, should emit a warning as recursive code will fail. */
+
+ // Find the highest rIdx used by this function for return.
+ regset = pb->tregisters;
+ idx = 0;
+ while (regset)
+ {
+ temp = ((regs *)regset->item)->rIdx;
+ if (temp > idx)
+ idx = temp;
+ regset = regset->next;
+ } // while
+ DFPRINTF((stderr,
+ "%*s(%u) function \"%s\" already visited: max idx = %04x\n",
+ 4 * level, "", level,PCF(pc)->fname, idx));
+ return idx + 1;
+ } // if
- pb->visited = 1;
+ /*
+ * We now traverse the call tree depth first, assigning indices > startIdx
+ * to the registers of all called functions before assigning indices to
+ * the registers of the calling function, starting with one greater than
+ * the max. index used by any child function.
+ * This approach guarantees that, if f calls g, all registers of f have
+ * greater indices than those of g (also holds transitively).
+ *
+ * XXX: If a function f calls a function g in a different module,
+ * we should handle the case that g could call a function h
+ * in f's module.
+ * The consequence of this is that even though f and h might
+ * share registers (they do not call each other locally) when
+ * looking only at f's module, they actually must not do so!
+ *
+ * For a non-static function f, let ES(f) be the set of functions
+ * (including f) that can only be reached via f in the module-local
+ * call graph (ES(f) will hence be a subgraph).
+ * Let further REG(ES(f)) be the set of registers assigned to
+ * functions in ES(f).
+ * Then we should make sure that REG(ES(f)) and REG(ES(g)) are
+ * disjoint for all non-static functions f and g.
+ *
+ * Unfortunately, determining the sets ES(f) is non-trivial,
+ * so we ignore this problem and declare all modules non-reentrant.
+ * This is a bug.
+ */
+ pb->visited = 1;
+
+ DFPRINTF((stderr,
+ "%*s(%u) reassigning registers for functions called by \"%s\":base idx = %04x\n",
+ 4 * level, "", level, PCF(pc)->fname, startIdx));
+
+ 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)
+ {
+ /*
+ * Reassign the registers of all called functions and record
+ * the max. index I used by any child function --> I+1 will be
+ * the first index available to this function.
+ * (Problem shown with regression test src/regression/sub2.c)
+ */
+ unsigned childsMaxIdx;
+ childsMaxIdx = register_reassign(pcn->pb,startIdx,level+1);
+ if (childsMaxIdx > idx)
+ idx = childsMaxIdx;
+ } // if
+ } // if
+ } // for
- DFPRINTF((stderr," (%u) reassigning registers for function \"%s\"\n",level,PCF(pc)->fname));
+ pc = setFirstItem(pb->function_entries);
+ DFPRINTF((stderr,
+ "%*s(%u) reassigning registers for function \"%s\":idx = %04x\n",
+ 4 * level, "", level, PCF(pc)->fname, idx));
- 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) {
- /* 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);
- }
- }
- }
+ if (pb->tregisters)
+ {
+ regs *r;
+ for (r = setFirstItem(pb->tregisters); r; r = setNextItem(pb->tregisters))
+ {
+ if ((r->type == REG_GPR) && (!r->isFixed) && (r->rIdx < (int)idx))
+ {
+ char s[20];
+ set *regset;
+ /*
+ * Make sure, idx is not yet used in this routine ...
+ * XXX: This should no longer be required, as all functions
+ * are reassigned at most once ...
+ */
+ 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,
+ "%*s(%u) reassigning register %p \"%s\" to \"%s\"\n",
+ 4 * level, "", level, r, r->name, s));
+ free(r->name);
+ r->name = Safe_strdup(s);
+ } // if
+ } // for
+ } // if
- return idx;
+ /* return lowest index available for caller's registers */
+ return idx;
}
/*------------------------------------------------------------------*/
/* Note for this to work the functions need to be declared static. */
/* */
/*------------------------------------------------------------------*/
-void ReuseReg(void)
+void
+ReuseReg(void)
{
- pBlock *pb;
- if (options.noOverlay || !the_pFile) return;
- 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,0);
- }
+ pBlock *pb;
+
+ if (options.noOverlay || !the_pFile)
+ return;
+
+ 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,0);
+ } // if
+ } // for
}
/*-----------------------------------------------------------------*/
}
}
+#if 0
/*-----------------------------------------------------------------*/
/* printCallTree - writes the call tree to a file */
/* */
}
+#endif
#if 0
/*-----------------------------------------------------------------*/