From 8b194ce521ec1d8a69f019f1b286a0a1c8ff2343 Mon Sep 17 00:00:00 2001 From: michaelh Date: Sun, 28 Jan 2001 03:12:00 +0000 Subject: [PATCH] Began adding the code generation framework. git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@542 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- src/izt/Makefile | 2 +- src/izt/clean.mk | 6 + src/izt/gen.c | 302 +++++++++++++++++++++++++++++++++++++++++- src/izt/gen.h | 24 ++++ src/izt/gen_generic.c | 56 ++++++++ src/izt/i186.c | 63 ++++++++- src/izt/izt.h | 8 +- src/izt/ralloc.c | 22 ++- 8 files changed, 460 insertions(+), 23 deletions(-) create mode 100644 src/izt/gen.h create mode 100644 src/izt/gen_generic.c diff --git a/src/izt/Makefile b/src/izt/Makefile index 5ae47209..1e6e5412 100644 --- a/src/izt/Makefile +++ b/src/izt/Makefile @@ -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../.. diff --git a/src/izt/clean.mk b/src/izt/clean.mk index e69de29b..4055fb30 100644 --- a/src/izt/clean.mk +++ b/src/izt/clean.mk @@ -0,0 +1,6 @@ +# + +clean: + rm -f $(LIB) *.o *~ port.a + +# End of src/z80/clean.mk diff --git a/src/izt/gen.c b/src/izt/gen.c index c6536360..7d13682c 100644 --- a/src/izt/gen.c +++ b/src/izt/gen.c @@ -1,12 +1,304 @@ #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 index 00000000..174cf2c0 --- /dev/null +++ b/src/izt/gen.h @@ -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 index 00000000..576fd08a --- /dev/null +++ b/src/izt/gen_generic.c @@ -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); +} diff --git a/src/izt/i186.c b/src/izt/i186.c index c11a5b8a..16b539ad 100644 --- a/src/izt/i186.c +++ b/src/izt/i186.c @@ -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() diff --git a/src/izt/izt.h b/src/izt/izt.h index 3a8fc8ce..968d278e 100644 --- a/src/izt/izt.h +++ b/src/izt/izt.h @@ -1,4 +1,5 @@ #include +#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); diff --git a/src/izt/ralloc.c b/src/izt/ralloc.c index dcb6b0a4..f01ec1b8 100644 --- a/src/izt/ralloc.c +++ b/src/izt/ralloc.c @@ -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; -- 2.30.2