Began adding the code generation framework.
authormichaelh <michaelh@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Sun, 28 Jan 2001 03:12:00 +0000 (03:12 +0000)
committermichaelh <michaelh@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Sun, 28 Jan 2001 03:12:00 +0000 (03:12 +0000)
git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@542 4a8a32a2-be11-0410-ad9d-d568d2c75423

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

index 5ae472096f6d47ccb77e7836ca6d39fdb91df189..1e6e54123bb64e9ccbe2564ccfba0b425803c886 100644 (file)
@@ -2,7 +2,7 @@ PRJDIR = ../..
 
 include $(PRJDIR)/Makefile.common
 
-OBJ = i186.o ralloc.o gen.o tlcs900h.o
+OBJ = i186.o ralloc.o gen.o tlcs900h.o gen_generic.o
 LIB = port.a
 
 CFLAGS += -I.. -I. -I../..
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4055fb30f34ce62fce0e41a11fa4a1025f1cff59 100644 (file)
@@ -0,0 +1,6 @@
+#
+
+clean:
+       rm -f $(LIB) *.o *~ port.a
+
+# End of src/z80/clean.mk
index c6536360de79483bfff0eec1a27653e840b3f2fb..7d13682c4468493149799597c7e3469365941f09 100644 (file)
 #include "izt.h"
+#include "gen.h"
 
-void iemit(const char *format, ...)
+static struct {
+    struct {
+       lineNode *head;
+       lineNode *current;
+    } lines;
+    struct {
+       hTab *base;
+       hTab *proc;
+    } htabs;
+} _G;
+
+static void _tidyUp(char *buf)
+{
+    // Clean up the line so that it is 'prettier'.
+    if (*buf == ';') {
+       // If this is a comment line (starts with a ';') then indent it.
+       // PENDING: The outputter does its own pretty print.  Disable for now.
+    }
+    else if (strchr(buf, ':')) {
+       // Is a label - cant do anything.
+    }
+    else {
+       /* Change the first (and probably only) ' ' to a tab so
+          everything lines up.
+       */
+       while (*buf) {
+           if (*buf == ' ') {
+               *buf = '\t';
+               return;
+           }
+           buf++;
+       }
+    }
+}
+
+void iemit(const char *szFormat, ...)
 {
+    char buffer[1024];
     va_list ap;
-    va_start(ap, format);
 
-    vprintf(format, ap);
-    printf("\n");
+    va_start(ap, szFormat);
+
+    vsprintf(buffer, szFormat, ap);
+
+    _tidyUp(buffer);
+
+    if (_G.lines.current == NULL) {
+       _G.lines.head = newLineNode(buffer);
+       _G.lines.current = _G.lines.head;
+    }
+    else {
+       _G.lines.current = connectLine(_G.lines.current, newLineNode(buffer));
+    }
+    
+    // PENDING: Inline support.
+    //    _G.lines.current->isInline = inLine;
+}
+
+// Mapping between operand type and a friendly name.
+typedef struct {
+    const int op;
+    const char *name;
+} OPNAME;
+
+static OPNAME _opnames[] = {
+    { '!' ,            "genNot" },
+    { '~' ,            "genCpl" },
+    { UNARYMINUS,      "genUminus" },
+    { IPUSH,           "genIpush" },
+    { IPOP,            "genIfx" },
+    { CALL,            "genCall" },
+    { PCALL,           "genPcall" },
+    { FUNCTION,                "genFunction" },
+    { ENDFUNCTION,     "genEndFunction" },
+    { RETURN,          "genRet" },
+    { LABEL,           "genLabel" },
+    { GOTO,            "genGoto" },
+    { '+' ,            "genPlus" },
+    { '-' ,            "genMinus" },
+    { '*' ,            "genMult" },
+    { '/' ,            "genDiv" },
+    { '%' ,            "genMod" },
+    { '>' ,            "genCmpGt" },
+    { '<' ,            "genCmpLt" },
+    { EQ_OP,           "genCmpEq" },
+    { AND_OP,          "genAndOp" },
+    { OR_OP,           "genOrOp" },
+    { '^' ,            "genXor" },
+    { '|' ,            "genOr" },
+    { BITWISEAND,      "genAnd" },
+    { INLINEASM,       "genInline" },
+    { RRC,             "genRRC" },
+    { RLC,             "genRLC" },
+    { GETHBIT,         "genHBIT" },
+    { LEFT_OP,         "genLeftShift" },
+    { RIGHT_OP,                "genRightShift" },
+    { GET_VALUE_AT_ADDRESS,            "genPointerGet" },
+    { '=',             "genAssign" },
+    { IFX,             "genIfx" },
+    { ADDRESS_OF,      "genAddrOf" },
+    { JUMPTABLE,       "genJumpTab" },
+    { CAST,            "genCast" },
+    { RECEIVE,         "genReceive" },
+    { SEND,            "addSet" },
+    { 0,               NULL }
+};
+
+// Possible return codes for a find matcher.
+enum {
+    FIND_LESS_THAN = -1,
+    // This element does match.
+    FIND_MATCH = 0,
+    FIND_GREATER_THAN = 1,
+    // This element doesnt match.
+    FIND_NO_MATCH = FIND_GREATER_THAN,
+    // This element marks the end of list.
+    FIND_EOL
+};
+
+// Limits the given integer to the find result numbers.
+static int _limitToFind(int i) 
+{
+    if (i < 0) {
+       return FIND_LESS_THAN;
+    }
+    else if (i > 0) {
+       return FIND_GREATER_THAN;
+    }
+    else {
+       return FIND_MATCH;
+    }
+}
 
