+/*-----------------------------------------------------------------*/
+/* AnalyzeBanking - Called after the memory addresses have been */
+/* assigned to the registers. */
+/* */
+/*-----------------------------------------------------------------*/
+
+void AnalyzeBanking(void)
+{
+ pBlock *pb;
+
+ if(!picIsInitialized()) {
+ fprintf(stderr,"Temporary ERROR: at the moment you have to use\n");
+ fprintf(stderr,"an include file create by inc2h.pl. See SDCC source:\n");
+ fprintf(stderr,"support/scripts/inc2h.pl\n");
+ fprintf(stderr,"this is a nuisance bug that will be fixed shortly\n");
+
+ exit(1);
+ }
+
+ /* Phase x - Flow Analysis - Used Banks
+ *
+ * In this phase, the individual flow blocks are examined
+ * to determine the Register Banks they use
+ */
+
+ AnalyzeFlow(0);
+ AnalyzeFlow(1);
+
+ for(pb = the_pFile->pbHead; pb; pb = pb->next)
+ BanksUsedFlow(pb);
+ for(pb = the_pFile->pbHead; pb; pb = pb->next)
+ FixRegisterBanking(pb);
+
+}
+
+// Undefine REUSE_GPR in files pcode.c & device.c to prevent local function registers being reused.
+#define REUSE_GPR
+#ifdef REUSE_GPR
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+DEFSETFUNC (resetrIdx)
+{
+ if (!((regs *)item)->isFixed)
+ ((regs *)item)->rIdx = 0;
+
+ return 0;
+}
+
+pCode *findFunction(char *fname);
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+unsigned register_reassign(pBlock *pb, unsigned idx)
+{
+ pCode *pc;
+
+ /* check recursion */
+ pc = setFirstItem(pb->function_entries);
+ if(!pc)
+ return idx;
+
+ 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++;
+ 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);
+ }
+ }
+ }
+ }
+ }
+ 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);
+ }
+ }
+
+ }
+
+ return idx;
+}
+
+/*-----------------------------------------------------------------*/
+/* Re-allocate the GPR for optimum reuse for a given pblock */
+/* eg if a function m() calls function f1() and f2(), where f1 */
+/* allocates a local variable vf1 and f2 allocates a local */
+/* variable vf2. Then providing f1 and f2 do not call each other */
+/* they may share the same general purpose registers for vf1 and */
+/* vf2. */
+/* This is done by first setting the the regs rIdx to start after */
+/* all the global variables, then walking through the call tree */
+/* renaming the registers to match their new idx and incrementng */
+/* it as it goes. If a function has already been called it will */
+/* only rename the registers if it has already used up those */
+/* registers ie rIdx of the function's registers is lower than the */
+/* current rIdx. That way the register will not be reused while */
+/* still being used by an eariler function call. */
+/*-----------------------------------------------------------------*/
+void register_reusage(pBlock *mainPb)
+{
+ static int exercised = 0;
+ if (!exercised) { /* Only do this once */
+ /* Find end of statically allocated variables for start idx */
+ unsigned idx = 0x20; /* Start from begining of GPR. Note may not be 0x20 on some PICs */
+ regs *r;
+ for (r = setFirstItem(dynDirectRegs); r; r = setNextItem(dynDirectRegs)) {
+ if (r->type != REG_SFR) {
+ idx += r->size; /* Increment for all statically allocated variables */
+ }
+ }
+
+ applyToSet(dynAllocRegs,resetrIdx); /* Reset all rIdx to zero. */
+
+ if (mainPb)
+ idx = register_reassign(mainPb,idx); /* Do main and all the functions that are called from it. */
+ idx = register_reassign(the_pFile->pbHead,idx); /* Do the other functions such as interrupts. */
+ }
+ exercised++;
+}
+#endif // REUSE_GPR
+