aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--amd64/emit.c109
-rw-r--r--amd64/isel.c6
-rw-r--r--elf.c1
-rw-r--r--regalloc.c11
4 files changed, 98 insertions, 29 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index 3ccf595..8f3286a 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -189,6 +189,7 @@ enum operenc {
EN_MI16, /* mem, imm16 with /x */
EN_MI32, /* mem, imm32 with /x */
EN_OI, /* reg, imm32 with op + reg */
+ EN_I8, /* imm8 */
EN_I32, /* imm32 */
EN_R32, /* rel32 */
};
@@ -315,7 +316,7 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o
objreloc(xcon2sym(mem.con), REL_ABS32S, Stext, *pcode - objout.textbegin, mem.disp);
}
I32(0);
- break;
+ goto Imm;
}
if (mem.index == NOINDEX && mem.shift == 0) sib = 0;
else sib = 1;
@@ -332,6 +333,7 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o
else if (mod == 2 || (mod == 0 && mem.base == RBP/*RIP-rel*/)) {
I32(mem.disp);
}
+ Imm:
if (en->operenc == EN_MI8) B(src.imm);
if (en->operenc == EN_MI16) I16(src.imm);
if (en->operenc == EN_MI32) I32(src.imm);
@@ -353,6 +355,11 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o
D(opc, nopc - 1);
I32(src.imm);
break;
+ case EN_I8:
+ if (rex) B(0x40 | rex);
+ D(opc, nopc);
+ B(src.imm);
+ break;
case EN_I32:
if (rex) B(0x40 | rex);
D(opc, nopc);
@@ -470,6 +477,13 @@ DEFINSTR2(Xsubf,
{4, PFPR, PMEM, "\xF3\x0F\x5C", EN_RM}, /* SUBSS xmm, m32 */
{8, PFPR, PMEM, "\xF2\x0F\x5C", EN_RM}, /* SUBSD xmm, m64 */
)
+DEFINSTR2(Xand,
+ {4|8, PGPR, PGPR, "\x23", EN_RR}, /* AND r32/64, r32/64 */
+ {4|8, PGPR, PI8, "\x83", EN_RI8, .ext=4}, /* AND r32/64, imm8 */
+ {4|8, PRAX, PI32, "\x25", EN_I32}, /* AND eax/rax, imm */
+ {4|8, PGPR, PI32, "\x81", EN_RI32, .ext=4}, /* AND r32/64, imm */
+ { 8, PGPR, PMEM, "\x23", EN_RM}, /* AND r64, m64 */
+)
DEFINSTR2(Xxor,
{4|8, PGPR, PGPR, "\x33", EN_RR}, /* XOR r32/64, r32/64 */
{4|8, PGPR, PI8, "\x83", EN_RI8, .ext=6}, /* XOR r32/64, imm8 */
@@ -493,6 +507,9 @@ DEFINSTR1(Xinc,
DEFINSTR1(Xdec,
{4|8, PGPR, 0, "\xFF", EN_R, .ext=1} /* DEC r32/64 */
)
+DEFINSTR1(Xneg,
+ {4|8, PGPR, 0, "\xF7", EN_R, .ext=3} /* NEG r32/64 */
+)
DEFINSTR1(Xidiv,
{4|8, PGPR, 0, "\xF7", EN_R, .ext=7}, /* IDIV r32/64 */
{4|8, PMEM, 0, "\xF7", EN_M, .ext=7}, /* IDIV m32/64 */
@@ -510,8 +527,42 @@ DEFINSTR2(Xcmp,
{ 8, PGPR, PMEM, "\x3B", EN_RM}, /* CMP r64, m64 */
)
DEFINSTR2(Xtest,
- {4|8, PGPR, PGPR, "\x85", EN_RR}, /* TEST r32/64, r32/64 */
+ {4|8, PRAX, PI8, "\xA8", EN_I8}, /* TEST AL, imm8 */
+ {4, PRAX, PI32, "\xA9", EN_I32}, /* TEST EAX, imm32 */
+ { 8, PRAX, PU32, "\xA9", EN_I32}, /* TEST EAX, imm32 */
+ { 8, PRAX, PI32, "\xA9", EN_I32}, /* TEST RAX, imm32 */
+ {4|8, PGPR, PI8, "\xF6", EN_RI8, .r8=1}, /* TEST r8, imm8 */
+ {4|8, PGPR, PGPR, "\x85", EN_RR}, /* TEST r32/64, r32/64 */
+ {4|8, PGPR, PMEM, "\x85", EN_RM}, /* TEST r32/64, m32/64 */
+)
+
+DEFINSTR2(Ximul2,
+ {4|8, PGPR, PGPR, "\x0F\xAF", EN_RR}, /* MUL r32/64, r32/64 */
+ {4|8, PGPR, PMEM, "\x0F\xAF", EN_RM}, /* MUL r32/64, m32/64 */
)
+static void
+Xmul(uchar **pcode, enum irclass k, struct oper dst, struct oper s1, struct oper s2)
+{
+ static const struct desc imm8tab[] = {
+ {4|8, PGPR, PGPR, "\x6B", EN_RR}, /* MUL r32/64, r32/64, (imm8) */
+ {4|8, PGPR, PMEM, "\x6B", EN_RM}, /* MUL r32/64, m32/64, (imm8) */
+ }, imm32tab[] = {
+ {4|8, PGPR, PGPR, "\x69", EN_RR}, /* MUL r32/64, r32/64, (imm32) */
+ {4|8, PGPR, PMEM, "\x69", EN_RM}, /* MUL r32/64, m32/64, (imm32) */
+ };
+ if (!memcmp(&dst, &s1, sizeof dst) && s2.t != OIMM) {
+ Ximul2(pcode, k, dst, s2);
+ return;
+ }
+ assert(s2.t == OIMM);
+ if ((uint)(s2.imm + 128) < 256) {
+ encode(pcode, imm8tab, arraylength(imm8tab), k, dst, s1);
+ B(s2.imm);
+ } else {
+ encode(pcode, imm32tab, arraylength(imm32tab), k, dst, s1);
+ I32(s2.imm);
+ }
+}
enum cc {
CCO = 0x0, /* OF = 1*/
@@ -685,6 +736,7 @@ static const uchar icmpop2cc[] = {
[Oequ] = CCE, [Oneq] = CCNE,
[Olth] = CCL, [Ogth] = CCG, [Olte] = CCLE, [Ogte] = CCGE,
[Oulth] = CCB, [Ougth] = CCA, [Oulte] = CCBE, [Ougte] = CCGE,
+ [Oand] = CCNE, [Osub] = CCNE,
};
/* condition code for TEST reg,reg (compare with zero) */
static const uchar icmpzero2cc[] = {
@@ -747,8 +799,26 @@ emitinstr(uchar **pcode, struct function *fn, struct block *blk, int curi, struc
Xlea(pcode, cls, dst, mem);
}
break;
- case Osub: X = kisint(cls) ? Xsub : Xsubf; goto ALU2;
+ case Osub:
+ dst = mkregoper(ins->l);
+ if (kisflt(cls)) {
+ Xsubf(pcode, cls, dst, mkimmdatregoper(ins->r));
+ } else if (ins->reg-1 == dst.reg) { /* two-address */
+ Xsub(pcode, cls, dst, mkimmdatregoper(ins->r));
+ } else {
+ assert(isintcon(ins->r));
+ Xlea(pcode, cls, dst,
+ mkoper(OMEM, .base = mkregoper(ins->l).reg, .index = NOINDEX, .disp = -intconval(ins->r)));
+ }
+ break;
case Oshl: X = Xshl; goto ALU2;
+ case Oand:
+ if (!ins->reg) {
+ Xtest(pcode, cls, mkregoper(ins->l), mkimmdatregoper(ins->r));
+ break;
+ }
+ X = Xand;
+ goto ALU2;
case Oxor: X = Xxor; goto ALU2;
ALU2:
dst = mkregoper(ins->l);
@@ -757,11 +827,17 @@ emitinstr(uchar **pcode, struct function *fn, struct block *blk, int curi, struc
break;
case Oxinc: X1 = Xinc; goto ALU1;
case Oxdec: X1 = Xdec; goto ALU1;
+ case Oneg: X1 = Xneg; goto ALU1;
ALU1:
dst = mkregoper(ins->l);
assert(ins->reg-1 == dst.reg);
X1(pcode, cls, dst);
break;
+ case Omul:
+ if (kisint(cls)) {
+ Xmul(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), ref2oper(ins->r));
+ } else assert(0);
+ break;
case Odiv:
switch (cls) {
default: assert(0);
@@ -837,22 +913,17 @@ emitbranch(uchar **pcode, struct block *blk)
if (blk->s2) {
/* conditional branch.. */
union ref arg = blk->jmp.arg[0];
-
- if (!arg.bits) /* implicit by ZF */
- cc = CCNZ;
- else {
- struct instr *ins;
- assert(arg.t == RTMP);
- ins = &instrtab[arg.i];
- assert(oiscmp(ins->op));
- /* TODO handle float cmps */
- if (ins->r.bits != ZEROREF.bits) {
- /* for CMP instr */
- cc = icmpop2cc[ins->op];
- } else {
- /* for TEST instr, which modifies ZF and SF and sets CF = OF = 0 */
- cc = icmpzero2cc[ins->op];
- }
+ struct instr *ins;
+ assert(arg.t == RTMP);
+ ins = &instrtab[arg.i];
+ assert(oiscmp(ins->op) || ins->op == Oand || ins->op == Osub);
+ /* TODO handle float cmps */
+ if (ins->r.bits != ZEROREF.bits) {
+ /* for CMP instr */
+ cc = icmpop2cc[ins->op];
+ } else {
+ /* for TEST instr, which modifies ZF and SF and sets CF = OF = 0 */
+ cc = icmpzero2cc[ins->op];
}
if (blk->s1 == blk->lnext) {
/* if s1 is next adjacent block, swap s1,s2 and flip condition to emit a
diff --git a/amd64/isel.c b/amd64/isel.c
index 911bb2e..da5a128 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -397,10 +397,8 @@ seljmp(struct function *fn, struct block *blk)
c = insertinstr(blk, blk->ins.n, mkinstr(Ocopy, cls, c));
sel(fn, &instrtab[c.i], blk, &curi);
}
- if (iflagsrc == c.i) {
- if (!oiscmp(instrtab[c.i].op)) {
- blk->jmp.arg[0] = NOREF; /* implicit by zero flag */
- }
+ if (iflagsrc == c.i /* test cmp */
+ && (oiscmp(instrtab[c.i].op) || instrtab[c.i].op == Oand || instrtab[c.i].op == Osub)) {
instrtab[c.i].keep = 1;
} else {
if (!(opflags[instrtab[c.i].op] & ZF) || c.i != blk->ins.p[blk->ins.n - 1]) {
diff --git a/elf.c b/elf.c
index d269531..399434b 100644
--- a/elf.c
+++ b/elf.c
@@ -449,7 +449,6 @@ elffini(struct wbuf *out)
putsym(out, sym);
}
-
/* rel.* */
assert(relocs.n == ntextrel + nrodatarel + ndatarel);
for (enum section s = Stext; s <= Sbss; ++s) {
diff --git a/regalloc.c b/regalloc.c
index 2ecee01..096ad87 100644
--- a/regalloc.c
+++ b/regalloc.c
@@ -416,8 +416,8 @@ emitmove(enum irclass k, struct alloc dst, struct alloc src, struct block *blk,
case KF4: mv.op = Oloadf4; break;
case KF8: mv.op = Oloadf8; break;
}
- mv.l = mkref(RICON, dst.a*8);
- mv.reg = src.a;
+ mv.l = mkref(RICON, src.a*8);
+ mv.reg = dst.a+1;
addstkslotref(insertinstr(blk, curi, mv));
}
}
@@ -563,8 +563,9 @@ resolve(struct function *fn, struct bbrm *bbrm, struct block *blk, struct block
}
pmadd(insrescls(instrtab[var]), *alloc, *alloc2);
}
- if (!instrtab[var].reg && alloc->t == AREG)
+ if (!instrtab[var].reg && alloc->t == AREG) {
instrtab[var].reg = alloc->a + 1;
+ }
}
if (n) emitpm(n);
@@ -656,7 +657,7 @@ regalloc(struct function *fn)
for (int i = 0; i < 2; ++i) {
if (!blk->jmp.arg[i].bits) break;
/* do not allocate a reg for a cmp op used a branch argument, since it's a pseudo op */
- if (blk->jmp.t == Jb && blk->jmp.arg[i].t == RTMP && oiscmp(instrtab[blk->jmp.arg[i].i].op))
+ if (blk->jmp.t == Jb && blk->jmp.arg[i].t == RTMP && instrtab[blk->jmp.arg[i].i].keep)
break;
use(&ra, blk, curi, -blk->jmp.t,
blk->jmp.t == Jret ? fn->abiret[i].reg : -1,
@@ -717,7 +718,7 @@ regalloc(struct function *fn)
goto Nop;
} else if (ins->op == Ocopy && ins->l.t == RREG && ins->reg-1 == ins->l.i) {
goto Nop;
- } else if (ins->inplace && ins->l.t == RREG && ins->reg-1 != ins->l.i) {
+ } else if (ins->inplace && ins->l.t == RREG && ins->reg && ins->reg-1 != ins->l.i) {
/* fixup in-place (two-address) instructions */
allnops = 0;
insertinstr(blk, i++, mkmove(ins->cls, ins->reg-1, ins->l.i));