Imported initial.
authormichaelh <michaelh@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Fri, 19 Jan 2001 04:44:11 +0000 (04:44 +0000)
committermichaelh <michaelh@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Fri, 19 Jan 2001 04:44:11 +0000 (04:44 +0000)
git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@530 4a8a32a2-be11-0410-ad9d-d568d2c75423

src/izt/Makefile [new file with mode: 0644]
src/izt/clean.mk [new file with mode: 0644]
src/izt/gen.c [new file with mode: 0644]
src/izt/i186.c [new file with mode: 0644]
src/izt/izt.h [new file with mode: 0644]
src/izt/ralloc.c [new file with mode: 0644]
src/izt/tlcs900h.c [new file with mode: 0644]

diff --git a/src/izt/Makefile b/src/izt/Makefile
new file mode 100644 (file)
index 0000000..5ae4720
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/src/izt/gen.c b/src/izt/gen.c
new file mode 100644 (file)
index 0000000..c653636
--- /dev/null
@@ -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 (file)
index 0000000..c11a5b8
--- /dev/null
@@ -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 (file)
index 0000000..3a8fc8c
--- /dev/null
@@ -0,0 +1,62 @@
+#include <common.h>
+
+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 (file)
index 0000000..dcb6b0a
--- /dev/null
@@ -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; i<count; i++) {
+       iCode *ic;
+
+       if (ebbs[i]->noPath &&
+           (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 (file)
index 0000000..bd43248
--- /dev/null
@@ -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 == */
+};