qbe

Internal scc patchset buffer for QBE
Log | Files | Refs | README | LICENSE

commit 00a30954aca97004cb6f586bdeeabb488f1e3c3f
parent 5cea0c20ee3573949a2c24e4b3dea65fcbf6e48b
Author: Quentin Carbonneaux <quentin@c9x.me>
Date:   Fri,  9 Sep 2022 17:40:31 +0200

add support for thread-local storage

The apple targets are not done yet.

Diffstat:
Mall.h | 8++++++--
Mamd64/emit.c | 11+++++++----
Mamd64/isel.c | 3+--
Marm64/emit.c | 41++++++++++++++++++++++++++++-------------
Marm64/isel.c | 4++--
Memit.c | 35+++++++++++++++++++++++++++--------
Mfold.c | 9+++++++--
Mload.c | 2+-
Mparse.c | 31+++++++++++++++++++------------
Mrv64/emit.c | 63+++++++++++++++++++++++++++++++++++++++++++--------------------
Mrv64/isel.c | 4++--
Mutil.c | 4++--
12 files changed, 145 insertions(+), 70 deletions(-)

diff --git a/all.h b/all.h @@ -324,8 +324,11 @@ struct Con { double d; float s; } bits; + enum { + RelDef, + RelThr, + } rel; char flt; /* 1 to print as s, 2 to print as d */ - char local; }; typedef struct Addr Addr; @@ -339,6 +342,7 @@ struct Addr { /* amd64 addressing */ struct Lnk { char export; + char thread; char align; char *sec; char *secf; @@ -536,7 +540,7 @@ void spill(Fn *); void rega(Fn *); /* emit.c */ -void emitlnk(char *, Lnk *, char *, FILE *); +void emitfnlnk(char *, Lnk *, FILE *); void emitdat(Dat *, FILE *); int stashbits(void *, int); void elf_emitfnfin(char *, FILE *); diff --git a/amd64/emit.c b/amd64/emit.c @@ -166,8 +166,11 @@ emitcon(Con *con, FILE *f) switch (con->type) { case CAddr: l = str(con->label); - p = con->local ? T.asloc : l[0] == '"' ? "" : T.assym; - fprintf(f, "%s%s", p, l); + p = l[0] == '"' ? "" : T.assym; + if (con->rel == RelThr) + fprintf(f, "%%fs:%s%s@tpoff", p, l); + else + fprintf(f, "%s%s", p, l); if (con->bits.i) fprintf(f, "%+"PRId64, con->bits.i); break; @@ -337,7 +340,7 @@ Next: case RCon: off = fn->con[ref.val]; emitcon(&off, f); - if (off.type == CAddr) + if (off.type == CAddr && off.rel != RelThr) fprintf(f, "(%%rip)"); break; case RTmp: @@ -549,7 +552,7 @@ emitfn(Fn *fn, FILE *f) int *r, c, o, n, lbl; uint64_t fs; - emitlnk(fn->name, &fn->lnk, ".text", f); + emitfnlnk(fn->name, &fn->lnk, f); fputs("\tpushq %rbp\n\tmovq %rsp, %rbp\n", f); fs = framesz(fn); if (fs) diff --git a/amd64/isel.c b/amd64/isel.c @@ -78,9 +78,8 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn) vgrow(&fn->mem, ++fn->nmem); memset(&a, 0, sizeof a); a.offset.type = CAddr; - a.offset.local = 1; n = stashbits(&fn->con[r0.val].bits, KWIDE(k) ? 8 : 4); - sprintf(buf, "fp%d", n); + sprintf(buf, "\"%sfp%d\"", T.asloc, n); a.offset.label = intern(buf); fn->mem[fn->nmem-1] = a; } diff --git a/arm64/emit.c b/arm64/emit.c @@ -244,7 +244,7 @@ emitf(char *s, Ins *i, E *e) } static void -loadcon(Con *c, int r, int k, E *e) +loadaddr(Con *c, char *rn, E *e) { static char *ldsym[][2] = { /* arm64 */ @@ -254,7 +254,31 @@ loadcon(Con *c, int r, int k, E *e) [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]; + char *p, *l, off[32]; + + if (c->bits.i) + /* todo, handle large offsets */ + sprintf(off, "+%"PRIi64, c->bits.i); + else + off[0] = 0; + l = str(c->label); + p = l[0] == '"' ? "" : T.assym; + if (c->rel == RelThr) { + fprintf(e->f, "\tmrs\t%s, tpidr_el0\n", rn); + fprintf(e->f, "\tadd\t%s, %s, #:tprel_hi12:%s%s%s, lsl #12\n", + rn, rn, p, l, off); + fprintf(e->f, "\tadd\t%s, %s, #:tprel_lo12_nc:%s%s%s\n", + rn, rn, p, l, off); + } else { + fprintf(e->f, ldsym[e->apple][0], rn, p, l, off); + fprintf(e->f, ldsym[e->apple][1], rn, rn, p, l, off); + } +} + +static void +loadcon(Con *c, int r, int k, E *e) +{ + char *rn; int64_t n; int w, sh; @@ -262,16 +286,7 @@ loadcon(Con *c, int r, int k, E *e) rn = rname(r, k); n = c->bits.i; if (c->type == CAddr) { - rn = rname(r, Kl); - if (n) - /* todo, handle large offsets */ - sprintf(off, "+%"PRIi64, n); - else - off[0] = 0; - l = str(c->label); - p = c->local ? T.asloc : l[0] == '"' ? "" : T.assym; - fprintf(e->f, ldsym[e->apple][0], rn, p, l, off); - fprintf(e->f, ldsym[e->apple][1], rn, rn, p, l, off); + loadaddr(c, rn, e); return; } assert(c->type == CBits); @@ -471,7 +486,7 @@ emitfn(E *e) Blk *b, *t; Ins *i; - emitlnk(e->fn->name, &e->fn->lnk, ".text", e->f); + emitfnlnk(e->fn->name, &e->fn->lnk, e->f); framelayout(e); if (e->fn->vararg && !e->apple) { diff --git a/arm64/isel.c b/arm64/isel.c @@ -87,8 +87,8 @@ fixarg(Ref *pr, int k, int phi, Fn *fn) n = stashbits(&c->bits, KWIDE(k) ? 8 : 4); vgrow(&fn->con, ++fn->ncon); c = &fn->con[fn->ncon-1]; - sprintf(buf, "fp%d", n); - *c = (Con){.type = CAddr, .local = 1}; + sprintf(buf, "\"%sfp%d\"", T.asloc, n); + *c = (Con){.type = CAddr}; c->label = intern(buf); r2 = newtmp("isel", Kl, fn); emit(Oload, k, r1, r2, R); diff --git a/emit.c b/emit.c @@ -1,17 +1,30 @@ #include "all.h" +enum { + SecText, + SecData, + SecBss, +}; + void -emitlnk(char *n, Lnk *l, char *s, FILE *f) +emitlnk(char *n, Lnk *l, int s, FILE *f) { + static char *sec[2][3] = { + [0][SecText] = ".text", + [0][SecData] = ".data", + [0][SecBss] = ".bss", + [1][SecText] = ".abort \"unreachable\"", + [1][SecData] = ".section .tdata,\"awT\"", + [1][SecBss] = ".section .tbss,\"awT\"", + }; char *p; if (l->sec) { fprintf(f, ".section %s", l->sec); if (l->secf) - fprintf(f, ", %s", l->secf); - } else { - fputs(s, f); - } + fprintf(f, ",%s", l->secf); + } else + fputs(sec[l->thread != 0][s], f); fputc('\n', f); if (l->align) fprintf(f, ".balign %d\n", l->align); @@ -22,6 +35,12 @@ emitlnk(char *n, Lnk *l, char *s, FILE *f) } void +emitfnlnk(char *n, Lnk *l, FILE *f) +{ + emitlnk(n, l, SecText, f); +} + +void emitdat(Dat *d, FILE *f) { static char *dtoa[] = { @@ -39,7 +58,7 @@ emitdat(Dat *d, FILE *f) break; case DEnd: if (zero != -1) { - emitlnk(d->name, d->lnk, ".bss", f); + emitlnk(d->name, d->lnk, SecBss, f); fprintf(f, "\t.fill %"PRId64",1,0\n", zero); } break; @@ -51,7 +70,7 @@ emitdat(Dat *d, FILE *f) break; default: if (zero != -1) { - emitlnk(d->name, d->lnk, ".data", f); + emitlnk(d->name, d->lnk, SecData, f); if (zero > 0) fprintf(f, "\t.fill %"PRId64",1,0\n", zero); zero = -1; @@ -165,7 +184,7 @@ macho_emitfin(FILE *f) static char *sec[3] = { "__TEXT,__literal4,4byte_literals", "__TEXT,__literal8,8byte_literals", - ".rodata", /* should not happen */ + ".abort \"unreachable\"", }; emitfin(f, sec); diff --git a/fold.c b/fold.c @@ -334,9 +334,10 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr) } l, r; uint64_t x; uint32_t lab; - int typ; + int typ, rel; typ = CBits; + rel = RelDef; lab = 0; l.s = cl->bits.i; r.s = cr->bits.i; @@ -345,10 +346,12 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr) if (cr->type == CAddr) return 1; lab = cl->label; + rel = cl->rel; typ = CAddr; } else if (cr->type == CAddr) { lab = cr->label; + rel = cr->rel; typ = CAddr; } } @@ -356,6 +359,7 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr) if (cl->type == CAddr) { if (cr->type != CAddr) { lab = cl->label; + rel = cl->rel; typ = CAddr; } else if (cl->label != cr->label) return 1; @@ -404,6 +408,7 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr) x = l.u; if (cl->type == CAddr) { lab = cl->label; + rel = cl->rel; typ = CAddr; } break; @@ -457,7 +462,7 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr) else die("unreachable"); } - *res = (Con){.type=typ, .label=lab, .bits={.i=x}}; + *res = (Con){.type=typ, .label=lab, .rel=rel, .bits={.i=x}}; return 0; } diff --git a/load.c b/load.c @@ -155,7 +155,7 @@ load(Slice sl, bits msk, Loc *l) c.type = CAddr; c.label = a->label; c.bits.i = a->offset; - c.local = 0; + c.rel = RelDef; r = newcon(&c, curf); break; } diff --git a/parse.c b/parse.c @@ -45,6 +45,7 @@ enum { Tjnz, Tret, Texport, + Tthread, Tfunc, Ttype, Tdata, @@ -99,6 +100,7 @@ static char *kwmap[Ntok] = { [Tjnz] = "jnz", [Tret] = "ret", [Texport] = "export", + [Tthread] = "thread", [Tfunc] = "function", [Ttype] = "type", [Tdata] = "data", @@ -399,30 +401,34 @@ parseref() memset(&c, 0, sizeof c); switch (next()) { + default: + return R; case Ttmp: return tmpref(tokval.str); case Tint: c.type = CBits; c.bits.i = tokval.num; - goto Look; + break; case Tflts: c.type = CBits; c.bits.s = tokval.flts; c.flt = 1; - goto Look; + break; case Tfltd: c.type = CBits; c.bits.d = tokval.fltd; c.flt = 2; - goto Look; + break; + case Tthread: + c.rel = RelThr; + expect(Tglo); + /* fall through */ case Tglo: c.type = CAddr; c.label = intern(tokval.str); - Look: - return newcon(&c, curf); - default: - return R; + break; } + return newcon(&c, curf); } static int @@ -1101,6 +1107,9 @@ parselnk(Lnk *lnk) case Texport: lnk->export = 1; break; + case Tthread: + lnk->thread = 1; + break; case Tsection: if (lnk->sec) err("only one section allowed"); @@ -1113,9 +1122,9 @@ parselnk(Lnk *lnk) } break; default: - if (haslnk) - if (t != Tdata) - if (t != Tfunc) + if (t == Tfunc && lnk->thread) + err("only data may have thread linkage"); + if (haslnk && t != Tdata && t != Tfunc) err("only data and function have linkage"); return t; } @@ -1244,8 +1253,6 @@ printfn(Fn *fn, FILE *f) Ins *i; uint n; - if (fn->lnk.export) - fprintf(f, "export "); fprintf(f, "function $%s() {\n", fn->name); for (b=fn->start; b; b=b->link) { fprintf(f, "@%s\n", b->name); diff --git a/rv64/emit.c b/rv64/emit.c @@ -129,14 +129,10 @@ slot(int s, Fn *fn) static void emitaddr(Con *c, FILE *f) { - char off[32], *p; - + assert(c->rel == RelDef); + fputs(str(c->label), f); if (c->bits.i) - sprintf(off, "+%"PRIi64, c->bits.i); - else - off[0] = 0; - p = c->local ? ".L" : ""; - fprintf(f, "%s%s%s", p, str(c->label), off); + fprintf(f, "+%"PRIi64, c->bits.i); } static void @@ -229,25 +225,44 @@ emitf(char *s, Ins *i, Fn *fn, FILE *f) } static void +loadaddr(Con *c, char *rn, FILE *f) +{ + char off[32]; + + if (c->rel == RelThr) { + if (c->bits.i) + sprintf(off, "+%"PRIi64, c->bits.i); + else + off[0] = 0; + fprintf(f, "\tlui %s, %%tprel_hi(%s)%s\n", + rn, str(c->label), off); + fprintf(f, "\tadd %s, %s, tp, %%tprel_add(%s)%s\n", + rn, rn, str(c->label), off); + fprintf(f, "\taddi %s, %s, %%tprel_lo(%s)%s\n", + rn, rn, str(c->label), off); + } else { + fprintf(f, "\tla %s, ", rn); + emitaddr(c, f); + fputc('\n', f); + } +} + +static void loadcon(Con *c, int r, int k, FILE *f) { char *rn; int64_t n; - int w; - w = KWIDE(k); rn = rname[r]; switch (c->type) { case CAddr: - fprintf(f, "\tla %s, ", rn); - emitaddr(c, f); - fputc('\n', f); + loadaddr(c, rn, f); break; case CBits: n = c->bits.i; - if (!w) + if (!KWIDE(k)) n = (int32_t)n; - fprintf(f, "\tli %s, %"PRIu64"\n", rn, n); + fprintf(f, "\tli %s, %"PRIi64"\n", rn, n); break; default: die("invalid constant"); @@ -255,12 +270,20 @@ loadcon(Con *c, int r, int k, FILE *f) } static void -fixslot(Ref *pr, Fn *fn, FILE *f) +fixmem(Ref *pr, Fn *fn, FILE *f) { Ref r; int64_t s; + Con *c; r = *pr; + if (rtype(r) == RCon) { + c = &fn->con[r.val]; + if (c->type == CAddr && c->rel == RelThr) { + loadcon(c, T6, Kl, f); + *pr = TMP(T6); + } + } if (rtype(r) == RSlot) { s = slot(r.val, fn); if (s < -2048 || s > 2047) { @@ -282,9 +305,9 @@ emitins(Ins *i, Fn *fn, FILE *f) switch (i->op) { default: if (isload(i->op)) - fixslot(&i->arg[0], fn, f); + fixmem(&i->arg[0], fn, f); else if (isstore(i->op)) - fixslot(&i->arg[1], fn, f); + fixmem(&i->arg[1], fn, f); Table: /* most instructions are just pulled out of * the table omap[], some special cases are @@ -321,7 +344,7 @@ emitins(Ins *i, Fn *fn, FILE *f) case Ks: i->op = Ostores; break; case Kd: i->op = Ostored; break; } - fixslot(&i->arg[1], fn, f); + fixmem(&i->arg[1], fn, f); goto Table; } break; @@ -333,7 +356,7 @@ emitins(Ins *i, Fn *fn, FILE *f) break; case RSlot: i->op = Oload; - fixslot(&i->arg[0], fn, f); + fixmem(&i->arg[0], fn, f); goto Table; default: assert(isreg(i->arg[0])); @@ -415,7 +438,7 @@ rv64_emitfn(Fn *fn, FILE *f) Blk *b, *s; Ins *i; - emitlnk(fn->name, &fn->lnk, ".text", f); + emitfnlnk(fn->name, &fn->lnk, f); if (fn->vararg) { /* TODO: only need space for registers diff --git a/rv64/isel.c b/rv64/isel.c @@ -44,8 +44,8 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn) n = stashbits(&c->bits, KWIDE(k) ? 8 : 4); vgrow(&fn->con, ++fn->ncon); c = &fn->con[fn->ncon-1]; - sprintf(buf, "fp%d", n); - *c = (Con){.type = CAddr, .local = 1}; + sprintf(buf, "\"%sfp%d\"", T.asloc, n); + *c = (Con){.type = CAddr}; c->label = intern(buf); emit(Oload, k, r1, CON(c-fn->con), R); break; diff --git a/util.c b/util.c @@ -358,9 +358,9 @@ newcon(Con *c0, Fn *fn) for (i=0; i<fn->ncon; i++) { c1 = &fn->con[i]; if (c0->type == c1->type - && c0->bits.i == c1->bits.i && c0->label == c1->label - && c0->local == c1->local) + && c0->bits.i == c1->bits.i + && c0->rel == c1->rel) return CON(i); } vgrow(&fn->con, ++fn->ncon);