/*-----------------------------------------------------------------*/ static S4O_RET termScanAtFunc (const lineNode *pl, int rIdx) { sym_link *ftype; bool banked_reg = (rIdx == R0_IDX) || (rIdx == R1_IDX) || (rIdx == R2_IDX); if (!isFunc (pl)) return S4O_CONTINUE; // let's assume calls to literally given locations use the default // most notably : (*(void (*)()) 0) (); see bug 1749275 if (IS_VALOP (IC_LEFT (pl->ic))) return (options.model == MODEL_HUGE) && banked_reg ? S4O_ABORT : options.all_callee_saves ? S4O_CONTINUE : S4O_TERM; ftype = OP_SYM_TYPE(IC_LEFT(pl->ic)); if (IS_FUNCPTR (ftype)) ftype = ftype->next; if (IFFUNC_ISBANKEDCALL(ftype) && banked_reg) return S4O_ABORT; if (FUNC_ARGS (ftype) && getSize (FUNC_ARGS (ftype)->type) > 4) return S4O_ABORT; if (FUNC_CALLEESAVES(ftype)) return S4O_CONTINUE; if (FUNC_ISNAKED(ftype)) return S4O_CONTINUE; return S4O_TERM; }
/*-----------------------------------------------------------------*/ eBBlock * iCode2eBBlock (iCode * ic) { iCode *loop; eBBlock *ebb = neweBBlock (); /* allocate an entry */ /* put the first one unconditionally */ ebb->sch = ic; ic->seq = 0; /* if this is a label then */ if (ic->op == LABEL) ebb->entryLabel = ic->label; else { struct dbuf_s dbuf; dbuf_init (&dbuf, 128); dbuf_printf (&dbuf, "_eBBlock%d", eBBNum++); ebb->entryLabel = newSymbol (dbuf_c_str (&dbuf), 1); dbuf_destroy (&dbuf); ebb->entryLabel->key = labelKey++; } if (ic && (ic->op == GOTO || ic->op == JUMPTABLE || ic->op == IFX)) { ebb->ech = ebb->sch; return ebb; } /* if this is a function call */ if (ic->op == CALL || ic->op == PCALL) { sym_link *type = operandType (IC_LEFT (ic)); ebb->hasFcall = 1; if (currFunc) FUNC_HASFCALL (currFunc->type) = 1; if (IS_FUNCPTR (type)) type = type->next; if (type && FUNC_ISNORETURN (type)) { ebb->ech = ebb->sch; return ebb; } } if ((ic->next && ic->next->op == LABEL) || !ic->next) { ebb->ech = ebb->sch; return ebb; } /* loop thru till we find one with a label */ for (loop = ic->next; loop; loop = loop->next) { loop->seq = 0; /* if this is the last one */ if (!loop->next) break; /* if this is a function call */ if (loop->op == CALL || loop->op == PCALL) { sym_link *type = operandType (IC_LEFT (loop)); ebb->hasFcall = 1; if (currFunc) FUNC_HASFCALL (currFunc->type) = 1; if (IS_FUNCPTR (type)) type = type->next; if (type && FUNC_ISNORETURN (type)) break; } /* if the next one is a label */ /* if this is a goto or ifx */ if (loop->next->op == LABEL || loop->op == GOTO || loop->op == JUMPTABLE || loop->op == IFX) break; } /* mark the end of the chain */ ebb->ech = loop; return ebb; }
/** Mark variables for assignment by the register allocator. */ static void serialRegMark (eBBlock ** ebbs, int count) { int i; short int max_alloc_bytes = SHRT_MAX; // Byte limit. Set this to a low value to pass only few variables to the register allocator. This can be useful for debugging. stm8_call_stack_size = 2; // Saving of register to stack temporarily. /* for all blocks */ for (i = 0; i < count; i++) { iCode *ic; if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel)) continue; /* for all instructions do */ for (ic = ebbs[i]->sch; ic; ic = ic->next) { if ((ic->op == CALL || ic->op == PCALL) && ic->parmBytes + 5 > stm8_call_stack_size) { sym_link *dtype = operandType (IC_LEFT (ic)); sym_link *ftype = IS_FUNCPTR (dtype) ? dtype->next : dtype; /* 5 for saving all registers at call site + 2 for big return value */ stm8_call_stack_size = ic->parmBytes + 5 + 2 * (getSize (ftype->next) > 4); } if (ic->op == IPOP) wassert (0); /* if result is present && is a true symbol */ if (IC_RESULT (ic) && ic->op != IFX && IS_TRUE_SYMOP (IC_RESULT (ic))) OP_SYMBOL (IC_RESULT (ic))->allocreq++; /* some don't need registers, since there is no result. */ if (SKIP_IC2 (ic) || ic->op == JUMPTABLE || ic->op == IFX || ic->op == IPUSH || ic->op == IPOP || (IC_RESULT (ic) && POINTER_SET (ic))) continue; /* now we need to allocate registers only for the result */ if (IC_RESULT (ic)) { symbol *sym = OP_SYMBOL (IC_RESULT (ic)); D (D_ALLOC, ("serialRegAssign: in loop on result %p\n", sym)); if (sym->isspilt && sym->usl.spillLoc) // todo: Remove once remat is supported! { sym->usl.spillLoc->allocreq--; sym->isspilt = FALSE; } /* Make sure any spill location is definately allocated */ if (sym->isspilt && !sym->remat && sym->usl.spillLoc && !sym->usl.spillLoc->allocreq) sym->usl.spillLoc->allocreq++; /* if it does not need or is spilt or is already marked for the new allocator or will not live beyond this instructions */ if (!sym->nRegs || sym->isspilt || sym->for_newralloc || sym->liveTo <= ic->seq) { D (D_ALLOC, ("serialRegAssign: won't live long enough.\n")); continue; } if (sym->nRegs > 4 && ic->op == CALL) { spillThis (sym, TRUE); } else if (max_alloc_bytes >= sym->nRegs) { sym->for_newralloc = 1; max_alloc_bytes -= sym->nRegs; } else if (!sym->for_newralloc) { spillThis (sym, TRUE); printf ("Spilt %s due to byte limit.\n", sym->name); } } } } }
/*-----------------------------------------------------------------*/ static void eBBSuccessors (ebbIndex * ebbi) { eBBlock ** ebbs = ebbi->bbOrder; int count = ebbi->count; int i = 0; /* for all the blocks do */ for (; i < count; i++) { iCode *ic; if (ebbs[i]->noPath) continue; ebbs[i]->succVect = newBitVect (count); /* if the next on exists & this one does not */ /* end in a GOTO or RETURN then the next is */ /* a natural successor of this. Note we have */ /* consider eBBlocks with no instructions */ if (ebbs[i + 1]) { if (ebbs[i]->ech) { bool foundNoReturn = FALSE; if (ebbs[i]->ech->op == CALL || ebbs[i]->ech->op == PCALL) { sym_link *type = operandType (IC_LEFT (ebbs[i]->ech)); if (IS_FUNCPTR (type)) type = type->next; if (type && FUNC_ISNORETURN (type)) foundNoReturn = TRUE; } if (!foundNoReturn && ebbs[i]->ech->op != GOTO && ebbs[i]->ech->op != RETURN && ebbs[i]->ech->op != JUMPTABLE) { int j = i + 1; while (ebbs[j] && ebbs[j]->noPath) j++; addSuccessor (ebbs[i], ebbs[j]); /* add it */ } else { if (i && ebbs[i-1]->ech && ebbs[i-1]->ech->op==IFX) { ebbs[i]->isConditionalExitFrom=ebbs[i-1]; } } } /* no instructions in the block */ /* could happen for dummy blocks */ else addSuccessor (ebbs[i], ebbs[i + 1]); } /* go thru all the instructions: if we find a */ /* goto or ifx or a return then we have a succ */ if ((ic = ebbs[i]->ech)) { eBBlock *succ; /* special case for jumptable */ if (ic->op == JUMPTABLE) { symbol *lbl; for (lbl = setFirstItem (IC_JTLABELS (ic)); lbl; lbl = setNextItem (IC_JTLABELS (ic))) addSuccessor (ebbs[i], eBBWithEntryLabel (ebbi, lbl)); } else { succ = NULL; /* depending on the instruction operator */ switch (ic->op) { case GOTO: /* goto has edge to label */ succ = eBBWithEntryLabel (ebbi, ic->label); break; case IFX: /* conditional jump */ /* if true label is present */ if (IC_TRUE (ic)) succ = eBBWithEntryLabel (ebbi, IC_TRUE (ic)); else succ = eBBWithEntryLabel (ebbi, IC_FALSE (ic)); break; case RETURN: /* block with return */ succ = eBBWithEntryLabel (ebbi, returnLabel); break; } /* if there is a successor add to the list */ /* if it is not already present in the list */ if (succ) addSuccessor (ebbs[i], succ); } } } }