commit 79f3673d205617ac567f0566ebf8f450932d9976
parent bda9f2833c39ea5f4266dbcb4506ed8895e22d3f
Author: Quentin Carbonneaux <quentin@c9x.me>
Date: Wed, 31 Aug 2022 21:29:15 +0200
new arm64_apple target
Should make qbe work on apple
arm-based hardware.
Diffstat:
8 files changed, 273 insertions(+), 73 deletions(-)
diff --git a/Makefile b/Makefile
@@ -30,7 +30,14 @@ main.o: config.h
config.h:
@case `uname` in \
*Darwin*) \
- echo "#define Deftgt T_amd64_apple"; \
+ case `uname -m` in \
+ *arm64*) \
+ echo "#define Deftgt T_arm64_apple";\
+ ;; \
+ *) \
+ echo "#define Deftgt T_amd64_apple";\
+ ;; \
+ esac \
;; \
*) \
case `uname -m` in \
diff --git a/arm64/abi.c b/arm64/abi.c
@@ -1,5 +1,6 @@
#include "all.h"
+typedef struct Abi Abi;
typedef struct Class Class;
typedef struct Insl Insl;
typedef struct Params Params;
@@ -9,6 +10,12 @@ enum {
Cptr = 2, /* replaced by a pointer */
};
+struct Abi {
+ void (*vastart)(Fn *, Params, Ref);
+ void (*vaarg)(Fn *, Blk *, Ins *);
+ int apple;
+};
+
struct Class {
char class;
char ishfa;
@@ -17,6 +24,7 @@ struct Class {
uchar size;
} hfa;
uint size;
+ uint align;
Typ *t;
uchar nreg;
uchar ngp;
@@ -33,11 +41,15 @@ struct Insl {
struct Params {
uint ngp;
uint nfp;
- uint nstk;
+ uint stk;
};
static int gpreg[12] = {R0, R1, R2, R3, R4, R5, R6, R7};
static int fpreg[12] = {V0, V1, V2, V3, V4, V5, V6, V7};
+static int store[] = {
+ [Kw] = Ostorew, [Kl] = Ostorel,
+ [Ks] = Ostores, [Kd] = Ostored
+};
/* layout of call's second argument (RCall)
*
@@ -92,9 +104,10 @@ typclass(Class *c, Typ *t, int *gp, int *fp)
c->class = 0;
c->ngp = 0;
c->nfp = 0;
+ c->align = 8;
- if (t->align > 4)
- err("alignments larger than 16 are not supported");
+ if (t->align > 3)
+ err("alignments larger than 8 are not supported");
if (t->isdark || sz > 16 || sz == 0) {
/* large structs are replaced by a
@@ -130,10 +143,6 @@ typclass(Class *c, Typ *t, int *gp, int *fp)
static void
sttmps(Ref tmp[], int cls[], uint nreg, Ref mem, Fn *fn)
{
- static int st[] = {
- [Kw] = Ostorew, [Kl] = Ostorel,
- [Ks] = Ostores, [Kd] = Ostored
- };
uint n;
uint64_t off;
Ref r;
@@ -143,7 +152,7 @@ sttmps(Ref tmp[], int cls[], uint nreg, Ref mem, Fn *fn)
for (n=0; n<nreg; n++) {
tmp[n] = newtmp("abi", cls[n], fn);
r = newtmp("abi", Kl, fn);
- emit(st[cls[n]], 0, R, tmp[n], r);
+ emit(store[cls[n]], 0, R, tmp[n], r);
emit(Oadd, Kl, r, mem, getcon(off, fn));
off += KWIDE(cls[n]) ? 8 : 4;
}
@@ -206,12 +215,13 @@ selret(Blk *b, Fn *fn)
}
static int
-argsclass(Ins *i0, Ins *i1, Class *carg)
+argsclass(Ins *i0, Ins *i1, Class *carg, int apple)
{
- int envc, ngp, nfp, *gp, *fp;
+ int va, envc, ngp, nfp, *gp, *fp;
Class *c;
Ins *i;
+ va = 0;
envc = 0;
gp = gpreg;
fp = fpreg;
@@ -219,10 +229,32 @@ argsclass(Ins *i0, Ins *i1, Class *carg)
nfp = 8;
for (i=i0, c=carg; i<i1; i++, c++)
switch (i->op) {
+ case Oargsb:
+ case Oargub:
+ case Oparsb:
+ case Oparub:
+ c->size = 1;
+ goto Scalar;
+ case Oargsh:
+ case Oarguh:
+ case Oparsh:
+ case Oparuh:
+ c->size = 2;
+ goto Scalar;
case Opar:
case Oarg:
- *c->cls = i->cls;
c->size = 8;
+ if (apple && !KWIDE(i->cls))
+ c->size = 4;
+ Scalar:
+ c->align = c->size;
+ *c->cls = i->cls;
+ if (va) {
+ c->class |= Cstk;
+ c->size = 8;
+ c->align = 8;
+ break;
+ }
if (KBASE(i->cls) == 0 && ngp > 0) {
ngp--;
*c->reg = *gp++;
@@ -258,6 +290,7 @@ argsclass(Ins *i0, Ins *i1, Class *carg)
envc = 1;
break;
case Oargv:
+ va = apple != 0;
break;
default:
die("unreachable");
@@ -327,18 +360,23 @@ stkblob(Ref r, Class *c, Fn *fn, Insl **ilp)
*ilp = il;
}
+static uint
+align(uint x, uint al)
+{
+ return (x + al-1) & -al;
+}
+
static void
-selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
+selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp, int apple)
{
Ins *i;
Class *ca, *c, cr;
- int cty;
- uint n;
- uint64_t stk, off;
+ int op, cty;
+ uint n, stk, off;;
Ref r, rstk, tmp[4];
ca = alloc((i1-i0) * sizeof ca[0]);
- cty = argsclass(i0, i1, ca);
+ cty = argsclass(i0, i1, ca, apple);
stk = 0;
for (i=i0, c=ca; i<i1; i++, c++) {
@@ -347,10 +385,12 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
stkblob(i->arg[0], c, fn, ilp);
i->op = Oarg;
}
- if (c->class & Cstk)
+ if (c->class & Cstk) {
+ stk = align(stk, c->align);
stk += c->size;
+ }
}
- stk += stk & 15;
+ stk = align(stk, 16);
rstk = getcon(stk, fn);
if (stk)
emit(Oadd, Kl, TMP(SP), TMP(SP), rstk);
@@ -403,9 +443,16 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
for (i=i0, c=ca; i<i1; i++, c++) {
if ((c->class & Cstk) == 0)
continue;
- if (i->op == Oarg) {
+ off = align(off, c->align);
+ if (i->op == Oarg || isargbh(i->op)) {
r = newtmp("abi", Kl, fn);
- emit(Ostorel, 0, R, i->arg[0], r);
+ switch (c->size) {
+ case 1: op = Ostoreb; break;
+ case 2: op = Ostoreh; break;
+ case 4:
+ case 8: op = store[*c->cls]; break;
+ }
+ emit(op, 0, R, i->arg[0], r);
emit(Oadd, Kl, r, TMP(SP), getcon(off, fn));
}
if (i->op == Oargc)
@@ -421,18 +468,19 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
}
static Params
-selpar(Fn *fn, Ins *i0, Ins *i1)
+selpar(Fn *fn, Ins *i0, Ins *i1, int apple)
{
Class *ca, *c, cr;
Insl *il;
Ins *i;
- int n, s, cty;
+ int op, n, cty;
+ uint off;
Ref r, tmp[16], *t;
ca = alloc((i1-i0) * sizeof ca[0]);
curi = &insb[NIns];
- cty = argsclass(i0, i1, ca);
+ cty = argsclass(i0, i1, ca, apple);
fn->reg = arm64_argregs(CALL(cty), 0);
il = 0;
@@ -457,26 +505,32 @@ selpar(Fn *fn, Ins *i0, Ins *i1)
}
t = tmp;
- s = 2;
+ off = 0;
for (i=i0, c=ca; i<i1; i++, c++)
if (i->op == Oparc && !(c->class & Cptr)) {
if (c->class & Cstk) {
- fn->tmp[i->to.val].slot = -s;
- s += c->size / 8;
+ off = align(off, c->align);
+ fn->tmp[i->to.val].slot = -(off+2);
+ off += c->size;
} else
for (n=0; n<c->nreg; n++) {
r = TMP(c->reg[n]);
emit(Ocopy, c->cls[n], *t++, r, R);
}
} else if (c->class & Cstk) {
- emit(Oload, *c->cls, i->to, SLOT(-s), R);
- s++;
+ off = align(off, c->align);
+ if (isparbh(i->op))
+ op = Oloadsb + (i->op - Oparsb);
+ else
+ op = Oload;
+ emit(op, *c->cls, i->to, SLOT(-(off+2)), R);
+ off += c->size;
} else {
emit(Ocopy, *c->cls, i->to, TMP(*c->reg), R);
}
return (Params){
- .nstk = s - 2,
+ .stk = align(off, 8),
.ngp = (cty >> 5) & 15,
.nfp = (cty >> 9) & 15
};
@@ -514,7 +568,24 @@ chpred(Blk *b, Blk *bp, Blk *bp1)
}
static void
-selvaarg(Fn *fn, Blk *b, Ins *i)
+apple_selvaarg(Fn *fn, Blk *b, Ins *i)
+{
+ Ref ap, stk, stk8, c8;
+
+ (void)b;
+ c8 = getcon(8, fn);
+ ap = i->arg[0];
+ stk8 = newtmp("abi", Kl, fn);
+ stk = newtmp("abi", Kl, fn);
+
+ emit(Ostorel, 0, R, stk8, ap);
+ emit(Oadd, Kl, stk8, stk, c8);
+ emit(Oload, i->cls, i->to, stk, R);
+ emit(Oload, Kl, stk, ap, R);
+}
+
+static void
+arm64_selvaarg(Fn *fn, Blk *b, Ins *i)
{
Ref loc, lreg, lstk, nr, r0, r1, c8, c16, c24, c28, ap;
Blk *b0, *bstk, *breg;
@@ -607,7 +678,21 @@ selvaarg(Fn *fn, Blk *b, Ins *i)
}
static void
-selvastart(Fn *fn, Params p, Ref ap)
+apple_selvastart(Fn *fn, Params p, Ref ap)
+{
+ Ref off, stk, arg;
+
+ off = getcon(p.stk, fn);
+ stk = newtmp("abi", Kl, fn);
+ arg = newtmp("abi", Kl, fn);
+
+ emit(Ostorel, 0, R, arg, ap);
+ emit(Oadd, Kl, arg, stk, off);
+ emit(Oaddr, Kl, stk, SLOT(-1), R);
+}
+
+static void
+arm64_selvastart(Fn *fn, Params p, Ref ap)
{
Ref r0, r1, rsave;
@@ -615,7 +700,7 @@ selvastart(Fn *fn, Params p, Ref ap)
r0 = newtmp("abi", Kl, fn);
emit(Ostorel, Kw, R, r0, ap);
- emit(Oadd, Kl, r0, rsave, getcon(p.nstk*8 + 192, fn));
+ emit(Oadd, Kl, r0, rsave, getcon(p.stk + 192, fn));
r0 = newtmp("abi", Kl, fn);
r1 = newtmp("abi", Kl, fn);
@@ -639,8 +724,8 @@ selvastart(Fn *fn, Params p, Ref ap)
emit(Oadd, Kl, r0, ap, getcon(28, fn));
}
-void
-arm64_abi(Fn *fn)
+static void
+abi(Fn *fn, Abi abi)
{
Blk *b;
Ins *i, *i0, *ip;
@@ -655,7 +740,7 @@ arm64_abi(Fn *fn)
for (b=fn->start, i=b->ins; i<&b->ins[b->nins]; i++)
if (!ispar(i->op))
break;
- p = selpar(fn, b->ins, i);
+ p = selpar(fn, b->ins, i, abi.apple);
n = b->nins - (i - b->ins) + (&insb[NIns] - curi);
i0 = alloc(n * sizeof(Ins));
ip = icpy(ip = i0, curi, &insb[NIns] - curi);
@@ -682,14 +767,14 @@ arm64_abi(Fn *fn)
for (i0=i; i0>b->ins; i0--)
if (!isarg((i0-1)->op))
break;
- selcall(fn, i0, i, &il);
+ selcall(fn, i0, i, &il, abi.apple);
i = i0;
break;
case Ovastart:
- selvastart(fn, p, i->arg[0]);
+ abi.vastart(fn, p, i->arg[0]);
break;
case Ovaarg:
- selvaarg(fn, b, i);
+ abi.vaarg(fn, b, i);
break;
case Oarg:
case Oargc:
@@ -707,3 +792,74 @@ arm64_abi(Fn *fn)
printfn(fn, stderr);
}
}
+
+void
+arm64_abi(Fn *fn)
+{
+ abi(fn, (Abi){
+ arm64_selvastart,
+ arm64_selvaarg,
+ 0
+ });
+}
+
+void
+apple_abi(Fn *fn)
+{
+ abi(fn, (Abi){
+ apple_selvastart,
+ apple_selvaarg,
+ 1
+ });
+}
+
+/* abi0 for apple target; introduces
+ * necessery sign extension for arg
+ * passing & returns
+ */
+void
+apple_extsb(Fn *fn)
+{
+ Blk *b;
+ Ins *i0, *i1, *i;
+ int j, op;
+ Ref r;
+
+ for (b=fn->start; b; b=b->link) {
+ curi = &insb[NIns];
+ j = b->jmp.type;
+ if (isretbh(j)) {
+ r = newtmp("abi", Kw, fn);
+ op = Oextsb + (j - Jretsb);
+ emit(op, Kw, r, b->jmp.arg, R);
+ b->jmp.arg = r;
+ }
+ for (i=&b->ins[b->nins]; i>b->ins;) {
+ emiti(*--i);
+ if (i->op != Ocall)
+ continue;
+ for (i0=i1=i; i0>b->ins; i0--)
+ if (!isarg((i0-1)->op))
+ break;
+ for (i=i1; i>i0;) {
+ emiti(*--i);
+ if (isargbh(i->op)) {
+ i->to = newtmp("abi", Kl, fn);
+ curi->arg[0] = i->to;
+ }
+ }
+ for (i=i1; i>i0;)
+ if (isargbh((--i)->op)) {
+ op = Oextsb + (i->op - Oargsb);
+ emit(op, Kw, i->to, i->arg[0], R);
+ }
+ }
+ b->nins = &insb[NIns] - curi;
+ idup(&b->ins, curi, b->nins);
+ }
+
+ if (debug['A']) {
+ fprintf(stderr, "\n> After apple_extsb:\n");
+ printfn(fn, stderr);
+ }
+}
diff --git a/arm64/all.h b/arm64/all.h
@@ -28,6 +28,8 @@ extern int arm64_rclob[];
bits arm64_retregs(Ref, int[2]);
bits arm64_argregs(Ref, int[2]);
void arm64_abi(Fn *);
+void apple_extsb(Fn *);
+void apple_abi(Fn *);
/* isel.c */
int arm64_logimm(uint64_t, int);
@@ -35,3 +37,4 @@ void arm64_isel(Fn *);
/* emit.c */
void arm64_emitfn(Fn *, FILE *);
+void apple_emitfn(Fn *, FILE *);
diff --git a/arm64/emit.c b/arm64/emit.c
@@ -7,6 +7,7 @@ struct E {
Fn *fn;
uint64_t frame;
uint padding;
+ int apple;
};
#define CMP(X) \
@@ -144,10 +145,10 @@ slot(int s, E *e)
if (s == -1)
return 16 + e->frame;
if (s < 0) {
- if (e->fn->vararg)
- return 16 + e->frame + 192 - (s+2)*8;
+ if (e->fn->vararg && !e->apple)
+ return 16 + e->frame + 192 - (s+2);
else
- return 16 + e->frame - (s+2)*8;
+ return 16 + e->frame - (s+2);
} else
return 16 + e->padding + 4 * s;
}
@@ -243,8 +244,16 @@ emitf(char *s, Ins *i, E *e)
}
static void
-loadcon(Con *c, int r, int k, FILE *f)
+loadcon(Con *c, int r, int k, E *e)
{
+ static char *ldsym[][2] = {
+ /* arm64 */
+ [0][0] = "\tadrp\t%s, %s%s%s\n",
+ [0][1] = "\tadd\t%s, %s, #:lo12:%s%s%s\n",
+ /* apple */
+ [1][0] = "\tadrp\t%s, %s%s@page%s\n",
+ [1][1] = "\tadd\t%s, %s, %s%s@pageoff%s\n",
+ };
char *rn, *l, *p, off[32];
int64_t n;
int w, sh;
@@ -261,24 +270,22 @@ loadcon(Con *c, int r, int k, FILE *f)
off[0] = 0;
l = str(c->label);
p = c->local ? T.asloc : l[0] == '"' ? "" : T.assym;
- fprintf(f, "\tadrp\t%s, %s%s%s\n",
- rn, p, l, off);
- fprintf(f, "\tadd\t%s, %s, #:lo12:%s%s%s\n",
- rn, rn, p, l, off);
+ fprintf(e->f, ldsym[e->apple][0], rn, p, l, off);
+ fprintf(e->f, ldsym[e->apple][1], rn, rn, p, l, off);
return;
}
assert(c->type == CBits);
if (!w)
n = (int32_t)n;
if ((n | 0xffff) == -1 || arm64_logimm(n, k)) {
- fprintf(f, "\tmov\t%s, #%"PRIi64"\n", rn, n);
+ fprintf(e->f, "\tmov\t%s, #%"PRIi64"\n", rn, n);
} else {
- fprintf(f, "\tmov\t%s, #%d\n",
+ fprintf(e->f, "\tmov\t%s, #%d\n",
rn, (int)(n & 0xffff));
for (sh=16; n>>=16; sh+=16) {
if ((!w && sh == 32) || sh == 64)
break;
- fprintf(f, "\tmovk\t%s, #0x%x, lsl #%d\n",
+ fprintf(e->f, "\tmovk\t%s, #0x%x, lsl #%d\n",
rn, (uint)(n & 0xffff), sh);
}
}
@@ -358,7 +365,7 @@ emitins(Ins *i, E *e)
switch (rtype(i->arg[0])) {
case RCon:
c = &e->fn->con[i->arg[0].val];
- loadcon(c, i->to.val, i->cls, e->f);
+ loadcon(c, i->to.val, i->cls, e);
break;
case RSlot:
i->op = Oload;
@@ -450,8 +457,8 @@ framelayout(E *e)
*/
-void
-arm64_emitfn(Fn *fn, FILE *out)
+static void
+emitfn(E *e)
{
static char *ctoa[] = {
#define X(c, s) [c] = s,
@@ -463,13 +470,11 @@ arm64_emitfn(Fn *fn, FILE *out)
uint64_t o;
Blk *b, *t;
Ins *i;
- E *e;
- emitlnk(fn->name, &fn->lnk, ".text", out);
- e = &(E){.f = out, .fn = fn};
+ emitlnk(e->fn->name, &e->fn->lnk, ".text", e->f);
framelayout(e);
- if (e->fn->vararg) {
+ if (e->fn->vararg && !e->apple) {
for (n=7; n>=0; n--)
fprintf(e->f, "\tstr\tq%d, [sp, -16]!\n", n);
for (n=7; n>=0; n-=2)
@@ -531,7 +536,7 @@ arm64_emitfn(Fn *fn, FILE *out)
if (e->fn->dynalloc)
fputs("\tmov sp, x29\n", e->f);
o = e->frame + 16;
- if (e->fn->vararg)
+ if (e->fn->vararg && !e->apple)
o += 192;
if (o <= 504)
fprintf(e->f,
@@ -589,5 +594,18 @@ arm64_emitfn(Fn *fn, FILE *out)
}
}
id0 += e->fn->nblk;
- elf_emitfnfin(e->fn->name, e->f);
+}
+
+void
+arm64_emitfn(Fn *fn, FILE *out)
+{
+ emitfn(&(E){.f = out, .fn = fn, .apple = 0});
+ elf_emitfnfin(fn->name, out);
+}
+
+void
+apple_emitfn(Fn *fn, FILE *out)
+{
+ fn->lnk.align = 4;
+ emitfn(&(E){.f = out, .fn = fn, .apple = 1});
}
diff --git a/arm64/targ.c b/arm64/targ.c
@@ -25,25 +25,39 @@ arm64_memargs(int op)
return 0;
}
+#define ARM64_COMMON \
+ .gpr0 = R0, \
+ .ngpr = NGPR, \
+ .fpr0 = V0, \
+ .nfpr = NFPR, \
+ .rglob = RGLOB, \
+ .nrglob = 3, \
+ .rsave = arm64_rsave, \
+ .nrsave = {NGPS, NFPS}, \
+ .retregs = arm64_retregs, \
+ .argregs = arm64_argregs, \
+ .memargs = arm64_memargs, \
+ .isel = arm64_isel, \
+
Target T_arm64 = {
.name = "arm64",
- .gpr0 = R0,
- .ngpr = NGPR,
- .fpr0 = V0,
- .nfpr = NFPR,
- .rglob = RGLOB,
- .nrglob = 3,
- .rsave = arm64_rsave,
- .nrsave = {NGPS, NFPS},
- .retregs = arm64_retregs,
- .argregs = arm64_argregs,
- .memargs = arm64_memargs,
.abi0 = elimsb,
.abi1 = arm64_abi,
- .isel = arm64_isel,
.emitfn = arm64_emitfn,
.emitfin = elf_emitfin,
.asloc = ".L",
+ ARM64_COMMON
+};
+
+Target T_arm64_apple = {
+ .name = "arm64_apple",
+ .abi0 = apple_extsb,
+ .abi1 = apple_abi,
+ .emitfn = apple_emitfn,
+ .emitfin = macho_emitfin,
+ .asloc = "L",
+ .assym = "_",
+ ARM64_COMMON
};
MAKESURE(globals_are_not_arguments,
diff --git a/main.c b/main.c
@@ -21,12 +21,14 @@ char debug['Z'+1] = {
extern Target T_amd64_sysv;
extern Target T_amd64_apple;
extern Target T_arm64;
+extern Target T_arm64_apple;
extern Target T_rv64;
static Target *tlist[] = {
&T_amd64_sysv,
&T_amd64_apple,
&T_arm64,
+ &T_arm64_apple,
&T_rv64,
0
};
diff --git a/test/dark.ssa b/test/dark.ssa
@@ -1,4 +1,4 @@
-# skip arm64 rv64
+# skip arm64 arm64_apple rv64
# a hack example,
# we use a dark type to get
# a pointer to the stack.
diff --git a/tools/test.sh b/tools/test.sh
@@ -70,7 +70,7 @@ init() {
"")
case `uname` in
*Darwin*)
- cc="cc -Wl,-no_pie"
+ cc="cc"
;;
*OpenBSD*)
cc="cc -nopie"