aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-10-23 10:14:11 +0200
committerlemon <lsof@mailbox.org>2025-10-23 10:14:11 +0200
commit37643338d176c7612bddef054ae46c8cba8e352b (patch)
tree5789e49292bddf1fef57d5fcb3d1585bfef0b43c /amd64
parent6149bc3a40e55ec6525aed42c9f2b2d480f20969 (diff)
amd64: load/store from abs address constants; movabs
Diffstat (limited to 'amd64')
-rw-r--r--amd64/emit.c43
-rw-r--r--amd64/isel.c29
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