From: michaelh Date: Fri, 19 Jan 2001 04:44:11 +0000 (+0000) Subject: Imported initial. X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=e98149340c973a181d44b1522d92fb4be9c677bb;p=fw%2Fsdcc Imported initial. git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@530 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/src/izt/Makefile b/src/izt/Makefile new file mode 100644 index 00000000..5ae47209 --- /dev/null +++ b/src/izt/Makefile @@ -0,0 +1,23 @@ +PRJDIR = ../.. + +include $(PRJDIR)/Makefile.common + +OBJ = i186.o ralloc.o gen.o tlcs900h.o +LIB = port.a + +CFLAGS += -I.. -I. -I../.. +LDFLAGS = -ggdb + +all: $(LIB) + +$(LIB): $(OBJ) + rm -f $(LIB) + ar r $(LIB) $(OBJ) + $(RANLIB) $(LIB) + +%.rul: %.def + $(AWK) -f ../SDCCpeeph.awk $< > $@ + +main.o: main.c peeph.rul peeph-z80.rul peeph-gbz80.rul mappings.i + +include clean.mk diff --git a/src/izt/clean.mk b/src/izt/clean.mk new file mode 100644 index 00000000..e69de29b diff --git a/src/izt/gen.c b/src/izt/gen.c new file mode 100644 index 00000000..c6536360 --- /dev/null +++ b/src/izt/gen.c @@ -0,0 +1,12 @@ +#include "izt.h" + +void iemit(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + + vprintf(format, ap); + printf("\n"); + + va_end(ap); +} diff --git a/src/izt/i186.c b/src/izt/i186.c new file mode 100644 index 00000000..c11a5b8a --- /dev/null +++ b/src/izt/i186.c @@ -0,0 +1,171 @@ +/** @file izt/i186.c + i186 specific general functions. +*/ +#include "izt.h" + +static REG _i186_regs[] = { + { 1, REG_ID_CL, "cl", 0, { REG_ID_CX, REG_ID_NONE, REG_ID_NONE } }, + { 1, REG_ID_CH, "ch", 0, { REG_ID_CX, REG_ID_NONE, REG_ID_NONE } }, + { 1, REG_ID_DL, "dl", 0, { REG_ID_DX, REG_ID_NONE, REG_ID_NONE } }, + { 1, REG_ID_DH, "dh", 0, { REG_ID_DX, REG_ID_NONE, REG_ID_NONE } }, + { 2, REG_ID_CX, "cx", 0, { REG_ID_CL, REG_ID_CH, REG_ID_NONE } }, + { 2, REG_ID_DX, "dx", 0, { REG_ID_DL, REG_ID_DH, REG_ID_NONE } }, + { 0, REG_ID_NONE,"??", 0, { REG_ID_NONE, REG_ID_NONE, REG_ID_NONE } } +}; + +static char _defaultRules[] = +{ + //#include "peeph.rul" +}; + +/* list of key words used by i186 */ +static char *_i186_keywords[] = { + NULL +}; + +static void _i186_init(void) +{ + asm_addTree(&asm_asxxxx_mapping); + izt_init(_i186_regs); +} + +static void _i186_reset_regparm() +{ +} + +static int _i186_regparm( sym_link *l) +{ + // PENDING: No register parameters. + return 0; +} + +static bool _i186_parseOptions(int *pargc, char **argv, int *i) +{ + /* TODO: allow port-specific command line options to specify + * segment names here. + */ + return FALSE; +} + +static void _i186_finaliseOptions(void) +{ + // No options +} + +static void _i186_setDefaultOptions(void) +{ + // No options +} + +static const char *_i186_getRegName(struct regs *reg) +{ + if (reg) + return reg->name; + wassert(0); + return "err"; +} + +static void _i186_genAssemblerPreamble(FILE *of) +{ + // PENDING +} + +/* Generate interrupt vector table. */ +static int _i186_genIVT(FILE *of, symbol **interrupts, int maxInterrupts) +{ + // PENDING + return 0; +} + +/** $1 is always the basename. + $2 is always the output file. + $3 varies + $l is the list of extra options that should be there somewhere... + MUST be terminated with a NULL. +*/ +// PENDING +static const char *_linkCmd[] = { + "aslink", "-nf", "$1", NULL +}; + +// PENDING +static const char *_asmCmd[] = { + "gpasm", NULL, NULL, NULL +}; + +void i186_assignRegisters (eBBlock **ebbs, int count) +{ +} + +/* Globals */ +PORT i186_port = { + "i186", + "Intel 8086/80186", /* Target name */ + { + FALSE, /* Emit glue around main */ + MODEL_SMALL, + MODEL_SMALL + }, + { + _asmCmd, + NULL, + NULL, + 0 + }, + { + _linkCmd, + NULL, + ".o" + }, + { + _defaultRules + }, + { + /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */ + 1, 2, 2, 4, 2, 2, 2, 1, 4, 4 + }, + { + "XSEG (XDATA)", + "STACK (DATA)", + "CSEG (CODE)", + "DSEG (DATA)", + "ISEG (DATA)", + "XSEG (XDATA)", + "BSEG (BIT)", + "RSEG (DATA)", + "GSINIT (CODE)", + "OSEG (OVR,DATA)", + "GSFINAL (CODE)", + "HOME (CODE)", + NULL, + NULL, + 1 + }, + { + +1, 1, 4, 1, 1, 0 + }, + /* i186 has an 16 bit mul */ + { + 2, 0 + }, + "_", + _i186_init, + _i186_parseOptions, + _i186_finaliseOptions, + _i186_setDefaultOptions, + izt_assignRegisters, + _i186_getRegName , + _i186_keywords, + _i186_genAssemblerPreamble, + _i186_genIVT , + _i186_reset_regparm, + _i186_regparm, + NULL, + FALSE, + 0, /* leave lt */ + 0, /* leave gt */ + 1, /* transform <= to ! > */ + 1, /* transform >= to ! < */ + 1, /* transform != to !(a == b) */ + 0 /* leave == */ +}; diff --git a/src/izt/izt.h b/src/izt/izt.h new file mode 100644 index 00000000..3a8fc8ce --- /dev/null +++ b/src/izt/izt.h @@ -0,0 +1,62 @@ +#include + +typedef enum { + REG_ID_NONE, + // Z80 + REG_ID_A, + REG_ID_B, + REG_ID_C, + REG_ID_D, + REG_ID_E, + REG_ID_H, + REG_ID_L, + REG_ID_AF, + REG_ID_BC, + REG_ID_DE, + REG_ID_HL, + REG_ID_IX, + REG_ID_IY, + // TLCS-900H + REG_ID_XBC, + REG_ID_XDE, + // i186 + REG_ID_CL, + REG_ID_CH, + REG_ID_CX, + REG_ID_DL, + REG_ID_DH, + REG_ID_DX, + REG_ID_MAX +} REG_ID; + +enum { + REG_USED = 1, + REG_USED_HIDDEN = 2 +}; + +enum { + REG_TYPE_CND = 1, + REG_TYPE_GPR = 2 +} REG_TYPE; + +typedef struct regs { + int size; + REG_ID id; + const char *name; + int used; + REG_ID hides[3]; +} REG; + +#define TEST(_d, _a) \ + (_a) ? (void)0 : (failures++, printf("Test %s \"%s\" failed.\n", #_a, _d), _dumpRegs()) + +#define NUM_OF(_a) (sizeof(_a)/sizeof(*(_a))) + +typedef struct { + REG *regs; +} PORT_DATA; + +PORT_DATA port_data; + +void izt_init(REG *regs); +void izt_assignRegisters (eBBlock **ebbs, int count); diff --git a/src/izt/ralloc.c b/src/izt/ralloc.c new file mode 100644 index 00000000..dcb6b0a4 --- /dev/null +++ b/src/izt/ralloc.c @@ -0,0 +1,816 @@ +/** @file izt/ralloc.c + */ +#include "izt.h" + +/// Static data. +static struct { + struct { + /// Used to generate a unique name for the spill location. + int loc; + /// Set of all iTemps spilt onto the stack. + set *set; + /// Similar to stackSpill + bitVect *vect; + } spill; + /// Bitvector of all registers used in this function. + bitVect *funcUsedRegs; + /// If a bit is set in this then the iCode at that sequence has had + /// registers allocated. + bitVect *regAssigned; + int blockSpill; + int stackExtend; +} _G; + +static REG *_findRegById(REG_ID id) +{ + REG *r = port_data.regs; + + while (r->size) { + if (r->id == id) + return r; + r++; + } + wassert(0); + return NULL; +} + +static REG *_getSubReg(REG *r, int size, int offset) +{ + wassert(r->size >= size); + + if (r->size == size) { + wassert(offset == 0); + return r; + } + // We use the hiding table to get the parts of the register. + else if (size == 1) { + wassert(offset == 0 || offset == 1); + return _findRegById(r->hides[offset]); + } + else if (size == 2) { + wassert(offset == 0); + return _findRegById(r->hides[2]); + } + // Cant. + wassert(0); + return NULL; +} + +static int _numRegsAvailable(int size) +{ + REG *r = port_data.regs; + int ret = 0; + + while (r->size) { + if (r->size == size && r->used == 0) + ret++; + r++; + } + + return ret; +} + +static void _setClearUsed(REG_ID id, int clear) +{ + REG *r = _findRegById(id); + wassert(r); + + if (!clear) { + // The parent shouldnt be able to be allocated if this child + // is already. + wassert((r->used & REG_USED_HIDDEN) == 0); + r->used |= REG_USED_HIDDEN; + } + else { + wassert((r->used & REG_USED_HIDDEN) != 0); + r->used &= ~REG_USED_HIDDEN; + } +} + +static void _markAsUsed(REG_ID id) +{ + _setClearUsed(id, FALSE); +} + +static void _markAsFree(REG_ID id) +{ + _setClearUsed(id, TRUE); +} + +static REG *_allocateReg(int size) +{ + REG *r = port_data.regs; + + while (r->size) { + if (r->size == size && r->used == 0) { + // Now go through the interference table and mark all other + // registers as used. + int i; + for (i=0; i < NUM_OF(r->hides); i++) { + if (r->hides[i] == REG_ID_NONE) { + break; + } + _markAsUsed(r->hides[i]); + } + r->used |= REG_USED; + return r; + } + r++; + } + return NULL; +} + +static bitVect *_markRegBits(bitVect *v, REG *r) +{ + int i; + + // Mark the primary register. + v = bitVectSetBit(v, r->id); + + // Now add all the hidden registers. + for (i=0; i < NUM_OF(r->hides); i++) { + if (r->hides[i] == REG_ID_NONE) { + break; + } + v = bitVectSetBit(v, r->hides[i]); + } + + return v; +} + +static void _freeReg(REG *r) +{ + int i; + wassert(r->used == REG_USED); + + r->used = 0; + + for (i=0; i < NUM_OF(r->hides); i++) { + if (r->hides[i] == REG_ID_NONE) { + break; + } + _markAsFree(r->hides[i]); + } +} + +static void _freeAllRegs(viod) +{ + REG *r = port_data.regs; + + while (r->size) { + r->used = 0; + r++; + } +} + +static void _dumpRegs(void) +{ + REG *r = port_data.regs; + + while (r->size) { + printf("%u\t%u\t%s\t%u\n", r->size, r->id, r->name, r->used); + r++; + } +} + +void izt_init(REG *regs) +{ + wassert(regs); + port_data.regs = regs; +} + +/// Lower register pressure by packing iTemps where possible. +static void _packRegisters(eBBlock *ebp) +{ + // PENDING: Assignment packing + // PENDING: Mark address of a true symbol as remat. + // PENDING: Propagate remat through equals. + // PENDING: Assign bitwise which is followed by a conditional into carry. + // PENDING: Pack for one use on pointer get or set. Assumes that the pointer + // is stored in the scratch register. + // PENDING: Pack short use iTemps into ACC or the scratch register. +} + +static void _computeRequiredRegs(void) +{ + symbol *sym; + int k; + + // Iterate over each live range. + for (sym = hTabFirstItem(liveRanges, &k); sym ; + sym = hTabNextItem(liveRanges, &k)) { + + sym->nRegs = 0; + + // If the symbol is never used, then next. + if ((sym->liveTo - sym->liveFrom) == 0) + continue; + + // Only temporaries need registers. + if (!sym->isitmp) + continue; + + // Conditionals live in carry and dont need registers. + if (sym->regType == REG_TYPE_CND) + continue; + + +#if 0 // PENDING. Currently we dont compute ruonly or accuse. + if (sym->ruonly || sym->accuse) { + if (IS_AGGREGATE(sym->type) || sym->isptr) + sym->type = aggrToPtr(sym->type,FALSE); + continue ; + } +#endif + // We need registers. + if (IS_AGGREGATE(sym->type) || sym->isptr) { + // Turn an aggregate into something real. + sym->type = aggrToPtr(sym->type, FALSE); + } + + sym->nRegs = getSize(sym->type); + wassert(sym->nRegs <= 4); + } +} + +static bool _doesntNeedRegs(iCode *ic) +{ + // Some types of instructions dont need registers. + // PENDING: Flush out the types and make processor specific. + if (SKIP_IC2(ic) || + ic->op == JUMPTABLE || + ic->op == IFX || + ic->op == IPUSH || + ic->op == IPOP || + ic->op == RETURN) { + return TRUE; + } + return FALSE; +} + +static bool _willCauseSpill(int size) +{ + return _numRegsAvailable(size) == 0; +} + +static void _deassignLRs(iCode *ic, eBBlock *ebp) +{ + symbol *sym; + int ignored; + symbol *result; + + // For each symbol + for (sym = hTabFirstItem(liveRanges, &ignored); sym; sym = hTabNextItem(liveRanges, &ignored)) { + + // Has this symbol expired yet? + if (sym->liveTo > ic->seq) { + // No. Cant deassign. + continue; + } + + // It has expired. Free up the resources. + + // If it was spilt, then free up the stack spill location. + if (sym->isspilt) { + if (sym->stackSpil) { + sym->usl.spillLoc->isFree = 1; + sym->stackSpil = 0; + } + continue; + } + + // If it currently has no registers assigned, then continue. + if (bitVectBitValue(_G.regAssigned, sym->key) == 0) { + continue; + } + + // If it has no registers assigned to it, then continue. + if (sym->nRegs == 0) { + continue; + } + + // Mark this sym as not having registers assigned. + bitVectUnSetBit(_G.regAssigned, sym->key); + + // Free the registers. + _freeReg(sym->regs[0]); + + // If deallocating will free up enough registers for this iCode + // then steal them immediatly. + if (IC_RESULT(ic) && !_doesntNeedRegs(ic)) { + result = OP_SYMBOL(IC_RESULT(ic)); + if (result && // Has a result + result->liveTo > ic->seq && // and lives past this instruction + result->liveTo <= ebp->lSeq && // and doesnt go past this block + result->nRegs && // and actually needs registers + !result->isspilt && // and doesnt have them yet + !result->remat && // and wouldnt waste them + !bitVectBitValue(_G.regAssigned, result->key) && // doesnt have them yet + !_willCauseSpill(result->nRegs) + ) { + result->regs[0] = _allocateReg(result->nRegs); + } + } + } +} + +/// Returns true if the live range of the given symbol doesnt overlap +/// with any of the live ranges in the set. +static bool _noOverlap (set *itmpStack, symbol *fsym) +{ + symbol *sym; + + for (sym = setFirstItem(itmpStack); sym; sym = setNextItem(itmpStack)) { + if (sym->liveTo > fsym->liveFrom) { + return FALSE; + } + } + return TRUE; +} + +/// Set operator that returns 1 if a free spill location is found. +DEFSETFUNC(_stackIsFree) +{ + symbol *sym = item; + V_ARG(symbol **,sloc); + V_ARG(symbol *,fsym); + + // Dont bother if one has already been found. + if (*sloc) + return 0; + + if (sym->isFree && // This location is free... + _noOverlap(sym->usl.itmpStack, fsym) && // and its usage doesnt overlap with the usage of this sym + getSize(sym->type) >= getSize(fsym->type) && // and the location is big enough to hold the sym + 1) { + // All good. Take this location. + *sloc = sym; + return 1; + } + else { + // No match. + return 0; + } +} + +/// Create a new spill location on the stack for this symbol. +symbol *_createStackSpill(symbol *sym) +{ + symbol *sloc= NULL; + + // Try to reuse an exisiting spill location. + if (applyToSet(_G.spill.set, _stackIsFree, &sloc, sym)) { + // Found one. Take it over. + sym->usl.spillLoc = sloc; + sym->stackSpil = TRUE; + sloc->isFree = 0; + addSetHead(&sloc->usl.itmpStack, sym); + return sym; + } + + // No existing location. Time to create one. + // Give it a pretty name. + sprintf(buffer, "sloc%d", ++_G.spill.loc); + // And create. + sloc = newiTemp(buffer); + + // Setup the type. + sloc->type = copyLinkChain(sym->type); + sloc->etype = getSpec(sloc->type); + SPEC_SCLS(sloc->etype) = S_AUTO ; + + allocLocal(sloc); + + // "To prevent compiler warning" + sloc->isref = 1; + + // Increase the local variable stack size on this function. + if (IN_STACK(sloc->etype)) { + currFunc->stack += getSize(sloc->type); + _G.stackExtend += getSize(sloc->type); + } else { + // The IZT port currently doesnt support loading locals into data space. + wassert(0); + } + + // And add it to the spill set. + addSetHead(&_G.spill.set, sloc); + sym->usl.spillLoc = sloc; + sym->stackSpil = TRUE; + + // "Add it to the set of itempStack set of the spill location + addSetHead(&sloc->usl.itmpStack,sym); + + return sym; +} + +static void _spillThis(symbol *sym) +{ + // Create a spill location if it needs one and doesnt have one yet. + if (!(sym->remat || sym->usl.spillLoc)) { + _createStackSpill(sym); + } + + sym->isspilt = TRUE; + // Add it to the spilt set. + _G.spill.vect = bitVectSetBit(_G.spill.vect, sym->key); + // and remove it from the 'has registers' set. + bitVectUnSetBit(_G.regAssigned, sym->key); + + // Free up any registers that were assigned to this. + if (sym->regs[0]) { + _freeReg(sym->regs[0]); + sym->regs[0] = NULL; + } + + // CHECK: If this sym now has a spill location, mark it as allocated + // so that the stack packing later doesnt remove it. + if (sym->usl.spillLoc && !sym->remat) { + sym->usl.spillLoc->allocreq = TRUE; + } + + return; +} + +static bitVect *_findSpillable(iCode *ic) +{ + bitVect *spillable; + + // First create a copy of the currently live ranges. + spillable = bitVectCopy(ic->rlive); + // Remove those which are already spilt. + spillable = bitVectCplAnd(spillable, _G.spill.vect); + // Remove those that this iCode uses. + spillable = bitVectCplAnd(spillable, ic->uses); + // Remove those that this iCode defines. + bitVectUnSetBit(spillable, ic->defKey); + + // Only those that have registers assigned can actually be spilt :) + spillable = bitVectIntersect(spillable, _G.regAssigned); + + return spillable; +} + +/// Finds the least used live range +static symbol *_leastUsedLR(set *sset) +{ + // sym is the currently least used symbol. + symbol *sym; + // walk walks the list of symbols in the scan set. + symbol *walk; + + // Use the first as the seed. + sym = walk = setFirstItem(sset); + + while (walk) { + // Prefer spilling the symbol with the least allocated registers. + // PENDING: Why? + if (walk->used == sym->used) { + if (getSize(walk->type) < getSize(sym->type)) { + sym = walk; + } + } + else if (walk->used < sym->used) { + // This is used less than the current best. It looses. + sym = walk; + } + + walk = setNextItem(sset); + } + + setToNull((void **)&sset); + sym->blockSpil = 0; + + return sym; +} + +/// Applies a function to a given set of live ranges. +static set *_liveRangesWith(bitVect *lrs, int (func)(symbol *,eBBlock *, iCode *), + eBBlock *ebp, iCode *ic) +{ + set *rset = NULL; + int i; + + // Dont do anything if the bitVect is empty. + if (!lrs || !lrs->size) + return NULL; + + for (i = 1; i < lrs->size; i++ ) { + symbol *sym; + + // If this bit isnt turned on, skip. + if (!bitVectBitValue(lrs, i)) + continue ; + + // If we don't find it in the live range hash table we are in serious trouble. + if (!(sym = hTabItemWithKey(liveRanges, i))) { + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "liveRangesWith could not find liveRange"); + exit(1); + } + + // If the function likes it, and it has registers assigned to + // it, add it to the return set. + if (func(sym, ebp, ic) && bitVectBitValue(_G.regAssigned, sym->key)) { + addSetHead(&rset,sym); + } + } + + return rset; +} + +/// Returns TRUE always. Used to fetch all live ranges. +static int _allLRs(symbol *sym, eBBlock *ebp, iCode *ic) +{ + return 1; +} + +static void _serialRegAssign(eBBlock **ebbs, int count) +{ + int i; + + // For each block, do... + for (i=0; inoPath && + (ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel )) { + // PENDING: Dont understand. + continue; + } + + + // For each iCode in this block, do... + for (ic = ebbs[i]->sch; ic; ic = ic->next) { + symbol *sym; + bitVect *spillable; + int willCauseSpill; + + // Dont support IPOP + wassert(ic->op != IPOP); + + // 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 = 1; + + // Take away registers from live ranges that end at this + // instruction. + _deassignLRs(ic, ebbs[i]); + + // Some instructions dont need registers. + if (_doesntNeedRegs(ic)) { + continue; + } + + // If there is no result, then it doesnt need registers. + if (!IC_RESULT(ic)) { + continue; + } + + sym = OP_SYMBOL(IC_RESULT(ic)); + + // Does it need any registers? + if (sym->nRegs == 0) { + continue; + } + + // Is it already split? + if (sym->isspilt) { + continue; + } + + // Does it already have registers assigned? + if (bitVectBitValue(_G.regAssigned,sym->key)) { + continue; + } + + // Will it live past this instruction? + if (sym->liveTo <= ic->seq) { + continue; + } + + // MLH Doesnt understand this. + /* "Iif some liverange has been spilt at the block level + and this one live beyond this block then spil this + to be safe" */ + if (_G.blockSpill && sym->liveTo > ebbs[i]->lSeq) { + _spillThis(sym); + continue; + } + + // Seems that this symbol needs registers. See if + // allocating will cause a spill. + willCauseSpill = _willCauseSpill(sym->nRegs); + spillable = _findSpillable(ic); + + // If this is remat., then dont waste any regsiters on it. + if (sym->remat) { + _spillThis(sym); + continue; + } + + // If trying to allocate will cause a spill, and nothing + // else is spillable then this sym looses. + if (willCauseSpill && bitVectIsZero(spillable)) { + _spillThis(sym); + continue; + } + + // If this will cause a spill, and it already has a spill + // location then spill this if it is the least used. + if (willCauseSpill && sym->usl.spillLoc) { + symbol *leastUsed = _leastUsedLR(_liveRangesWith(spillable, _allLRs, ebbs[i], ic)); + if (leastUsed && leastUsed->used > sym->used) { + _spillThis(sym); + continue; + } + } + + // Hmm. Here we could have no registers available but + // we'll still try to allocate. MLH wonders how this will + // work. + + // Mark this iCode as having registers assigned to it. + _G.regAssigned = bitVectSetBit(_G.regAssigned, sym->key); + + // And do it. + sym->regs[0] = _allocateReg(sym->nRegs); + } + } +} + +static void izt_gen(iCode *ic) +{ + printf("izt_gen\n"); +} + +static DEFSETFUNC(_deallocStackSpil) +{ + symbol *sym = item; + + deallocLocal(sym); + return 0; +} + +/// Compute the register mask for an operand. +bitVect *_rUmaskForOp(operand *op) +{ + bitVect *rumask; + symbol *sym; + + // "Only temporaries are assigned registers" + if (!IS_ITEMP(op)) + return NULL; + + sym = OP_SYMBOL(op); + + // If its spilt or no registers are needed, then no regs are assigned. + if (sym->isspilt || !sym->nRegs) + return NULL; + + rumask = newBitVect(REG_ID_MAX); + + if (sym->regs[0]) { + rumask = _markRegBits(rumask, sym->regs[0]); + } + + return rumask; +} + +/// Returns bit vector of registers used in iCode. +bitVect *_regsUsedIniCode (iCode *ic) +{ + bitVect *rmask = newBitVect(REG_ID_MAX); + + do { + // Special cases first. + if (ic->op == IFX ) { + rmask = bitVectUnion(rmask, _rUmaskForOp(IC_COND(ic))); + break; + } + + if (ic->op == JUMPTABLE) { + rmask = bitVectUnion(rmask, _rUmaskForOp(IC_JTCOND(ic))); + break; + } + + // Now the good old left, right, and result. + if (IC_LEFT(ic)) { + rmask = bitVectUnion(rmask, _rUmaskForOp(IC_LEFT(ic))); + } + + if (IC_RIGHT(ic)) { + rmask = bitVectUnion(rmask, _rUmaskForOp(IC_RIGHT(ic))); + } + + if (IC_RESULT(ic)) { + rmask = bitVectUnion(rmask, _rUmaskForOp(IC_RESULT(ic))); + } + } while (0); + + return rmask; +} + +/// Compute the helper bitVect that contains the register used mask. +static void _createRegMask(eBBlock **ebbs, int count) +{ + int i; + + /* for all blocks */ + for (i = 0; i < count; i++) { + iCode *ic ; + + // If this code is unused, skip it. + if ( ebbs[i]->noPath && + ( ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel )) { + continue; + } + + /* for all instructions */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) { + int j; + + if (SKIP_IC2(ic) || !ic->rlive) + continue ; + + // Mark the registers used in this instruction. + ic->rUsed = _regsUsedIniCode(ic); + // Mark them as used at least once in the function. + _G.funcUsedRegs = bitVectUnion(_G.funcUsedRegs, ic->rUsed); + + /* now create the register mask for those + registers that are in use : this is a + super set of ic->rUsed */ + ic->rMask = newBitVect(REG_ID_MAX+1); + + // "For all live Ranges alive at this point" + for (j = 1; j < ic->rlive->size; j++) { + symbol *sym; + + // "If if not alive then continue" + if (!bitVectBitValue(ic->rlive,j)) { + continue; + } + + // "Find the live range we are interested in" + if (!(sym = hTabItemWithKey(liveRanges,j))) { + werror (E_INTERNAL_ERROR,__FILE__,__LINE__, + "createRegMask cannot find live range"); + exit(0); + } + + // "If no register assigned to it" + if (!sym->nRegs || sym->isspilt) { + continue; + } + + // If this has any registers allocated, mark them as such. + if (sym->regs[0]) { + ic->rMask = _markRegBits(ic->rMask, sym->regs[0]); + } + } + } + } +} + +void izt_assignRegisters(eBBlock **ebbs, int count) +{ + // Contains a flat version of ebbs used in code generation. + iCode *chain; + + // Clear the bit vector of registers used in this function. + // Assumes that assignRegisters is called once per function. + setToNull((void *)&_G.funcUsedRegs); + + // First scan each live range, and figure out what registers + // are required. + _computeRequiredRegs(); + + // Now allocate the registers. + _serialRegAssign(ebbs, count); + + // And create the helper register used mask. + _createRegMask(ebbs, count); + + // Turn the bblock array into an optimised list of iCode entries. + chain = iCodeLabelOptimize(iCodeFromeBBlock(ebbs,count)); + + // Redo the stack offsets. This will remove any redundent stack + // locations ie iTemps that exist only in registers. + redoStackOffsets(); + + izt_gen(chain); + + // Deallocate any stack spill locations. + applyToSet(_G.spill.set, _deallocStackSpil); + + _G.spill.loc = 0; + setToNull((void **)&_G.spill.set); + setToNull((void **)&_G.spill.vect); + + // And free all registers. + _freeAllRegs(); +} diff --git a/src/izt/tlcs900h.c b/src/izt/tlcs900h.c new file mode 100644 index 00000000..bd43248b --- /dev/null +++ b/src/izt/tlcs900h.c @@ -0,0 +1,174 @@ +/** @file izt/tlcs900h.c + tlcs900h specific general functions. +*/ +#include "izt.h" + +static REG _tlcs900h_regs[] = { + { 1, REG_ID_C, "c", 0, { REG_ID_BC, REG_ID_NONE, REG_ID_NONE } }, + { 1, REG_ID_B, "b", 0, { REG_ID_BC, REG_ID_NONE, REG_ID_NONE } }, + { 1, REG_ID_E, "e", 0, { REG_ID_DE, REG_ID_NONE, REG_ID_NONE } }, + { 1, REG_ID_D, "d", 0, { REG_ID_DE, REG_ID_NONE, REG_ID_NONE } }, + { 2, REG_ID_BC, "bc", 0, { REG_ID_C, REG_ID_B, REG_ID_NONE } }, + { 2, REG_ID_DE, "de", 0, { REG_ID_E, REG_ID_D, REG_ID_NONE } }, + { 4, REG_ID_XBC, "xbc", 0, { REG_ID_C, REG_ID_B, REG_ID_BC } }, + { 4, REG_ID_XDE, "xde", 0, { REG_ID_E, REG_ID_D, REG_ID_DE } }, + { 0, REG_ID_NONE,"??", 0, { REG_ID_NONE, REG_ID_NONE, REG_ID_NONE } } +}; + +static char _defaultRules[] = +{ + //#include "peeph.rul" +}; + +/* list of key words used by msc51 */ +static char *_tlcs900h_keywords[] = { + NULL +}; + +void tlcs900h_assignRegisters (eBBlock **ebbs, int count); + +static void _tlcs900h_init(void) +{ + asm_addTree(&asm_asxxxx_mapping); +} + +static void _tlcs900h_reset_regparm() +{ +} + +static int _tlcs900h_regparm( sym_link *l) +{ + // PENDING: No register parameters. + return 0; +} + +static bool _tlcs900h_parseOptions(int *pargc, char **argv, int *i) +{ + /* TODO: allow port-specific command line options to specify + * segment names here. + */ + return FALSE; +} + +static void _tlcs900h_finaliseOptions(void) +{ + // No options +} + +static void _tlcs900h_setDefaultOptions(void) +{ + // No options +} + +static const char *_tlcs900h_getRegName(struct regs *reg) +{ + if (reg) + return reg->name; + wassert(0); + return "err"; +} + +static void _tlcs900h_genAssemblerPreamble(FILE *of) +{ + // PENDING +} + +/* Generate interrupt vector table. */ +static int _tlcs900h_genIVT(FILE *of, symbol **interrupts, int maxInterrupts) +{ + // PENDING + return 0; +} + +/** $1 is always the basename. + $2 is always the output file. + $3 varies + $l is the list of extra options that should be there somewhere... + MUST be terminated with a NULL. +*/ +// PENDING +static const char *_linkCmd[] = { + "aslink", "-nf", "$1", NULL +}; + +// PENDING +static const char *_asmCmd[] = { + "gpasm", NULL, NULL, NULL +}; + +void tlcs900h_assignRegisters (eBBlock **ebbs, int count) +{ +} + +/* Globals */ +PORT tlcs900h_port = { + "tlcs900h", + "Toshiba TLCS-900H", /* Target name */ + { + TRUE, /* Emit glue around main */ + MODEL_SMALL, + MODEL_SMALL + }, + { + _asmCmd, + NULL, + NULL, + 0 + }, + { + _linkCmd, + NULL, + ".o" + }, + { + _defaultRules + }, + { + /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */ + 1, 2, 2, 4, 2, 2, 2, 1, 4, 4 + }, + { + "XSEG (XDATA)", + "STACK (DATA)", + "CSEG (CODE)", + "DSEG (DATA)", + "ISEG (DATA)", + "XSEG (XDATA)", + "BSEG (BIT)", + "RSEG (DATA)", + "GSINIT (CODE)", + "OSEG (OVR,DATA)", + "GSFINAL (CODE)", + "HOME (CODE)", + NULL, + NULL, + 1 + }, + { + +1, 1, 4, 1, 1, 0 + }, + /* tlcs900h has an 16 bit mul */ + { + 2, 0 + }, + "_", + _tlcs900h_init, + _tlcs900h_parseOptions, + _tlcs900h_finaliseOptions, + _tlcs900h_setDefaultOptions, + tlcs900h_assignRegisters, + _tlcs900h_getRegName , + _tlcs900h_keywords, + _tlcs900h_genAssemblerPreamble, + _tlcs900h_genIVT , + _tlcs900h_reset_regparm, + _tlcs900h_regparm, + NULL, + FALSE, + 0, /* leave lt */ + 0, /* leave gt */ + 1, /* transform <= to ! > */ + 1, /* transform >= to ! < */ + 1, /* transform != to !(a == b) */ + 0 /* leave == */ +};