aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-04-12 11:49:17 +0200
committerlemon <lsof@mailbox.org>2026-04-12 11:51:25 +0200
commitf13b3021eb273af3093a498fb3b09271546ae3cc (patch)
tree712ff8a744a5126748858658485939054c249107 /src
parent104c0812ac073ceab75c45f82c1341fd5b8aab80 (diff)
aarch64: fix stack frame layout, again
Turns out hardware enforces SP 16-bit alignment in every SP relative load/store, but QEMU doesn't emulate this.
Diffstat (limited to 'src')
-rw-r--r--src/t_aarch64_emit.c67
-rw-r--r--src/t_aarch64_isel.c5
2 files changed, 37 insertions, 35 deletions
diff --git a/src/t_aarch64_emit.c b/src/t_aarch64_emit.c
index ca251f0..bdbb0b0 100644
--- a/src/t_aarch64_emit.c
+++ b/src/t_aarch64_emit.c
@@ -54,10 +54,10 @@ static inline bool usegot(int c)
typedef struct Frame {
regset save;
struct RPair { uchar a,b; } pairs[10];
- uchar single[3];
- uint nfpairs, ngpairs;
+ uchar single[2];
+ int nfpairs, ngpairs, nsingle;
bool usefp;
- int size;
+ int size, stksiz;
} Frame;
static Frame frame;
@@ -65,8 +65,13 @@ static Frame frame;
static int
stackdisp(int i)
{
- return i < 0 ? frame.size - i - 8 /* arg */
- : frame.size - i + 16*frame.usefp;
+ if (frame.usefp) {
+ return i < 0 ? frame.size - i - 8 /* arg */
+ : 16 + i;
+ } else {
+ return i < 0 ? frame.size - i - 8 /* arg */
+ : i;
+ }
}
static Oper
@@ -935,6 +940,7 @@ prologue(uchar **pcode, Frame *frame, Function *fn)
{
*frame = (Frame){0};
regset save = frame->save = fn->regusage & mctarg->rcallee;
+ Oper adr = mkoper(OMEM, .m = {.mode = APREIDX, .base = SP, .disp = -16});
if (save) {
int prev = 0;
struct RPair *p = frame->pairs;
@@ -946,13 +952,8 @@ prologue(uchar **pcode, Frame *frame, Function *fn)
prev = 0;
} else prev = reg;
}
- uint ngpr = popcnt(save & (BIT(30)-1));
if (prev) {
- frame->single[0] = prev;
- if (ngpr & 1) {
- frame->single[1] = prev = lowestsetbit(save);
- rsclr(&save, prev);
- }
+ frame->single[frame->nsingle++] = prev;
prev = 0;
}
for (uint reg = R(19); reg < FP; ++reg) {
@@ -963,32 +964,23 @@ prologue(uchar **pcode, Frame *frame, Function *fn)
prev = 0;
} else prev = reg;
}
- if (prev) frame->single[2] = prev;
+ if (prev) frame->single[frame->nsingle++] = prev;
p = frame->pairs;
- Oper adr = mkoper(OMEM, .m = {.mode = APREIDX, .base = SP, .disp = -16});
for (int i = 0; i < frame->nfpairs; ++i, ++p) {
Xfstp(pcode, KF64, reg2oper(p->a), reg2oper(p->b), adr);
frame->size += 16;
}
- adr.m.disp = -8;
- int rx;
- if ((rx = frame->single[0])) {
- Xfstr(pcode, KF64, reg2oper(rx), adr);
- frame->size += 8;
- }
- if ((rx = frame->single[1])) {
- Xstr(pcode, KPTR, reg2oper(rx), adr);
- frame->size += 8;
- }
- adr.m.disp = -16;
for (int i = 0; i < frame->ngpairs; ++i, ++p) {
Xstp(pcode, KPTR, reg2oper(p->a), reg2oper(p->b), adr);
frame->size += 16;
}
- adr.m.disp = -8;
- if ((rx = frame->single[2])) {
- Xstr(pcode, KPTR, reg2oper(rx), adr);
+ for (int i = 0; i < frame->nsingle; ++i) {
+ int r = frame->single[i];
+ int off = -8 - i * 8;
+ (r < 32 ? Xstr : Xfstr)(pcode, r < 32 ? KI64 : KF64, reg2oper(r),
+ mkoper(OMEM, .m = {.mode = AIMMIDX, .base = SP, .disp = off}));
+ adr.m.disp -= 8;
frame->size += 8;
}
}
@@ -999,33 +991,38 @@ prologue(uchar **pcode, Frame *frame, Function *fn)
frame->size += fn->stksiz;
if ((frame->usefp = !fn->isleaf)) {
frame->size += 16;
- Oper adr = mkoper(OMEM, .m = {.mode = APREIDX, .base = SP, .disp = -16 - fn->stksiz});
+ adr.m.disp -= fn->stksiz;
Xstp(pcode, KPTR, reg2oper(FP), reg2oper(LR), adr);
Xadd(pcode, KPTR, reg2oper(R(29)), reg2oper(SP), mkoper(OIMM, {0})); /* MOV x29,sp */
} else if (fn->stksiz) {
- Xsub(pcode, KPTR, reg2oper(SP), reg2oper(SP), mkoper(OIMM, .imm = fn->stksiz));
+ Xsub(pcode, KPTR, reg2oper(SP), reg2oper(SP), mkoper(OIMM, .imm = fn->stksiz + 8*frame->nsingle));
}
+ frame->stksiz = fn->stksiz;
}
static void
epilogue(uchar **pcode, Function *fn, Frame *frame)
{
- Oper adr = mkoper(OMEM, .m = {.mode = APOSTIDX, .base = SP, .disp = 16+fn->stksiz});
+ Oper adr = mkoper(OMEM, .m = {.mode = APOSTIDX, .base = SP, .disp = 16+fn->stksiz+8*frame->nsingle});
if (frame->usefp) {
Xldp(pcode, KPTR, reg2oper(FP), reg2oper(LR), adr);
} else if (fn->stksiz) {
- Xadd(pcode, KPTR, reg2oper(SP), reg2oper(SP), mkoper(OIMM, .imm = fn->stksiz));
+ Xadd(pcode, KPTR, reg2oper(SP), reg2oper(SP), mkoper(OIMM, .imm = fn->stksiz+8*frame->nsingle));
}
if (frame->save) {
struct RPair *p = frame->pairs + frame->nfpairs + frame->ngpairs - 1;
- adr.m.disp = 8;
- if (frame->single[2]) Xldr(pcode, KF64, reg2oper(frame->single[2]), adr);
+ for (int i = 0; i < frame->nsingle; ++i) {
+ int r = frame->single[i];
+ int off = -8-8*i;
+ (r < 32 ? Xldr : Xfldr)(pcode, r < 32 ? KI64 : KF64, reg2oper(r),
+ mkoper(OMEM, .m = {.mode = AIMMIDX, .base = SP, .disp = off}));
+ adr.m.disp -= 8;
+ frame->size += 8;
+ }
adr.m.disp = 16;
for (int i = 0; i < frame->ngpairs; ++i, --p)
Xldp(pcode, KPTR, reg2oper(p->a), reg2oper(p->b), adr);
adr.m.disp = 8;
- if (frame->single[1]) Xldr(pcode, KPTR, reg2oper(frame->single[1]), adr);
- if (frame->single[0]) Xfldr(pcode, KF64, reg2oper(frame->single[0]), adr);
adr.m.disp = 16;
for (int i = 0; i < frame->nfpairs; ++i, --p)
Xfldp(pcode, KF64, reg2oper(p->a), reg2oper(p->b), adr);
diff --git a/src/t_aarch64_isel.c b/src/t_aarch64_isel.c
index 178fa23..1d49012 100644
--- a/src/t_aarch64_isel.c
+++ b/src/t_aarch64_isel.c
@@ -264,6 +264,10 @@ aadd(IRAddr *addr, Block *blk, int *curi, Ref r, uint siz/*1,2,4,8*/)
if (r.t == RSTACK) {
if (addr->base.bits) goto Ref;
addr->base = r;
+ } else if (r.t == RADDR) {
+ if (!addr->base.bits && !addr->index.bits && !addr->disp) {
+ *addr = addrtab.p[r.i];
+ } else goto Ref;
} else if (r.t == RTMP) {
Instr *ins = &instrtab[r.i];
if (ins->op == Oadd) {
@@ -534,6 +538,7 @@ seljmp(Function *fn, Block *blk)
if (blk->jmp.arg[1].bits) {
r = mkref(RREG, fn->abiret[1].reg);
ins = &instrtab[insertinstr(blk, blk->ins.n, mkinstr2(Omove, fn->abiret[1].ty.cls, r, blk->jmp.arg[1])).i];
+ blk->jmp.arg[1] = r;
}
}
}