X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fpic%2Fpcode.c;h=b97ff171e477bf22c313c255df3c82c34aac0f23;hb=5a1d5e778e85664f4e6657019348b4756b16eacb;hp=8bf1f0b979c8325810e7be9a72f512caa77e4abd;hpb=1e65e3bd5cbff5a1ab4a7a65c2ff68e4b5e5b43c;p=fw%2Fsdcc diff --git a/src/pic/pcode.c b/src/pic/pcode.c index 8bf1f0b9..b97ff171 100644 --- a/src/pic/pcode.c +++ b/src/pic/pcode.c @@ -4013,14 +4013,14 @@ static void insertPCodeInstruction(pCodeInstruction *pci, pCodeInstruction *new_ /*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/ -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 @@ -4029,6 +4029,7 @@ static void insertBankSel(pCodeInstruction *pci, const char *name) new_pc = newpCode(POC_BANKSEL, pcop); insertPCodeInstruction(pci, PCI(new_pc)); + return 1; } /* @@ -4193,14 +4194,10 @@ static void FixRegisterBanking(pBlock *pb) // 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); @@ -4208,10 +4205,11 @@ static void FixRegisterBanking(pBlock *pb) } } // 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 @@ -4745,77 +4743,139 @@ static void InitReuseReg(void) /*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/ -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; } /*------------------------------------------------------------------*/ @@ -4839,16 +4899,26 @@ static unsigned register_reassign(pBlock *pb, unsigned idx, unsigned level) /* 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 } /*-----------------------------------------------------------------*/