summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2022-09-09 17:40:31 +0200
committerQuentin Carbonneaux <quentin@c9x.me>2022-10-08 21:48:42 +0200
commit00a30954aca97004cb6f586bdeeabb488f1e3c3f (patch)
tree951dc4c0a5be04fe7d5aed13f4201eb90c60f841
parent5cea0c20ee3573949a2c24e4b3dea65fcbf6e48b (diff)
downloadroux-00a30954aca97004cb6f586bdeeabb488f1e3c3f.tar.gz
add support for thread-local storage
The apple targets are not done yet.
-rw-r--r--all.h8
-rw-r--r--amd64/emit.c11
-rw-r--r--amd64/isel.c3
-rw-r--r--arm64/emit.c41
-rw-r--r--arm64/isel.c4
-rw-r--r--emit.c35
-rw-r--r--fold.c9
-rw-r--r--load.c2
-rw-r--r--parse.c31
-rw-r--r--rv64/emit.c63
-rw-r--r--rv64/isel.c4
-rw-r--r--util.c4
12 files changed, 145 insertions, 70 deletions
diff --git a/all.h b/all.h
index 0d0bee6..14ebf68 100644
--- 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
index db6ead8..cf36ebe 100644
--- 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
index 640bf12..a562441 100644
--- 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
index 18c19d2..fc3f9ac 100644
--- 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
index c80e481..320cf33 100644
--- 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
index 372ce3d..5e0f452 100644
--- 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
index 24b09a6..0bbf8a7 100644
--- 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
index 6c1494a..cca8400 100644
--- 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
index 85214c2..874a71f 100644
--- 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
index 1fdc4b2..a176c11 100644
--- 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
index 3d9884f..42c0097 100644
--- 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
index ab4a90b..e187713 100644
--- 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);