diff options
| author | 2025-10-23 10:14:11 +0200 | |
|---|---|---|
| committer | 2025-10-23 10:14:11 +0200 | |
| commit | 37643338d176c7612bddef054ae46c8cba8e352b (patch) | |
| tree | 5789e49292bddf1fef57d5fcb3d1585bfef0b43c | |
| parent | 6149bc3a40e55ec6525aed42c9f2b2d480f20969 (diff) | |
amd64: load/store from abs address constants; movabs
| -rw-r--r-- | amd64/emit.c | 43 | ||||
| -rw-r--r-- | amd64/isel.c | 29 |
2 files changed, 51 insertions, 21 deletions
diff --git a/amd64/emit.c b/amd64/emit.c index 044098d..bf7813f 100644 --- a/amd64/emit.c +++ b/amd64/emit.c @@ -140,6 +140,12 @@ mkmemoper(union ref r) .cindex = addr->index.bits ? mkregoper(addr->index).reg : NOINDEX, .cshift = addr->shift, .disp = addr->disp); + } else if (isintcon(addr->base)) { + assert(!addr->disp); + return mkoper(OMEM, .base = NOBASE, + .index = addr->index.bits ? mkregoper(addr->index).reg : NOINDEX, + .disp = intconval(addr->base), + .shift = addr->shift); } else if (isaddrcon(addr->index)) { assert(!addr->shift); return mkoper(OSYM, .con = addr->index.i, @@ -351,13 +357,21 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o } } - if (mem.index == NOINDEX && mem.shift == 0) sib = 0; - else sib = 1; - mod = !mem.disp ? 0 /* disp = 0 -> mod = 00 */ - : (uint)(mem.disp + 128) < 256 ? 1 /* disp8 -> mod = 01 */ - : 2; /* disp32 -> mod = 10 */ - if (mod == 0 && (mem.base == RBP || mem.base == R13)) mod = 1; - if (mem.base == RSP || mem.base == R12) sib = 1; + if (mem.base != NOBASE) { + if (mem.index == NOINDEX && mem.shift == 0) sib = 0; + else sib = 1; + mod = !mem.disp ? 0 /* disp = 0 -> mod = 00 */ + : (uint)(mem.disp + 128) < 256 ? 1 /* disp8 -> mod = 01 */ + : 2; /* disp32 -> mod = 10 */ + if (mod == 0 && (mem.base == RBP || mem.base == R13)) mod = 1; + if (mem.base == RSP || mem.base == R12) sib = 1; + } else { + /* [disp + (index*s)] */ + sib = 1; + mem.base = RBP; + mod = 0; + assert(mem.index != RSP); + } D(opc, nopc); B(mod << 6 | (reg & 7) << 3 | (sib ? 4 : (mem.base & 7))); if (sib) { @@ -365,7 +379,7 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o 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*/)) { + else if (mod == 2 || (mod == 0 && mem.base == RBP/*RIP-rel*/) || (mod == 0 && sib && mem.base == RSP/*absolute*/)) { I32(mem.disp); } } @@ -842,11 +856,18 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope Xxor(pcode, kisint(cls) ? KI4 : cls, dst, dst); } else if (isaddrcon(val)) { if (ccopt.pic) GOTLoad: - /* for mov reg, [rip(sym@GOTPCREL)] */ + /* for mov reg, [rip(sym@GOTPCREL)] */ Xmov(pcode, cls, dst, mkoper(OSYM, .con = val.i, .cindex = NOINDEX)); else - /* for lea reg, [rip(sym)] */ + /* for lea reg, [rip(sym)] */ Xlea(pcode, cls, dst, mkoper(OSYM, .con = val.i, .cindex = NOINDEX)); + } else if (val.t == RXCON && in_range(concls(val), KI8, KPTR)) { + /* movabs */ + assert(dst.t == OREG && in_range(dst.reg, RAX, R15)); + B(0x48 | (dst.reg >> 3)); /* REX.W (+ REX.B) */ + B(0xB8 + (dst.reg & 0x7)); /* MOVABS r64, */ + wr64le(*pcode, intconval(val)); /* imm64 */ + *pcode += 8; } else { struct oper src = mkimmdatregoper(val); if (memcmp(&dst, &src, sizeof dst) != 0) @@ -971,7 +992,7 @@ emitinstr(uchar **pcode, struct function *fn, struct block *blk, int curi, struc assert(ins->reg-1 == dst.reg); X1(pcode, cls, dst); break; - case Omul: + case Omul: if (kisint(cls)) case Oumul: Ximul(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), ref2oper(ins->r)); diff --git a/amd64/isel.c b/amd64/isel.c index 65ccfb7..6041faf 100644 --- a/amd64/isel.c +++ b/amd64/isel.c @@ -71,12 +71,13 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi) *r = ZEROREF; else *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, con->cls, ZEROREF)); - } else if (kisflt(con->cls) || con->cls == KI8) { - /* float immediates & >32b immediates are loaded from memory */ + } else if (con->cls >= KI8) { + /* float immediates & 64bit immediates are loaded from memory */ uchar data[8]; uint siz = cls2siz[con->cls]; - if (con->cls == KI4) wr32le(data, con->i); - else if (con->cls != KF4) wr64le(data, con->i); + if (con->cls <= KPTR && in_range(ins->op, Ocopy, Omove)) /* in this case we can use movabs */ + return; + if (con->cls != KF4) wr64le(data, con->i); else { union { float f; int i; } pun = { con->f }; wr32le(data, pun.i); @@ -259,6 +260,18 @@ addarg4addrp(union ref r) } static void +loadstoreaddr(struct block *blk, union ref *r, int *curi) +{ + if (isimm32(*r)) { + *r = mkaddr((struct addr){.base = *r}); + } else if (!fuseaddr(r, blk, curi) && r->t != RTMP && r->t != RREG) { + *r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, *r)); + } else { + picfixsym(r, blk, curi); + } +} + +static void sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) { uint siz, alignlog2; @@ -392,14 +405,10 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) break; case Oloads1: case Oloadu1: case Oloads2: case Oloadu2: case Oloads4: case Oloadu4: case Oloadi8: case Oloadf4: case Oloadf8: - if (!fuseaddr(&ins->l, blk, curi) && ins->l.t != RTMP && ins->l.t != RREG) - ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, ins->l)); - picfixsym(&ins->l, blk, curi); + loadstoreaddr(blk, &ins->l, curi); break; case Ostore1: case Ostore2: case Ostore4: case Ostore8: - if (!fuseaddr(&ins->l, blk, curi) && ins->l.t != RTMP && ins->l.t != RREG) - ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, ins->l)); - picfixsym(&ins->l, blk, curi); + loadstoreaddr(blk, &ins->l, curi); if (isaddrcon(ins->r)) ins->r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, ins->r)); else |