summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2016-02-03 11:33:34 -0500
committerQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2016-02-03 11:33:34 -0500
commit09176bc115f92a5756796b4fe0f96c49ca5a3d0d (patch)
tree406012135b489dbd83b813b4d9f6638bff0e9152
parentcf3f6edb75a57a973f37b32a5aad192095b25d77 (diff)
downloadroux-09176bc115f92a5756796b4fe0f96c49ca5a3d0d.tar.gz
more revamp in emit
-rw-r--r--lisc/emit.c344
1 files changed, 170 insertions, 174 deletions
diff --git a/lisc/emit.c b/lisc/emit.c
index 4259b4a..0a6ec1e 100644
--- a/lisc/emit.c
+++ b/lisc/emit.c
@@ -42,6 +42,7 @@ static struct {
char *asm;
} omap[] = {
{ OAdd, Ka, "+add%k %0, %1" },
+ { OSub, Ka, "-sub%k %0, %1" },
{ OAnd, Ki, "+and%k %0, %1" },
{ OMul, Ki, "+imul%k %0, %1" },
{ ODiv, Ka, "-div%k %0, %1" },
@@ -81,7 +82,7 @@ static struct {
{ OXSet+Cne, Ki, "setnz %B=\n\tmovzb%k %B=, %=" },
};
-static char *rsub[][4] = {
+static char *rname[][4] = {
[RAX] = {"rax", "eax", "ax", "al"},
[RBX] = {"rbx", "ebx", "bx", "bl"},
[RCX] = {"rcx", "ecx", "cx", "cl"},
@@ -100,11 +101,13 @@ static char *rsub[][4] = {
[R15] = {"r15", "r15d", "r15w", "r15b"},
};
+
static int
slot(int s, Fn *fn)
{
struct { int i:14; } x;
+ /* sign extend s using a bitfield */
x.i = s;
assert(NAlign == 3);
if (x.i < 0)
@@ -133,55 +136,106 @@ emitcon(Con *con, FILE *f)
}
static void
-emitf(char *fmt, Ins *i, Fn *fn, FILE *f)
+regtoa(int reg, int sz)
+{
+ static char buf[6];
+
+ if (reg >= XMM0) {
+ sprintf(buf, "XMM%d", reg-XMM0);
+ return buf;
+ } else
+ return rname[reg][sz];
+}
+
+static Ref
+getarg(char c, Ins *i)
+{
+ switch (c) {
+ default:
+ diag("emit: 0, 1, = expected in format");
+ case '0':
+ return i->arg[0];
+ case '1':
+ return i->arg[1];
+ case '=':
+ return i->to;
+ }
+}
+
+static void emiti(Ins, Fn *, FILE *);
+
+static void
+emitcopy(Ref r1, Ref r2, int k, Fn *fn, FILE *f)
+{
+ Ins icp;
+
+ icp.op = OCopy;
+ icp.arg[0] = r2;
+ icp.to = r1;
+ icp.k = k;
+ emiti(icp, fn, f);
+}
+
+static void
+emitf(char *s, Ins *i, Fn *fn, FILE *f)
{
- static char stoa[] = "qlwb";
- va_list ap;
- char c, *s, *s1;
- int i, ty;
+ static char ktoa[][3] = {"l", "q", "ss", "sd"};
+ char c, *s1;
+ int i, sz;
Ref ref;
Mem *m;
Con off;
- va_start(ap, fmt);
ty = SWord;
- s = fmt;
fputc('\t', f);
+
+ switch (*s) {
+ case '+':
+ if (req(i->arg[1], i->to)) {
+ ref = i->arg[0];
+ i->arg[0] = i->arg[1];
+ i->arg[1] = ref;
+ }
+ /* fall through */
+ case '-':
+ if (req(i->arg[1], i->to) && !req(i->arg[0], i->to))
+ diag("emit: cannot convert to 2-address");
+ emitcopy(i->arg[0], i->to, i->cls, fn, f);
+ break;
+ }
Next:
while ((c = *s++) != '%')
if (!c) {
- va_end(ap);
fputc('\n', f);
return;
} else
fputc(c, f);
switch ((c = *s++)) {
default:
- diag("emit: unknown escape");
- case 'w':
- case 'W':
- i = va_arg(ap, int);
- ty = i ? SLong: SWord;
- if (0) {
- case 't':
- case 'T':
- ty = va_arg(ap, int);
- }
- if (c == 't' || c == 'w')
- fputc(stoa[ty], f);
+ diag("emit: invalid escape");
+ case '%':
+ fputc('%', f);
break;
- case 's':
- s1 = va_arg(ap, char *);
- fputs(s1, f);
+ case 'k':
+ fputs(ktoa[ty], f);
break;
- case 'R':
- ref = va_arg(ap, Ref);
+ case '0':
+ case '1':
+ case '=':
+ sz = KWIDE(i->cls) ? SLong : SWord;
+ s--;
+ /* fall through */
+ case 'D':
+ case 'S':
+ Ref:
+ c = *s++;
+ ref = getarg(c, i);
switch (rtype(ref)) {
default:
diag("emit: invalid reference");
case RTmp:
assert(isreg(ref));
- fprintf(f, "%%%s", rsub[ref.val][ty]);
+ fprintf(f, "%%%s", regtoa(ref.val, sz));
break;
case RSlot:
fprintf(f, "%d(%%rbp)", slot(ref.val, fn));
@@ -201,10 +255,10 @@ Next:
break;
fputc('(', f);
if (!req(m->base, R))
- fprintf(f, "%%%s", rsub[m->base.val][SLong]);
+ fprintf(f, "%%%s", regtoa(m->base.val, SLong));
if (!req(m->index, R))
fprintf(f, ", %%%s, %d",
- rsub[m->index.val][SLong],
+ regtoa(m->index.val, SLong),
m->scale
);
fputc(')', f);
@@ -215,8 +269,21 @@ Next:
break;
}
break;
+ case 'L':
+ sz = SLong;
+ goto Ref;
+ case 'W':
+ sz = SWord;
+ goto Ref;
+ case 'H':
+ sz = SShort;
+ goto Ref;
+ case 'B':
+ sz = SByte;
+ goto Ref;
case 'M':
- ref = va_arg(ap, Ref);
+ c = *s++;
+ ref = getarg(c, i);
switch (rtype(ref)) {
default:
diag("emit: invalid memory reference");
@@ -230,7 +297,7 @@ Next:
break;
case RTmp:
assert(isreg(ref));
- fprintf(f, "(%%%s)", rsub[ref.val][SLong]);
+ fprintf(f, "(%%%s)", regtoa(ref.val, SLong));
break;
}
break;
@@ -238,179 +305,104 @@ Next:
goto Next;
}
-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
-eins(Ins i, Fn *fn, FILE *f)
+emiti(Ins i, Fn *fn, FILE *f)
{
- static char *otoa[NOp] = {
- [OAdd] = "add",
- [OSub] = "sub",
- [OMul] = "imul",
- [OAnd] = "and",
- [OLoad+Tl] = "mov",
- [OLoad+Tsw] = "movsl",
- /* [OLoad+Tuw] treated manually */
- [OLoad+Tsh] = "movsw",
- [OLoad+Tuh] = "movzw",
- [OLoad+Tsb] = "movsb",
- [OLoad+Tub] = "movzb",
- };
- Ref r0, r1;
+ Ref r;
int64_t val;
switch (i.op) {
+ default:
+ Table:
+ /* most instructions are just pulled out of
+ * the table omap[], some special cases are
+ * detailed below */
+ //
+ // look in the table
+ //
+ diag("emit: unhandled instruction (3)");
+ case ONop:
+ /* just do nothing for nops, they are inserted
+ * by some passes */
+ break;
case OMul:
+ /* here, we try to use the 3-addresss form
+ * of multiplication when possible */
if (rtype(i.arg[1]) == RCon) {
- r0 = i.arg[1];
- r1 = i.arg[0];
- } else {
- r0 = i.arg[0];
- r1 = i.arg[1];
+ r = i.arg[0];
+ i.arg[0] = i.arg[1];
+ i.arg[1] = r;
}
- if (rtype(r0) == RCon && rtype(r1) == RTmp) {
- emitf(fn, f, "imul%w %R, %R, %R",
- i.wide, r0, r1, i.to);
+ if (KTYPE(i.cls) == 0 /* only available for ints */
+ && rtype(i.arg[0]) == RCon
+ && rtype(i.arg[1]) == RTmp) {
+ emitf("imul%k %0, %1, %=", &i, fn, f);
break;
}
- /* fall through */
- case OAdd:
+ goto Table;
case OSub:
- case OAnd:
+ /* we have to use the negation trick to handle
+ * some 3-address substractions */
if (req(i.to, i.arg[1])) {
- if (i.op == OSub) {
- emitf(fn, f, "neg%w %R", i.wide, i.to);
- emitf(fn, f, "add%w %R, %R",
- i.wide, i.arg[0], i.to);
- break;
- }
- i.arg[1] = i.arg[0];
- i.arg[0] = i.to;
+ emitf("neg%k %=", &i, fn, f);
+ emitf("add%k %0, %=", &i, fn, f);
+ break;
}
- if (!req(i.to, i.arg[0]))
- emitf(fn, f, "mov%w %R, %R",
- i.wide, i.arg[0], i.to);
- emitf(fn, f, "%s%w %R, %R", otoa[i.op],
- i.wide, i.arg[1], i.to);
- break;
+ goto Table;
case OCopy:
+ /* make sure we don't emit useless copies,
+ * also, we can use a trick to load 64-bits
+ * registers, it's detailed in my note below
+ * http://c9x.me/art/notes.html?09/19/2015 */
if (req(i.to, R) || req(i.arg[0], R))
break;
if (isreg(i.to)
- && i.wide
&& rtype(i.arg[0]) == RCon
+ && i.cls == Kl
&& fn->con[i.arg[0].val].type == CNum
&& (val = fn->con[i.arg[0].val].val) >= 0
&& val <= UINT32_MAX) {
- emitf(fn, f, "movl %R, %R", i.arg[0], i.to);
+ emitf("movl %W0, %W=", &i, fn, f);
} else if (!req(i.arg[0], i.to))
- emitf(fn, f, "mov%w %R, %R",
- i.wide, i.arg[0], i.to);
- break;
- case OStorel:
- case OStorew:
- case OStoreh:
- case OStoreb:
- emitf(fn, f, "mov%t %R, %M",
- i.op - OStorel, i.arg[0], i.arg[1]);
- break;
- case OLoad+Tuw:
- emitf(fn, f, "movl %M, %R", i.arg[0], i.to);
- break;
- case OLoad+Tsw:
- if (i.wide == 0) {
- emitf(fn, f, "movl %M, %R", i.arg[0], i.to);
- break;
- }
- case OLoad+Tl:
- case OLoad+Tsh:
- case OLoad+Tuh:
- case OLoad+Tsb:
- case OLoad+Tub:
- emitf(fn, f, "%s%w %M, %R", otoa[i.op],
- i.wide, i.arg[0], i.to);
- break;
- case OExt+Tuw:
- emitf(fn, f, "movl %R, %R", i.arg[0], i.to);
- break;
- case OExt+Tsw:
- case OExt+Tsh:
- case OExt+Tuh:
- case OExt+Tsb:
- case OExt+Tub:
- emitf(fn, f, "mov%s%t%s %R, %W%R",
- (i.op-OExt-Tsw)%2 ? "z" : "s",
- 1+(i.op-OExt-Tsw)/2,
- i.wide ? "q" : "l",
- i.arg[0], i.wide, i.to);
+ emitf("mov%k %0, %=", &i, fn, f);
break;
case OCall:
+ /* calls simply have a weird syntax in AT&T
+ * assembly... */
switch (rtype(i.arg[0])) {
default:
diag("emit: invalid call instruction");
case RCon:
- emitf(fn, f, "callq %M", i.arg[0]);
+ emitf("callq %0", &i, fn, f);
break;
case RTmp:
- emitf(fn, f, "call%w *%R", 1, i.arg[0]);
+ emitf("callq *%L0", &i, fn, f);
break;
}
break;
- case OAddr:
- emitf(fn, f, "lea%w %M, %R", i.wide, i.arg[0], i.to);
- break;
- case OSwap:
- emitf(fn, f, "xchg%w %R, %R", i.wide, i.arg[0], i.arg[1]);
- break;
- case OSign:
- if (req(i.to, TMP(RDX)) && req(i.arg[0], TMP(RAX))) {
- if (i.wide)
- fprintf(f, "\tcqto\n");
- else
- fprintf(f, "\tcltd\n");
- } else
- diag("emit: unhandled instruction (2)");
- break;
case OSAlloc:
- emitf(fn, f, "sub%w %R, %R", 1, i.arg[0], TMP(RSP));
+ /* there is no good reason why this is here
+ * maybe we should split OSAlloc in 2 different
+ * instructions depending on the result
+ */
+ emitf("subq %L0, %%rsp", &i, fn, f);
if (!req(i.to, R))
- emitf(fn, f, "mov%w %R, %R", 1, TMP(RSP), i.to);
- break;
- case OXPush:
- emitf(fn, f, "push%w %R", i.wide, i.arg[0]);
- break;
- case OXDiv:
- emitf(fn, f, "idiv%w %R", i.wide, i.arg[0]);
- break;
- case OXCmp:
- emitf(fn, f, "cmp%w %R, %R", i.wide, i.arg[0], i.arg[1]);
+ emitcopy(TMP(RSP), i.to, Kl, fn, f);
break;
- case OXTest:
- emitf(fn, f, "test%w %R, %R", i.wide, i.arg[0], i.arg[1]);
- break;
- case ONop:
- break;
- default:
- if (OXSet <= i.op && i.op <= OXSet1) {
- emitf(fn, f, "set%s%t %R",
- ctoa[i.op-OXSet], SByte, i.to);
- emitf(fn, f, "movzb%w %T%R, %W%R",
- i.wide, SByte, i.to, i.wide, i.to);
- break;
- }
- diag("emit: unhandled instruction (3)");
+ }
+}
+
+static int
+cneg(int cmp)
+{
+ switch (cmp) {
+ default: diag("emit: 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;
}
}
@@ -431,7 +423,7 @@ void
emitfn(Fn *fn, FILE *f)
{
Blk *b, *s;
- Ins *i;
+ Ins *i, itmp;
int *r, c, fs;
fprintf(f,
@@ -447,18 +439,22 @@ emitfn(Fn *fn, FILE *f)
if (fs)
fprintf(f, "\tsub $%d, %%rsp\n", fs);
for (r=rclob; r-rclob < NRClob; r++)
- if (fn->reg & BIT(*r))
- emitf(fn, f, "push%w %R", 1, TMP(*r));
+ if (fn->reg & BIT(*r)) {
+ itmp.arg[0] = TMP(*r);
+ emitf("pushq %L0", &itmp, fn, f);
+ }
for (b=fn->start; b; b=b->link) {
fprintf(f, ".L%s:\n", b->name);
- for (i=b->ins; i-b->ins < b->nins; i++)
+ for (i=b->ins; i!=&b->ins[b->nins]; i++)
eins(*i, fn, f);
switch (b->jmp.type) {
case JRet0:
for (r=&rclob[NRClob]; r>rclob;)
- if (fn->reg & BIT(*--r))
- emitf(fn, f, "pop%w %R", 1, TMP(*r));
+ if (fn->reg & BIT(*--r)) {
+ itmp.arg[0] = TMP(*r);
+ emitf("popq %L0", &itmp, fn, f);
+ }
fprintf(f,
"\tleave\n"
"\tret\n"