#include "lisc.h" enum { SLong, SWord, SShort, SByte }; static char *rsub[][4] = { [RXX] = {"BLACK CAT", "BROKEN MIRROR", "666", "NOOOO!"}, [RAX] = {"rax", "eax", "ax", "al"}, [RBX] = {"rbx", "ebx", "bx", "bl"}, [RCX] = {"rcx", "ecx", "cx", "cl"}, [RDX] = {"rdx", "edx", "dx", "dl"}, [RSI] = {"rsi", "esi", "si", "sil"}, [RDI] = {"rdi", "edi", "di", "dil"}, [RBP] = {"rbp", "ebp", "bp", "bpl"}, [RSP] = {"rsp", "esp", "sp", "spl"}, [R8 ] = {"r8" , "r8d", "r8w", "r8b"}, [R9 ] = {"r9" , "r9d", "r9w", "r9b"}, [R10] = {"r10", "r10d", "r10w", "r10b"}, [R11] = {"r11", "r11d", "r11w", "r11b"}, [R12] = {"r12", "r12d", "r12w", "r12b"}, [R13] = {"r13", "r13d", "r13w", "r13b"}, [R14] = {"r14", "r14d", "r14w", "r14b"}, [R15] = {"r15", "r15d", "r15w", "r15b"}, }; static char *ctoa[NCmp] = { [Ceq ] = "e", [Csle] = "le", [Cslt] = "l", [Csgt] = "g", [Csge] = "ge", [Cne ] = "ne", }; static char * rtoa(int r) { if (r < EAX) return rsub[r][SLong]; else return rsub[RBASE(r)][SWord]; } static int cneg(int cmp) { switch (cmp) { default: diag("cneg: unhandled comparison"); case Ceq: return Cne; case Csle: return Csgt; case Cslt: return Csge; case Csgt: return Csle; case Csge: return Cslt; case Cne: return Ceq; } } static void econ(Con *c, FILE *f) { switch (c->type) { case CAddr: fprintf(f, "%s", c->label); if (c->val) fprintf(f, "%+"PRId64, c->val); break; case CNum: fprintf(f, "%"PRId64, c->val); break; default: diag("econ: invalid constant"); } } static void eref(Ref r, Fn *fn, FILE *f) { switch (rtype(r)) { default: diag("emit: invalid reference"); case RTmp: assert(r.val < Tmp0); fprintf(f, "%%%s", rtoa(r.val)); break; case RMem: case RSlot: fprintf(f, "-%d(%%rbp)", 4 * r.val); break; case RCon: fprintf(f, "$"); econ(&fn->con[r.val], f); break; } } static void emem(Ref r, Fn *fn, FILE *f) { /* this function is now a hack * when full memory references * are supported, constants and * temporaries will not have * multiple meanings as they do * now */ switch (rtype(r)) { default: diag("emit: invalid memory reference"); case RMem: case RSlot: eref(r, fn, f); break; case RCon: econ(&fn->con[r.val], f); break; case RTmp: assert(r.val < EAX); fprintf(f, "("); eref(r, fn, f); fprintf(f, ")"); } } static void eop(char *op, Ref a, Ref b, Fn *fn, FILE *f) { fprintf(f, "\t%s ", op); eref(a, fn, f); if (!req(b, R)) { fprintf(f, ", "); eref(b, fn, f); } fprintf(f, "\n"); } static void eins(Ins i, Fn *fn, FILE *f) { static char *otoa[NOp] = { [OAdd] = "add", [OSub] = "sub", [OAnd] = "and", [OLoad] = "mov", [OLoadss] = "movsw", [OLoadus] = "movzw", [OLoadsb] = "movsb", [OLoadub] = "movzb", }; static char *stoa[] = { [OStorel - OStorel] = "q", [OStorew - OStorel] = "l", [OStores - OStorel] = "w", [OStoreb - OStorel] = "b", }; int reg; int64_t val; switch (i.op) { case OAdd: case OSub: case OAnd: if (req(i.to, i.arg[1])) { if (i.op == OSub) { eop("neg", i.to, R, fn, f); eop("add", i.arg[0], i.to, fn, f); break; } i.arg[1] = i.arg[0]; i.arg[0] = i.to; } if (!req(i.to, i.arg[0])) eop("mov", i.arg[0], i.to, fn, f); eop(otoa[i.op], i.arg[1], i.to, fn, f); break; case OCopy: if (i.to.val < EAX && rtype(i.arg[0]) == RCon) { val = fn->con[i.arg[0].val].val; if (0 <= val && val <= UINT32_MAX) { fprintf(f, "\tmov $%"PRId64", %%%s\n", val, rsub[i.to.val][SWord]); break; } } if (rtype(i.arg[0]) == RMem) { assert(rtype(i.to)==RTmp && i.to.valstart; b; b=b->link) { fprintf(f, ".L%s:\n", b->name); for (i=b->ins; i-b->ins < b->nins; i++) eins(*i, fn, f); switch (b->jmp.type) { case JRet: fprintf(f, "\tleave\n" "\tret\n" ); break; case JJmp: if (b->s1 != b->link) fprintf(f, "\tjmp .L%s\n", b->s1->name); break; default: c = b->jmp.type - JXJc; if (0 <= c && c <= NCmp) { if (b->link == b->s2) { s = b->s1; } else if (b->link == b->s1) { c = cneg(c); s = b->s2; } else diag("emit: unhandled jump (1)"); fprintf(f, "\tj%s .L%s\n", ctoa[c], s->name); break; } diag("emit: unhandled jump (2)"); } } }