-    va_end(ap);
+// Matches an opname id to the given id.
+static int _opnamesMatcher(void *pthis, void *pkey)
+{
+    OPNAME *name = pthis;
+
+    if (name->name == NULL) {
+       return FIND_EOL;
+    }
+    else {
+       return _limitToFind(name->op - *(int *)pkey);
+    }
+}
+
+// Find an element of an unordered list.
+static void *_find(void *base, size_t elemSize, void *pkey, int (*match)(void *pthis, void *pkey))
+{
+    do {
+       switch (match(base, pkey)) {
+       case FIND_MATCH:
+           return base;
+       case FIND_EOL:
+           return NULL;
+       case FIND_LESS_THAN:
+       case FIND_GREATER_THAN:
+           base = (char *)base + elemSize;
+           break;
+       default:
+           wassert(0);
+       }
+    } while (1);
+}
+
+// Finds the friendly operation name for an op number.
+static const char *_findOpName(int op) {
+    OPNAME *name = _find(_opnames, sizeof(*_opnames), &op, _opnamesMatcher);
+    if (name) {
+       return name->name;
+    }
+    else {
+       return NULL;
+    }
+}
+
+// PENDING
+static bool _isResultRemat (iCode *ic)
+{
+    if (SKIP_IC(ic) || ic->op == IFX)
+       return 0;
+    
+    if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
+       symbol *sym = OP_SYMBOL(IC_RESULT(ic));
+       if (sym->remat && !POINTER_SET(ic)) 
+           return 1;
+    }
+    
+    return 0;
+}
+
+// Print out the generated lines.
+static void _printLines(void)
+{
+    // Currently a holder function.  The Z80 needs some special mangling
+    // for bank support.
+    printLine(_G.lines.head, codeOutFile);
 }
