~mpu/qbe

Implement thread-local storage v1 SUPERSEDED

Drew DeVault: 1
 Implement thread-local storage

 8 files changed, 68 insertions(+), 7 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~mpu/qbe/patches/34203/mbox | git am -3
Learn more about email & git

[RFC PATCH] Implement thread-local storage Export this patch

---
See test/tls.ssa for usage. Essentially:

threadlocal data $i = { w 42 }

%ret =l loadl threadlocal $i

Seeking sign-off on the approach and syntax. Still to-do:
- rv64, arm64 support
- Documentation updates

Points of note for the review:
- Adding -lpthread to every test
- use of strcmp in gasemitlnk
- Any edge cases I've forgotten about?

 all.h         |  2 ++
 amd64/emit.c  |  7 ++++++-
 amd64/isel.c  |  1 +
 gas.c         |  6 ++++++
 parse.c       | 24 ++++++++++++++++++++++++
 test/tls.ssa  | 23 +++++++++++++++++++++++
 tools/lexh.c  |  2 +-
 tools/test.sh | 10 +++++-----
 8 files changed, 68 insertions(+), 7 deletions(-)
 create mode 100644 test/tls.ssa

diff --git a/all.h b/all.h
index c8ec93c..3418f63 100644
--- a/all.h
+++ b/all.h
@@ -309,6 +309,7 @@ struct Con {
		CUndef,
		CBits,
		CAddr,
		CThreadLocal,
	} type;
	uint32_t label;
	union {
@@ -334,6 +335,7 @@ struct Lnk {
	char align;
	char *sec;
	char *secf;
	char istls;
};

struct Fn {
diff --git a/amd64/emit.c b/amd64/emit.c
index b8e9e8e..9870e0b 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -171,6 +171,10 @@ emitcon(Con *con, FILE *f)
		if (con->bits.i)
			fprintf(f, "%+"PRId64, con->bits.i);
		break;
	case CThreadLocal:
		l = str(con->label);
		fprintf(f, "%%fs:%s@tpoff", l);
		break;
	case CBits:
		fprintf(f, "%"PRId64, con->bits.i);
		break;
@@ -306,7 +310,8 @@ Next:
			fputc(')', f);
			break;
		case RCon:
			fputc('$', f);
			if (fn->con[ref.val].type != CThreadLocal)
				fputc('$', f);
			emitcon(&fn->con[ref.val], f);
			break;
		default:
diff --git a/amd64/isel.c b/amd64/isel.c
index 5a64429..592f7fc 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -36,6 +36,7 @@ noimm(Ref r, Fn *fn)
		return 0;
	switch (fn->con[r.val].type) {
	case CAddr:
	case CThreadLocal:
		/* we only support the 'small'
		 * code model of the ABI, this
		 * means that we can always
diff --git a/gas.c b/gas.c
index 865edba..92ffd7f 100644
--- a/gas.c
+++ b/gas.c
@@ -29,6 +29,12 @@ gasemitlnk(char *n, Lnk *l, char *s, FILE *f)
		fprintf(f, ".section %s", l->sec);
		if (l->secf)
			fprintf(f, ", %s", l->secf);
	} else if (l->istls) {
		if (strcmp(s, ".bss") == 0) {
			fprintf(f, ".section .tbss,\"awT\"");
		} else {
			fprintf(f, ".section .tdata,\"awT\"");
		}
	} else {
		fputs(s, f);
	}
diff --git a/parse.c b/parse.c
index 1912c8b..5e09a21 100644
--- a/parse.c
+++ b/parse.c
@@ -42,6 +42,7 @@ enum {
	Ttype,
	Tdata,
	Tsection,
	Tthreadlocal,
	Talign,
	Tl,
	Tw,
@@ -92,6 +93,7 @@ static char *kwmap[Ntok] = {
	[Ttype] = "type",
	[Tdata] = "data",
	[Tsection] = "section",
	[Tthreadlocal] = "threadlocal",
	[Talign] = "align",
	[Tl] = "l",
	[Tw] = "w",
@@ -403,6 +405,13 @@ parseref()
	case Tglo:
		c.type = CAddr;
		c.label = intern(tokval.str);
		goto Look;
	case Tthreadlocal:
		c.type = CThreadLocal;
		if (next() != Tglo)
			err("function name expected");
		c.label = intern(tokval.str);
		goto Look;
	Look:
		return newcon(&c, curf);
	default:
@@ -798,6 +807,9 @@ parsefn(Lnk *lnk)
	int i;
	PState ps;

	if (lnk->istls)
		err("TLS is not supported for function declarations");

	curb = 0;
	nblk = 0;
	curi = insb;
@@ -1073,6 +1085,8 @@ parselnk(Lnk *lnk)
		case Tsection:
			if (lnk->sec)
				err("only one section allowed");
			if (lnk->istls)
				err("threadlocal and section cannot co-exist");
			if (next() != Tstr)
				err("section \"name\" expected");
			lnk->sec = tokval.str;
@@ -1081,6 +1095,13 @@ parselnk(Lnk *lnk)
				lnk->secf = tokval.str;
			}
			break;
		case Tthreadlocal:
			if (lnk->istls)
				err("only one TLS directive allowed");
			if (lnk->sec)
				err("threadlocal and section cannot co-exist");
			lnk->istls = 1;
			break;
		default:
			if (haslnk)
			if (t != Tdata)
@@ -1138,6 +1159,9 @@ printcon(Con *c, FILE *f)
		if (c->bits.i)
			fprintf(f, "%+"PRIi64, c->bits.i);
		break;
	case CThreadLocal:
		fprintf(f, "threadlocal $%s", str(c->label));
		break;
	case CBits:
		if (c->flt == 1)
			fprintf(f, "s_%f", c->bits.s);
diff --git a/test/tls.ssa b/test/tls.ssa
new file mode 100644
index 0000000..5975932
--- /dev/null
+++ b/test/tls.ssa
@@ -0,0 +1,23 @@
export function w $main() {
@start
	%thread =l alloc8 8
	%retval =l alloc8 8

	storew 1337, threadlocal $i
	call $pthread_create(l %thread, l 0, l $thread, l 0)

	%thread_id =l loadl %thread
	call $pthread_join(l %thread_id, l %retval)

	%ret =l loadl %retval
	%res =l cnel %ret, 42
	ret %res
}

function w $thread() {
@start
	%ret =l loadl threadlocal $i
	ret %ret
}

threadlocal data $i = { w 42 }
diff --git a/tools/lexh.c b/tools/lexh.c
index 8d0af21..5be376e 100644
--- a/tools/lexh.c
+++ b/tools/lexh.c
@@ -26,7 +26,7 @@ char *tok[] = {
	"vaarg", "vastart", "...", "env",

	"call", "phi", "jmp", "jnz", "ret", "export",
	"function", "type", "data", "section", "align",
	"function", "type", "data", "section", "threadlocal", "align",
	"l", "w", "h", "b", "d", "s", "z", "loadw", "loadl",
	"loads", "loadd", "alloc1", "alloc2",

diff --git a/tools/test.sh b/tools/test.sh
index 4653b83..37105df 100755
--- a/tools/test.sh
+++ b/tools/test.sh
@@ -22,7 +22,7 @@ init() {
	arm64)
		for p in aarch64-linux-musl aarch64-linux-gnu
		do
			cc="$p-gcc -no-pie -static"
			cc="$p-gcc -no-pie -static -lpthread"
			qemu="qemu-aarch64"
			if
				$cc -v >/dev/null 2>&1 &&
@@ -46,7 +46,7 @@ init() {
	rv64)
		for p in riscv64-linux-musl riscv64-linux-gnu
		do
			cc="$p-gcc -no-pie -static"
			cc="$p-gcc -no-pie -static -lpthread"
			qemu="qemu-riscv64"
			if
				$cc -v >/dev/null 2>&1 &&
@@ -73,13 +73,13 @@ init() {
			cc="cc -Wl,-no_pie"
			;;
		*OpenBSD*)
			cc="cc -nopie"
			cc="cc -nopie -lpthread"
			;;
		*FreeBSD*)
			cc="cc"
			cc="cc -lpthread"
			;;
		*)
			cc="${CC:-cc} -no-pie"
			cc="${CC:-cc} -no-pie -lpthread"
			testcc "$cc" || cc="${CC:-cc}"
			;;
		esac

base-commit: c8cd2824eae0137505fe46530c3a8e9788ab9a63
-- 
2.37.1