#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();
+}
+