diff options
Diffstat (limited to 'amd64/emit.c')
| -rw-r--r-- | amd64/emit.c | 85 |
1 files changed, 58 insertions, 27 deletions
diff --git a/amd64/emit.c b/amd64/emit.c index 70386be..3ccf595 100644 --- a/amd64/emit.c +++ b/amd64/emit.c @@ -6,18 +6,24 @@ * * Can be a register, a 32-bit immediate, * a memory reference [base + index * scale + disp], - * or a RIP-relative reference to some symbol + * or a relocatable reference to some symbol plus a displacement and maybe index*scale */ -enum operkind { ONONE, OREG, OIMM, OMEM, OCONR }; -enum { NOBASE = 99, NOINDEX = 99 }; +enum operkind { ONONE, OREG, OIMM, OMEM, OSYM }; +enum { NOBASE = 63, NOINDEX = 63 }; static struct oper { uchar t; - struct { uchar shift, index, base; }; /* OMEM */ + union { + struct { uchar base; }; /* OMEM */ + struct { uchar cindex : 6, cshift : 2; }; /* OSYM */ + }; + union { + struct { uchar index, shift; }; /* OMEM */ + ushort con; /* OSYM */ + }; union { uchar reg; /* OREG */ - int disp; /* OMEM */ + int disp; /* OMEM, OSYM */ int imm; /* OIMM */ - int con; /* OCONR, conht index*/ }; } ioper[MAXINSTR]; #define mkoper(t, ...) ((struct oper){(t), __VA_ARGS__}) @@ -36,7 +42,7 @@ ref2oper(union ref r) if (conht[r.i].cls == KI4) return mkoper(OIMM, .imm = conht[r.i].i); else if (!conht[r.i].cls) - return mkoper(OCONR, .con = r.i); + return mkoper(OSYM, .con = r.i, .cindex = NOINDEX); assert(0); case RADDR: return mkmemoper(r); default: assert(0); @@ -119,13 +125,24 @@ mkmemoper(union ref r) addmemoper(&mem, mkoper(OIMM, .imm = addr->disp)); return mem; } + if (isaddrcon(addr->base)) { + return mkoper(OSYM, .con = addr->base.i, + .cindex = addr->index.bits ? mkregoper(addr->index).reg : NOINDEX, + .cshift = addr->shift, + .disp = addr->disp); + } else if (isaddrcon(addr->index)) { + assert(!addr->shift); + return mkoper(OSYM, .con = addr->index.i, + .cindex = addr->base.bits ? mkregoper(addr->base).reg : NOINDEX, + .disp = addr->disp); + } return mkoper(OMEM, .base = addr->base.bits ? mkregoper(addr->base).reg : NOBASE, .index = addr->index.bits ? mkregoper(addr->index).reg : NOINDEX, .disp = addr->disp, .shift = addr->shift); } else if (r.t == RXCON) { assert(!conht[r.i].cls); - return mkoper(OCONR, .con = r.i); + return mkoper(OSYM, .con = r.i, .cindex = NOINDEX); } else { return mkoper(OMEM, .base = isregref(r) ? ref2oper(r).reg : NOBASE, .index = NOINDEX, @@ -200,8 +217,8 @@ opermatch(enum operpat pat, struct oper oper) case PI16: return oper.t == OIMM && (short)oper.imm == oper.imm; case PI32: return oper.t == OIMM; case PU32: return oper.t == OIMM && oper.imm >= 0; - case PMEM: return in_range(oper.t, OMEM, OCONR); - case PSYM: return oper.t == OCONR; + case PMEM: return in_range(oper.t, OMEM, OSYM); + case PSYM: return oper.t == OSYM; } assert(0); } @@ -273,19 +290,33 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o mem = dst; reg = en->ext; Mem: - if (mem.t == OCONR) { /* RIP-relative addressing with relocation */ - mod = 0; - mem.disp = mem.con; - mem.base = RBP; - sib = 0; - if (rex) B(0x40 | rex); - goto EmitMem; + if (mem.t == OMEM) { + if (mem.base != NOBASE) rex |= mem.base >> 3; /* REX.B */ + if (mem.index != NOINDEX) rex |= mem.index >> 3 << 1; /* REX.X */ + } else { + if (mem.cindex != NOINDEX) rex |= mem.cindex >> 3 << 1; /* REX.X */ } - rex |= mem.base >> 3; /* REX.B */ - if (mem.t != EN_M) + if (en->operenc != EN_M) rex |= (reg >> 3) << 2; /* REX.R */ if (rex) B(0x40 | rex); else if (en->r8 && in_range(reg, RSP, RDI)) B(0x40); + + if (mem.t == OSYM) { + /* XXX PIC */ + D(opc, nopc); + if (mem.cindex == NOINDEX) { + /* %rip(var) */ + B(/*mod 0*/ (reg & 7) << 3 | RBP); + objreloc(xcon2sym(mem.con), REL_PCREL32, Stext, *pcode - objout.textbegin, -4 + mem.disp); + } else { + /* var(,%reg,shift) */ + B(/*mod 0*/ (reg & 7) << 3 | RSP); + B(mem.cshift << 6 | mem.cindex << 3 | RBP); /* SIB [index*s + disp32] */ + objreloc(xcon2sym(mem.con), REL_ABS32S, Stext, *pcode - objout.textbegin, mem.disp); + } + I32(0); + break; + } if (mem.index == NOINDEX && mem.shift == 0) sib = 0; else sib = 1; mod = !mem.disp ? 0 /* disp = 0 -> mod = 00 */ @@ -293,17 +324,12 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o : 2; /* disp32 -> mod = 10 */ if (mod == 0 && (mem.base == RBP || mem.base == R13)) mod = 1; if (mem.base == RSP || mem.base == R12) sib = 1; - EmitMem: D(opc, nopc); B(mod << 6 | (reg & 7) << 3 | (sib ? 4 : mem.base)); if (sib) B(mem.shift << 6 | (mem.index & 7) << 3 | (mem.base & 7)); if (mod == 1) B(mem.disp); else if (mod == 2 || (mod == 0 && mem.base == RBP/*RIP-rel*/)) { - if (mem.t == OCONR) { - objreloc(xcon2sym(mem.con), REL_PCREL32, Stext, *pcode - objout.textbegin, -4); - mem.disp = 0; - } I32(mem.disp); } if (en->operenc == EN_MI8) B(src.imm); @@ -335,7 +361,7 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o case EN_R32: if (rex) B(0x40 | rex); D(opc, nopc); - assert(dst.t == OCONR); + assert(dst.t == OSYM); objreloc(xcon2sym(dst.con), REL_PCREL32, Stext, *pcode - objout.textbegin, -4); I32(0); break; @@ -457,6 +483,10 @@ DEFINSTR2(Xshl, {4|8, PGPR, PI32, "\xC1", EN_RI8, .ext=4}, /* SHL r32/64, imm */ {4|8, PGPR, PRCX, "\xD3", EN_R, .ext=4}, /* SHL r32/64, CL */ ) +DEFINSTR2(Xcvtss2sd, + {-1, PFPR, PFPR, "\xF3\x0F\x5A", EN_RR}, /* CVTSS2SD xmm, xmm */ + {-1, PFPR, PMEM, "\xF3\x0F\x5A", EN_RM}, /* CVTSS2SD xmm, xmm */ +) DEFINSTR1(Xinc, {4|8, PGPR, 0, "\xFF", EN_R, .ext=0} /* INC r32/64 */ ) @@ -641,8 +671,8 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope } else if (val.bits == ZEROREF.bits && dst.t == OREG && !flagslivep(blk, curi)) { /* dst = 0 -> xor dst, dst; but only if it is ok to clobber flags */ Xxor(pcode, kisint(cls) ? KI4 : cls, dst, dst); - } else if (val.t == RXCON && conht[val.i].isdat && !conht[val.i].deref) { - Xlea(pcode, cls, dst, mkoper(OCONR, .con = val.i)); + } else if (isaddrcon(val)) { + Xlea(pcode, cls, dst, mkoper(OSYM, .con = val.i, .cindex = NOINDEX)); } else { struct oper src = mkimmdatregoper(val); if (memcmp(&dst, &src, sizeof dst) != 0) @@ -702,6 +732,7 @@ emitinstr(uchar **pcode, struct function *fn, struct block *blk, int curi, struc case Oloadu4: src = mkmemoper(ins->l); Movzxl: Xmov(pcode, KI4, reg2oper(ins->reg-1), src); break; case Oloadf4: case Oloadf8: Xmov(pcode, cls, reg2oper(ins->reg-1), mkmemoper(ins->l)); break; case Oloadi8: Xmov(pcode, KI8, reg2oper(ins->reg-1), mkmemoper(ins->l)); break; + case Ocvtf4f8: Xcvtss2sd(pcode, KF4, reg2oper(ins->reg-1), mkdatregoper(ins->l)); break; case Oadd: dst = mkregoper(ins->l); if (kisflt(cls)) { |