- pCode *pc;
-
- /* check recursion */
- pc = setFirstItem(pb->function_entries);
- if(!pc)
- 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);
- }
- }
- }
- }
- }
- 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;
+ pCode *pc;
+ unsigned temp;
+ unsigned idx = startIdx;
+
+ /* check recursion */
+ pc = setFirstItem(pb->function_entries);
+ if (!pc)
+ 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
+
+ /*
+ * 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
+
+ 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) && (!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 lowest index available for caller's registers */
+ return idx;