commit 5e0ba156116036ba42d7ce8e361004ea20fb2d6b
parent 5dbc5dc2c9816821db6e7f1a2903c54a7d549efd
Author: Sudipto Mallick <smlckz@disroot.org>
Date: Sun, 11 Jul 2021 20:38:30 +0000
arm64/emit.c: fix move instructions with big immediate values
Fixes #467. It assumes that the stack won't need to grow beyond 2^32 bytes.
If that were to happen, we'd need another or at most two more `movk` instructions.
Signed-off-by: Sudipto Mallick <smlckz@disroot.org>
Diffstat:
M | arm64/emit.c | | | 86 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- |
1 file changed, 71 insertions(+), 15 deletions(-)
diff --git a/arm64/emit.c b/arm64/emit.c
@@ -338,15 +338,21 @@ emitins(Ins *i, E *e)
assert(rtype(i->arg[0]) == RSlot);
rn = rname(i->to.val, Kl);
s = slot(i->arg[0].val, e);
- if (s <= 4095) {
+ if (s <= 4095)
fprintf(e->f, "\tadd\t%s, x29, #%"PRIu64"\n", rn, s);
- } else {
+ else if (s <= 65535)
fprintf(e->f,
"\tmov\t%s, #%"PRIu64"\n"
"\tadd\t%s, x29, %s\n",
rn, s, rn, rn
);
- }
+ else
+ fprintf(e->f,
+ "\tmov\t%s, #%"PRIu64"\n"
+ "\tmovk\t%s, #%"PRIu64", lsl #16\n"
+ "\tadd\t%s, x29, %s\n",
+ rn, s & 0xFFFF, rn, s >> 16, rn, rn
+ );
break;
}
}
@@ -435,20 +441,45 @@ arm64_emitfn(Fn *fn, FILE *out)
"\tstp\tx29, x30, [sp, -16]!\n",
e->frame
);
- else
+ else if (e->frame <= 65535)
fprintf(e->f,
"\tmov\tx16, #%"PRIu64"\n"
"\tsub\tsp, sp, x16\n"
"\tstp\tx29, x30, [sp, -16]!\n",
e->frame
);
+ else
+ fprintf(e->f,
+ "\tmov\tx16, #%"PRIu64"\n"
+ "\tmovk\tx16, #%"PRIu64", lsl #16\n"
+ "\tsub\tsp, sp, x16\n"
+ "\tstp\tx29, x30, [sp, -16]!\n",
+ e->frame & 0xFFFF, e->frame >> 16
+ );
fputs("\tadd\tx29, sp, 0\n", e->f);
for (o=e->frame+16, r=arm64_rclob; *r>=0; r++)
- if (e->fn->reg & BIT(*r))
- fprintf(e->f,
- "\tstr\t%s, [sp, %"PRIu64"]\n",
- rname(*r, Kx), o -= 8
- );
+ if (e->fn->reg & BIT(*r)) {
+ if (o <= 32760)
+ fprintf(e->f,
+ "\tstr\t%s, [sp, %"PRIu64"]\n",
+ rname(*r, Kx), o -= 8
+ );
+ else if (o <= 65535)
+ fprintf(e->f,
+ "\tmov\tx16, #%"PRIu64"\n"
+ "\tstr\t%s, [sp, x16]\n",
+ o -= 8, rname(*r, Kx)
+ );
+ else {
+ o -= 8;
+ fprintf(e->f,
+ "\tmov\tx16, #%"PRIu64"\n"
+ "\tmovk\tx16, #%"PRIu64", lsl #16\n"
+ "\tstr\t%s, [sp, x16]\n",
+ o & 0xFFFF, o >> 16, rname(*r, Kx)
+ );
+ }
+ }
for (lbl=0, b=e->fn->start; b; b=b->link) {
if (lbl || b->npred > 1)
@@ -459,11 +490,28 @@ arm64_emitfn(Fn *fn, FILE *out)
switch (b->jmp.type) {
case Jret0:
for (o=e->frame+16, r=arm64_rclob; *r>=0; r++)
- if (e->fn->reg & BIT(*r))
- fprintf(e->f,
- "\tldr\t%s, [sp, %"PRIu64"]\n",
- rname(*r, Kx), o -= 8
- );
+ if (e->fn->reg & BIT(*r)) {
+ if (o <= 32760)
+ fprintf(e->f,
+ "\tldr\t%s, [sp, %"PRIu64"]\n",
+ rname(*r, Kx), o -= 8
+ );
+ else if (o <= 65535)
+ fprintf(e->f,
+ "\tmov\tx16, #%"PRIu64"\n"
+ "\tldr\t%s, [sp, x16]\n",
+ o -= 8, rname(*r, Kx)
+ );
+ else {
+ o -= 8;
+ fprintf(e->f,
+ "\tmov\tx16, #%"PRIu64"\n"
+ "\tmovk\tx16, #%"PRIu64", lsl #16\n"
+ "\tldr\t%s, [sp, x16]\n",
+ o & 0xFFFF, o >> 16, rname(*r, Kx)
+ );
+ }
+ }
o = e->frame + 16;
if (e->fn->vararg)
o += 192;
@@ -478,13 +526,21 @@ arm64_emitfn(Fn *fn, FILE *out)
"\tadd\tsp, sp, #%"PRIu64"\n",
o - 16
);
- else
+ else if (o - 16 <= 65535)
fprintf(e->f,
"\tldp\tx29, x30, [sp], 16\n"
"\tmov\tx16, #%"PRIu64"\n"
"\tadd\tsp, sp, x16\n",
o - 16
);
+ else
+ fprintf(e->f,
+ "\tldp\tx29, x30, [sp], 16\n"
+ "\tmov\tx16, #%"PRIu64"\n"
+ "\tmovk\tx16, #%"PRIu64", lsl #16\n"
+ "\tadd\tsp, sp, x16\n",
+ (o - 16) & 0xFFFF, (o - 16) >> 16
+ );
fprintf(e->f, "\tret\n");
break;
case Jjmp: