add support for thread-local storage

The apple targets are not done yet.
This commit is contained in:
Quentin Carbonneaux 2022-09-09 17:40:31 +02:00
parent 5cea0c20ee
commit 00a30954ac
12 changed files with 145 additions and 70 deletions

8
all.h
View file

@ -324,8 +324,11 @@ struct Con {
double d; double d;
float s; float s;
} bits; } bits;
enum {
RelDef,
RelThr,
} rel;
char flt; /* 1 to print as s, 2 to print as d */ char flt; /* 1 to print as s, 2 to print as d */
char local;
}; };
typedef struct Addr Addr; typedef struct Addr Addr;
@ -339,6 +342,7 @@ struct Addr { /* amd64 addressing */
struct Lnk { struct Lnk {
char export; char export;
char thread;
char align; char align;
char *sec; char *sec;
char *secf; char *secf;
@ -536,7 +540,7 @@ void spill(Fn *);
void rega(Fn *); void rega(Fn *);
/* emit.c */ /* emit.c */
void emitlnk(char *, Lnk *, char *, FILE *); void emitfnlnk(char *, Lnk *, FILE *);
void emitdat(Dat *, FILE *); void emitdat(Dat *, FILE *);
int stashbits(void *, int); int stashbits(void *, int);
void elf_emitfnfin(char *, FILE *); void elf_emitfnfin(char *, FILE *);

View file

@ -166,7 +166,10 @@ emitcon(Con *con, FILE *f)
switch (con->type) { switch (con->type) {
case CAddr: case CAddr:
l = str(con->label); l = str(con->label);
p = con->local ? T.asloc : l[0] == '"' ? "" : T.assym; p = l[0] == '"' ? "" : T.assym;
if (con->rel == RelThr)
fprintf(f, "%%fs:%s%s@tpoff", p, l);
else
fprintf(f, "%s%s", p, l); fprintf(f, "%s%s", p, l);
if (con->bits.i) if (con->bits.i)
fprintf(f, "%+"PRId64, con->bits.i); fprintf(f, "%+"PRId64, con->bits.i);
@ -337,7 +340,7 @@ Next:
case RCon: case RCon:
off = fn->con[ref.val]; off = fn->con[ref.val];
emitcon(&off, f); emitcon(&off, f);
if (off.type == CAddr) if (off.type == CAddr && off.rel != RelThr)
fprintf(f, "(%%rip)"); fprintf(f, "(%%rip)");
break; break;
case RTmp: case RTmp:
@ -549,7 +552,7 @@ emitfn(Fn *fn, FILE *f)
int *r, c, o, n, lbl; int *r, c, o, n, lbl;
uint64_t fs; 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); fputs("\tpushq %rbp\n\tmovq %rsp, %rbp\n", f);
fs = framesz(fn); fs = framesz(fn);
if (fs) if (fs)

View file

@ -78,9 +78,8 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
vgrow(&fn->mem, ++fn->nmem); vgrow(&fn->mem, ++fn->nmem);
memset(&a, 0, sizeof a); memset(&a, 0, sizeof a);
a.offset.type = CAddr; a.offset.type = CAddr;
a.offset.local = 1;
n = stashbits(&fn->con[r0.val].bits, KWIDE(k) ? 8 : 4); 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); a.offset.label = intern(buf);
fn->mem[fn->nmem-1] = a; fn->mem[fn->nmem-1] = a;
} }

View file

@ -244,7 +244,7 @@ emitf(char *s, Ins *i, E *e)
} }
static void static void
loadcon(Con *c, int r, int k, E *e) loadaddr(Con *c, char *rn, E *e)
{ {
static char *ldsym[][2] = { static char *ldsym[][2] = {
/* arm64 */ /* 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][0] = "\tadrp\t%s, %s%s@page%s\n",
[1][1] = "\tadd\t%s, %s, %s%s@pageoff%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; int64_t n;
int w, sh; int w, sh;
@ -262,16 +286,7 @@ loadcon(Con *c, int r, int k, E *e)
rn = rname(r, k); rn = rname(r, k);
n = c->bits.i; n = c->bits.i;
if (c->type == CAddr) { if (c->type == CAddr) {
rn = rname(r, Kl); loadaddr(c, rn, e);
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);
return; return;
} }
assert(c->type == CBits); assert(c->type == CBits);
@ -471,7 +486,7 @@ emitfn(E *e)
Blk *b, *t; Blk *b, *t;
Ins *i; Ins *i;
emitlnk(e->fn->name, &e->fn->lnk, ".text", e->f); emitfnlnk(e->fn->name, &e->fn->lnk, e->f);
framelayout(e); framelayout(e);
if (e->fn->vararg && !e->apple) { if (e->fn->vararg && !e->apple) {

View file

@ -87,8 +87,8 @@ fixarg(Ref *pr, int k, int phi, Fn *fn)
n = stashbits(&c->bits, KWIDE(k) ? 8 : 4); n = stashbits(&c->bits, KWIDE(k) ? 8 : 4);
vgrow(&fn->con, ++fn->ncon); vgrow(&fn->con, ++fn->ncon);
c = &fn->con[fn->ncon-1]; c = &fn->con[fn->ncon-1];
sprintf(buf, "fp%d", n); sprintf(buf, "\"%sfp%d\"", T.asloc, n);
*c = (Con){.type = CAddr, .local = 1}; *c = (Con){.type = CAddr};
c->label = intern(buf); c->label = intern(buf);
r2 = newtmp("isel", Kl, fn); r2 = newtmp("isel", Kl, fn);
emit(Oload, k, r1, r2, R); emit(Oload, k, r1, r2, R);

33
emit.c
View file

@ -1,17 +1,30 @@
#include "all.h" #include "all.h"
enum {
SecText,
SecData,
SecBss,
};
void 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; char *p;
if (l->sec) { if (l->sec) {
fprintf(f, ".section %s", l->sec); fprintf(f, ".section %s", l->sec);
if (l->secf) if (l->secf)
fprintf(f, ",%s", l->secf); fprintf(f, ",%s", l->secf);
} else { } else
fputs(s, f); fputs(sec[l->thread != 0][s], f);
}
fputc('\n', f); fputc('\n', f);
if (l->align) if (l->align)
fprintf(f, ".balign %d\n", l->align); fprintf(f, ".balign %d\n", l->align);
@ -21,6 +34,12 @@ emitlnk(char *n, Lnk *l, char *s, FILE *f)
fprintf(f, "%s%s:\n", p, n); fprintf(f, "%s%s:\n", p, n);
} }
void
emitfnlnk(char *n, Lnk *l, FILE *f)
{
emitlnk(n, l, SecText, f);
}
void void
emitdat(Dat *d, FILE *f) emitdat(Dat *d, FILE *f)
{ {
@ -39,7 +58,7 @@ emitdat(Dat *d, FILE *f)
break; break;
case DEnd: case DEnd:
if (zero != -1) { 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); fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
} }
break; break;
@ -51,7 +70,7 @@ emitdat(Dat *d, FILE *f)
break; break;
default: default:
if (zero != -1) { if (zero != -1) {
emitlnk(d->name, d->lnk, ".data", f); emitlnk(d->name, d->lnk, SecData, f);
if (zero > 0) if (zero > 0)
fprintf(f, "\t.fill %"PRId64",1,0\n", zero); fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
zero = -1; zero = -1;
@ -165,7 +184,7 @@ macho_emitfin(FILE *f)
static char *sec[3] = { static char *sec[3] = {
"__TEXT,__literal4,4byte_literals", "__TEXT,__literal4,4byte_literals",
"__TEXT,__literal8,8byte_literals", "__TEXT,__literal8,8byte_literals",
".rodata", /* should not happen */ ".abort \"unreachable\"",
}; };
emitfin(f, sec); emitfin(f, sec);

9
fold.c
View file

@ -334,9 +334,10 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
} l, r; } l, r;
uint64_t x; uint64_t x;
uint32_t lab; uint32_t lab;
int typ; int typ, rel;
typ = CBits; typ = CBits;
rel = RelDef;
lab = 0; lab = 0;
l.s = cl->bits.i; l.s = cl->bits.i;
r.s = cr->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) if (cr->type == CAddr)
return 1; return 1;
lab = cl->label; lab = cl->label;
rel = cl->rel;
typ = CAddr; typ = CAddr;
} }
else if (cr->type == CAddr) { else if (cr->type == CAddr) {
lab = cr->label; lab = cr->label;
rel = cr->rel;
typ = CAddr; typ = CAddr;
} }
} }
@ -356,6 +359,7 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
if (cl->type == CAddr) { if (cl->type == CAddr) {
if (cr->type != CAddr) { if (cr->type != CAddr) {
lab = cl->label; lab = cl->label;
rel = cl->rel;
typ = CAddr; typ = CAddr;
} else if (cl->label != cr->label) } else if (cl->label != cr->label)
return 1; return 1;
@ -404,6 +408,7 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
x = l.u; x = l.u;
if (cl->type == CAddr) { if (cl->type == CAddr) {
lab = cl->label; lab = cl->label;
rel = cl->rel;
typ = CAddr; typ = CAddr;
} }
break; break;
@ -457,7 +462,7 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
else else
die("unreachable"); die("unreachable");
} }
*res = (Con){.type=typ, .label=lab, .bits={.i=x}}; *res = (Con){.type=typ, .label=lab, .rel=rel, .bits={.i=x}};
return 0; return 0;
} }

2
load.c
View file

@ -155,7 +155,7 @@ load(Slice sl, bits msk, Loc *l)
c.type = CAddr; c.type = CAddr;
c.label = a->label; c.label = a->label;
c.bits.i = a->offset; c.bits.i = a->offset;
c.local = 0; c.rel = RelDef;
r = newcon(&c, curf); r = newcon(&c, curf);
break; break;
} }

31
parse.c
View file

@ -45,6 +45,7 @@ enum {
Tjnz, Tjnz,
Tret, Tret,
Texport, Texport,
Tthread,
Tfunc, Tfunc,
Ttype, Ttype,
Tdata, Tdata,
@ -99,6 +100,7 @@ static char *kwmap[Ntok] = {
[Tjnz] = "jnz", [Tjnz] = "jnz",
[Tret] = "ret", [Tret] = "ret",
[Texport] = "export", [Texport] = "export",
[Tthread] = "thread",
[Tfunc] = "function", [Tfunc] = "function",
[Ttype] = "type", [Ttype] = "type",
[Tdata] = "data", [Tdata] = "data",
@ -399,30 +401,34 @@ parseref()
memset(&c, 0, sizeof c); memset(&c, 0, sizeof c);
switch (next()) { switch (next()) {
default:
return R;
case Ttmp: case Ttmp:
return tmpref(tokval.str); return tmpref(tokval.str);
case Tint: case Tint:
c.type = CBits; c.type = CBits;
c.bits.i = tokval.num; c.bits.i = tokval.num;
goto Look; break;
case Tflts: case Tflts:
c.type = CBits; c.type = CBits;
c.bits.s = tokval.flts; c.bits.s = tokval.flts;
c.flt = 1; c.flt = 1;
goto Look; break;
case Tfltd: case Tfltd:
c.type = CBits; c.type = CBits;
c.bits.d = tokval.fltd; c.bits.d = tokval.fltd;
c.flt = 2; c.flt = 2;
goto Look; break;
case Tthread:
c.rel = RelThr;
expect(Tglo);
/* fall through */
case Tglo: case Tglo:
c.type = CAddr; c.type = CAddr;
c.label = intern(tokval.str); c.label = intern(tokval.str);
Look: break;
return newcon(&c, curf);
default:
return R;
} }
return newcon(&c, curf);
} }
static int static int
@ -1101,6 +1107,9 @@ parselnk(Lnk *lnk)
case Texport: case Texport:
lnk->export = 1; lnk->export = 1;
break; break;
case Tthread:
lnk->thread = 1;
break;
case Tsection: case Tsection:
if (lnk->sec) if (lnk->sec)
err("only one section allowed"); err("only one section allowed");
@ -1113,9 +1122,9 @@ parselnk(Lnk *lnk)
} }
break; break;
default: default:
if (haslnk) if (t == Tfunc && lnk->thread)
if (t != Tdata) err("only data may have thread linkage");
if (t != Tfunc) if (haslnk && t != Tdata && t != Tfunc)
err("only data and function have linkage"); err("only data and function have linkage");
return t; return t;
} }
@ -1244,8 +1253,6 @@ printfn(Fn *fn, FILE *f)
Ins *i; Ins *i;
uint n; uint n;
if (fn->lnk.export)
fprintf(f, "export ");
fprintf(f, "function $%s() {\n", fn->name); fprintf(f, "function $%s() {\n", fn->name);
for (b=fn->start; b; b=b->link) { for (b=fn->start; b; b=b->link) {
fprintf(f, "@%s\n", b->name); fprintf(f, "@%s\n", b->name);

View file

@ -129,14 +129,10 @@ slot(int s, Fn *fn)
static void static void
emitaddr(Con *c, FILE *f) emitaddr(Con *c, FILE *f)
{ {
char off[32], *p; assert(c->rel == RelDef);
fputs(str(c->label), f);
if (c->bits.i) if (c->bits.i)
sprintf(off, "+%"PRIi64, c->bits.i); fprintf(f, "+%"PRIi64, c->bits.i);
else
off[0] = 0;
p = c->local ? ".L" : "";
fprintf(f, "%s%s%s", p, str(c->label), off);
} }
static void static void
@ -228,26 +224,45 @@ 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 static void
loadcon(Con *c, int r, int k, FILE *f) loadcon(Con *c, int r, int k, FILE *f)
{ {
char *rn; char *rn;
int64_t n; int64_t n;
int w;
w = KWIDE(k);
rn = rname[r]; rn = rname[r];
switch (c->type) { switch (c->type) {
case CAddr: case CAddr:
fprintf(f, "\tla %s, ", rn); loadaddr(c, rn, f);
emitaddr(c, f);
fputc('\n', f);
break; break;
case CBits: case CBits:
n = c->bits.i; n = c->bits.i;
if (!w) if (!KWIDE(k))
n = (int32_t)n; n = (int32_t)n;
fprintf(f, "\tli %s, %"PRIu64"\n", rn, n); fprintf(f, "\tli %s, %"PRIi64"\n", rn, n);
break; break;
default: default:
die("invalid constant"); die("invalid constant");
@ -255,12 +270,20 @@ loadcon(Con *c, int r, int k, FILE *f)
} }
static void static void
fixslot(Ref *pr, Fn *fn, FILE *f) fixmem(Ref *pr, Fn *fn, FILE *f)
{ {
Ref r; Ref r;
int64_t s; int64_t s;
Con *c;
r = *pr; 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) { if (rtype(r) == RSlot) {
s = slot(r.val, fn); s = slot(r.val, fn);
if (s < -2048 || s > 2047) { if (s < -2048 || s > 2047) {
@ -282,9 +305,9 @@ emitins(Ins *i, Fn *fn, FILE *f)
switch (i->op) { switch (i->op) {
default: default:
if (isload(i->op)) if (isload(i->op))
fixslot(&i->arg[0], fn, f); fixmem(&i->arg[0], fn, f);
else if (isstore(i->op)) else if (isstore(i->op))
fixslot(&i->arg[1], fn, f); fixmem(&i->arg[1], fn, f);
Table: Table:
/* most instructions are just pulled out of /* most instructions are just pulled out of
* the table omap[], some special cases are * 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 Ks: i->op = Ostores; break;
case Kd: i->op = Ostored; break; case Kd: i->op = Ostored; break;
} }
fixslot(&i->arg[1], fn, f); fixmem(&i->arg[1], fn, f);
goto Table; goto Table;
} }
break; break;
@ -333,7 +356,7 @@ emitins(Ins *i, Fn *fn, FILE *f)
break; break;
case RSlot: case RSlot:
i->op = Oload; i->op = Oload;
fixslot(&i->arg[0], fn, f); fixmem(&i->arg[0], fn, f);
goto Table; goto Table;
default: default:
assert(isreg(i->arg[0])); assert(isreg(i->arg[0]));
@ -415,7 +438,7 @@ rv64_emitfn(Fn *fn, FILE *f)
Blk *b, *s; Blk *b, *s;
Ins *i; Ins *i;
emitlnk(fn->name, &fn->lnk, ".text", f); emitfnlnk(fn->name, &fn->lnk, f);
if (fn->vararg) { if (fn->vararg) {
/* TODO: only need space for registers /* TODO: only need space for registers

View file

@ -44,8 +44,8 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
n = stashbits(&c->bits, KWIDE(k) ? 8 : 4); n = stashbits(&c->bits, KWIDE(k) ? 8 : 4);
vgrow(&fn->con, ++fn->ncon); vgrow(&fn->con, ++fn->ncon);
c = &fn->con[fn->ncon-1]; c = &fn->con[fn->ncon-1];
sprintf(buf, "fp%d", n); sprintf(buf, "\"%sfp%d\"", T.asloc, n);
*c = (Con){.type = CAddr, .local = 1}; *c = (Con){.type = CAddr};
c->label = intern(buf); c->label = intern(buf);
emit(Oload, k, r1, CON(c-fn->con), R); emit(Oload, k, r1, CON(c-fn->con), R);
break; break;

4
util.c
View file

@ -358,9 +358,9 @@ newcon(Con *c0, Fn *fn)
for (i=0; i<fn->ncon; i++) { for (i=0; i<fn->ncon; i++) {
c1 = &fn->con[i]; c1 = &fn->con[i];
if (c0->type == c1->type if (c0->type == c1->type
&& c0->bits.i == c1->bits.i
&& c0->label == c1->label && c0->label == c1->label
&& c0->local == c1->local) && c0->bits.i == c1->bits.i
&& c0->rel == c1->rel)
return CON(i); return CON(i);
} }
vgrow(&fn->con, ++fn->ncon); vgrow(&fn->con, ++fn->ncon);