diff options
author | Quentin Carbonneaux <quentin@c9x.me> | 2022-08-31 21:29:15 +0200 |
---|---|---|
committer | Quentin Carbonneaux <quentin@c9x.me> | 2022-10-03 10:41:26 +0200 |
commit | 79f3673d205617ac567f0566ebf8f450932d9976 (patch) | |
tree | 48ea32843eacd8ac33b4bbcdc975df5d8ab6356c /arm64/abi.c | |
parent | bda9f2833c39ea5f4266dbcb4506ed8895e22d3f (diff) | |
download | roux-79f3673d205617ac567f0566ebf8f450932d9976.tar.gz |
new arm64_apple target
Should make qbe work on apple arm-based hardware.
Diffstat (limited to 'arm64/abi.c')
-rw-r--r-- | arm64/abi.c | 232 |
1 files changed, 194 insertions, 38 deletions
diff --git a/arm64/abi.c b/arm64/abi.c index b2b5973..945a676 100644 --- 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); + } +} |