diff options
| -rw-r--r-- | amd64/emit.c | 109 | ||||
| -rw-r--r-- | amd64/isel.c | 6 | ||||
| -rw-r--r-- | elf.c | 1 | ||||
| -rw-r--r-- | regalloc.c | 11 |
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]) { @@ -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) { @@ -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)); |