+
+void izt_initEmitters(void)
+{
+    _G.htabs.base = newHashTable(100);
+    _G.htabs.proc = newHashTable(100);
+
+    izt_initBaseEmitters(&_G.htabs.base);
+}
+
+static int _emitterCompare(const void *p1, const void *p2)
+{
+    wassert(p1);
+    wassert(p2);
+    return ((EMITTER *)p1)->op == ((EMITTER *)p2)->op;
+}
+
+static bool _tryEmittingiCode(hTab *h, iCode *ic)
+{
+    EMITTER key = { ic->op, NULL };
+    EMITTER *found;
+
+    found = hTabFindByKey(h, ic->op, &key, _emitterCompare);
+
+    if (found) {
+       found->emit(ic);
+       return TRUE;
+    }
+    else {
+       return FALSE;
+    }
+}
+
+// Add a NULL terminated array of emitters into the given hash table.
+void izt_addEmittersToHTab(hTab **into, EMITTER _base_emitters[])
+{
+    while (_base_emitters->emit != NULL) {
+       printf("Added an emitter for %u %p\n", _base_emitters->op, _base_emitters);
+       hTabAddItemLong(into, _base_emitters->op, _base_emitters, _base_emitters);
+       _base_emitters++;
+    }
+}
+
+void izt_gen(iCode *iic)
+{
+    iCode *ic = iic;
+    int cln = 0;
+
+    _G.lines.head = NULL;
+    _G.lines.current = NULL;
+
+    // No debug info support.
+    for (; ic; ic = ic->next) {
+       const char *name;
+
+       // Print out the source file line number.
+       if (cln != ic->lineno) {
+           iemit("; %s %d", ic->filename, ic->lineno);
+           cln = ic->lineno ;
+       }
+
+       if (ic->generated) {
+           // Code has already been generated.  Skip.
+           continue;
+       }
+       if (_isResultRemat(ic)) {
+           // The code is spilt and remat. - no need to generate.
+           continue;
+       }
+       
+       // Print the friendly name of the operation, if it has one.
+       name = _findOpName(ic->op);
+       if (name) {
+           iemit("; %s", name);
+       }
+       else {
+           iemit("; warning: unrecognised operation name for %u", ic->op);
+       }
+
+       fflush(stdout);
+       // Now actually call the code generator.
+       // The current processor handler gets first try.
+       if (_tryEmittingiCode(_G.htabs.proc, ic)) {
+           // Yay.
+       }
+       else if (_tryEmittingiCode(_G.htabs.base, ic)) {
+           // Base handler took it.
+       }
+       else {
+           // None took it.  Warn the developer.
+           iemit("; warning: no handler for code %u", ic->op);
+       }
+    }
+
+    // Pass the code through the peephole optimiser.
+    if (!options.nopeep) {
+       peepHole(&_G.lines.head);
+    }
+
+    // And emit the remainder.
+    _printLines();
+}
+
diff --git a/src/izt/gen.h b/src/izt/gen.h
new file mode 100644 (file)
index 0000000..174cf2c
--- /dev/null
@@ -0,0 +1,24 @@
+// izt specific gen functions.
+#ifndef IZT_GEN_INCLUDE
+#define IZT_GEN_INCLUDE
+
+// Emit a line of code.
+void iemit(const char *format, ...);
+
+// Generic descripter for a function that can emit a type of iCode.
+typedef struct {
+    int op;
+    void (*emit)(iCode *ic);
+} EMITTER;
+
+// Call the base izt handler to handle this iCode.
+void izt_baseEmitter(iCode *ic);
+// Initialise the base emitter table.
+void izt_initBaseEmitters(hTab **into);
+// Add a NULL terminated array of emitters into the given hash table.
+void izt_addEmittersToHTab(hTab **into, EMITTER _base_emitters[]);
+// Initialise the emitter tables.
+void izt_initEmitters(void);
+
+#endif
+
diff --git a/src/izt/gen_generic.c b/src/izt/gen_generic.c
new file mode 100644 (file)
index 0000000..576fd08
--- /dev/null
@@ -0,0 +1,56 @@
+#include "izt.h"
+#include "gen.h"
+
+static void _genLabel(iCode *ic)
+{
+    iemit("!tlabeldef", IC_LABEL(ic)->key + 100);
+}
+
+static void _genGoto(iCode *ic)
+{
+    iemit("jp !tlabel", IC_LABEL(ic)->key+100);
+}
+
+static void _genFunction(iCode *ic)
+{
+    symbol *sym = OP_SYMBOL(IC_LEFT(ic));
+
+    // Create the function header
+    iemit("!functionheader", sym->name);
+    iemit("!functionlabeldef", sym->rname);
+
+    if (sym->stack) {
+       iemit("!enterx", sym->stack);
+    }
+    else {
+       iemit("!enter");
+    }
+}
+
+static void _genReturn(iCode *ic)
+{
+    if (IC_LEFT(ic)) {
+       // Has a return value.  Load it up.
+       iemit("; PENDING: call the generic loader to setup the return value.");
+    }
+
+    if (ic->next && ic->next->op == LABEL && IC_LABEL(ic->next) == returnLabel) {
+       // The next label is the return label.  Dont bother emitting a jump.
+    }
+    else {
+       iemit("jp !tlabel", returnLabel->key+100);
+    }
+}
+
+static EMITTER _base_emitters[] = {
+    { LABEL,           _genLabel },
+    { GOTO,            _genGoto },
+    { FUNCTION,                _genFunction },
+    { RETURN,          _genReturn },
+    { 0,               NULL }
+};
+
+void izt_initBaseEmitters(hTab **into)
+{
+    izt_addEmittersToHTab(into, _base_emitters);
+}
index c11a5b8aa366f1223d861295b70629ed5fd72840..16b539ad629df3761aa189a1dc7c41489b83d7fd 100644 (file)
@@ -13,6 +13,10 @@ static REG _i186_regs[] = {
     { 0, REG_ID_NONE,"??",  0, { REG_ID_NONE, REG_ID_NONE, REG_ID_NONE } }
 };
 
+static IZT_PORT _i186_port = {
+    _i186_regs
+};
+
 static char _defaultRules[] =
 {
     //#include "peeph.rul"
@@ -23,10 +27,67 @@ static char *_i186_keywords[] =     {
     NULL
 };
 
+// PENDING: A default set of mappings to make asm.c happy.
+static const ASM_MAPPING _asxxxx_z80_mapping[] = {
+    /* We want to prepend the _ */
+    { "area", ".area _%s" },
+    { "areacode", ".area _%s" },
+    { "areadata", ".area _%s" },
+    { "areahome", ".area _%s" },
+    { "*ixx", "%d(ix)" },
+    { "*iyx", "%d(iy)" },
+    { "*hl", "(hl)" },
+    { "di", "di" },
+    { "ldahli", 
+               "ld a,(hl)\n"
+               "\tinc\thl" },
+    { "ldahlsp", 
+               "ld hl,#%d\n"
+               "\tadd\thl,sp" },
+    { "ldaspsp", 
+               "ld hl,#%d\n"
+               "\tadd\thl,sp\n"
+               "\tld\tsp,hl" },
+    { "*pair", "(%s)" },
+    { "shortjp", "jp" },
+    { "enter", 
+               "push\tix\n"
+               "\tld\tix,#0\n"
+               "\tadd\tix,sp" },
+    { "enterx", 
+               "push\tix\n"
+               "\tld\tix,#0\n"
+               "\tadd\tix,sp\n"
+               "\tld\thl,#-%d\n"
+               "\tadd\thl,sp\n"
+               "\tld\tsp,hl" },
+    { "leave", 
+               "pop\tix\n"
+    },
+    { "leavex", 
+               "ld sp,ix\n"
+               "\tpop\tix\n"
+    },
+    { "pusha", 
+               "push af\n"
+               "\tpush\tbc\n"
+               "\tpush\tde\n"
+               "\tpush\thl"
+    },
+    { "adjustsp", "lda sp,-%d(sp)" },
+    { NULL, NULL }
+};
+
+static const ASM_MAPPINGS _asxxxx_z80 = {
+    &asm_asxxxx_mapping,
+    _asxxxx_z80_mapping
+};
+
 static void _i186_init(void)
 {
     asm_addTree(&asm_asxxxx_mapping);
-    izt_init(_i186_regs);
+    asm_addTree(&_asxxxx_z80);
+    izt_init(&_i186_port);
 }
 
 static void _i186_reset_regparm()
index 3a8fc8ce2016672677a3a11ad79e0c4f7335226e..968d278e558010f2eb63579031a4697c1f5d26af 100644 (file)
@@ -1,4 +1,5 @@
 #include <common.h>
+#include "gen.h"
 
 typedef enum {
     REG_ID_NONE,
@@ -54,9 +55,10 @@ typedef struct regs {
 
 typedef struct {
     REG *regs;
-} PORT_DATA;
+} IZT_PORT;
 
-PORT_DATA port_data;
+IZT_PORT *izt_port;
 
-void izt_init(REG *regs);
+void izt_init(IZT_PORT *port);
 void izt_assignRegisters (eBBlock **ebbs, int count);
+void izt_gen(iCode *ic);
index dcb6b0a4ea5f83041bf23971fb585504d9f02fc2..f01ec1b8ab1305d7e9d3c1a74cfddeeb0b1096d8 100644 (file)
@@ -23,7 +23,7 @@ static struct {
 
 static REG *_findRegById(REG_ID id)
 {
-    REG *r = port_data.regs;
+    REG *r = izt_port->regs;
     
     while (r->size) {
        if (r->id == id)
@@ -58,7 +58,7 @@ static REG *_getSubReg(REG *r, int size, int offset)
 
 static int _numRegsAvailable(int size)
 {
-    REG *r = port_data.regs;
+    REG *r = izt_port->regs;
     int ret = 0;
 
     while (r->size) {
@@ -99,7 +99,7 @@ static void _markAsFree(REG_ID id)
 
 static REG *_allocateReg(int size)
 {
-    REG *r = port_data.regs;
+    REG *r = izt_port->regs;
     
     while (r->size) {
        if (r->size == size && r->used == 0) {
@@ -155,7 +155,7 @@ static void _freeReg(REG *r)
 
 static void _freeAllRegs(viod)
 {
-    REG *r = port_data.regs;
+    REG *r = izt_port->regs;
 
     while (r->size) {
        r->used = 0;
@@ -165,7 +165,7 @@ static void _freeAllRegs(viod)
 
 static void _dumpRegs(void)
 {
-    REG *r = port_data.regs;
+    REG *r = izt_port->regs;
 
     while (r->size) {
        printf("%u\t%u\t%s\t%u\n", r->size, r->id, r->name, r->used);
@@ -173,10 +173,11 @@ static void _dumpRegs(void)
     }
 }
 
-void izt_init(REG *regs)
+void izt_init(IZT_PORT *port)
 {
-    wassert(regs);
-    port_data.regs = regs;
+    wassert(port && port->regs);
+    izt_port = port;
+    izt_initEmitters();
 }
 
 /// Lower register pressure by packing iTemps where possible.
@@ -641,11 +642,6 @@ static void _serialRegAssign(eBBlock **ebbs, int count)
     }
 }
 
-static void izt_gen(iCode *ic)
-{
-    printf("izt_gen\n");    
-}
-
 static DEFSETFUNC(_deallocStackSpil)
 {
     symbol *sym = item;