diff options
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | cc.h | 2 | ||||
| -rw-r--r-- | decl.c | 8 | ||||
| -rw-r--r-- | eval.c | 2 | ||||
| -rw-r--r-- | qbe.c | 12 | ||||
| -rw-r--r-- | test/thread-local.c | 10 | ||||
| -rw-r--r-- | test/thread-local.qbe | 23 | 
7 files changed, 48 insertions, 10 deletions
| @@ -80,7 +80,6 @@ specified in `config.h`.  - Digraph sequences ([6.4.6p3], will not be implemented).  - Variable-length arrays ([#1]).  - `volatile`-qualified types ([#7]). -- `_Thread_local` storage-class specifier ([#5]).  - `long double` type ([#3]).  - Inline assembly ([#5]).  - Preprocessor ([#6]). @@ -541,7 +541,7 @@ void switchcase(struct switchcases *, unsigned long long, struct block *);  struct block *mkblock(char *); -struct value *mkglobal(char *, bool); +struct value *mkglobal(char *, bool, bool);  struct value *mkintconst(unsigned long long);  unsigned long long intconstvalue(struct value *); @@ -941,7 +941,7 @@ declcommon(struct scope *s, enum declkind kind, char *name, char *asmname, struc  	if (kind == DECLFUNC || linkage != LINKNONE || sc & SCSTATIC) {  		if (asmname)  			name = asmname; -		d->value = mkglobal(name, linkage == LINKNONE && !asmname); +		d->value = mkglobal(name, linkage == LINKNONE && !asmname, sc & SCTHREADLOCAL);  		d->asmname = asmname;  	}  	return d; @@ -981,8 +981,6 @@ decl(struct scope *s, struct func *f)  		if (sc & SCREGISTER)  			error(&tok.loc, "external declaration must not contain 'register'");  	} -	if (sc & SCTHREADLOCAL) -		error(&tok.loc, "'_Thread_local' is not yet supported");  	if (consume(TSEMICOLON)) {  		/* XXX 6.7p2 error unless in function parameter/struct/union, or tag/enum members are declared */  		return true; @@ -1029,7 +1027,7 @@ decl(struct scope *s, struct func *f)  					error(&tok.loc, "object '%s' redefined", name);  				init = parseinit(s, d->type);  				hasinit = true; -			} else if (d->linkage != LINKNONE) { +			} else if (d->linkage != LINKNONE && (!(sc & SCTHREADLOCAL) || sc & SCEXTERN)) {  				if (!(sc & SCEXTERN) && !d->defined && !d->tentative) {  					d->tentative = true;  					*tentativedefnsend = d; @@ -1096,7 +1094,7 @@ stringdecl(struct expr *expr)  	d = *entry;  	if (!d) {  		d = mkdecl(NULL, DECLOBJECT, expr->type, QUALNONE, LINKNONE); -		d->value = mkglobal("string", true); +		d->value = mkglobal("string", true, false);  		emitdata(d, mkinit(0, expr->type->size, (struct bitfield){0}, expr));  		*entry = d;  	} @@ -119,7 +119,7 @@ eval(struct expr *expr)  		if (expr->u.compound.storage != SDSTATIC)  			break;  		d = mkdecl(NULL, DECLOBJECT, t, expr->qual, LINKNONE); -		d->value = mkglobal(NULL, true); +		d->value = mkglobal(NULL, true, false);  		emitdata(d, expr->u.compound.init);  		expr->kind = EXPRIDENT;  		expr->u.ident.decl = d; @@ -20,6 +20,7 @@ struct value {  		VALUE_LABEL,  	} kind;  	unsigned id; +	bool threadlocal;  	union {  		char *name;  		unsigned long long i; @@ -128,7 +129,7 @@ mkblock(char *name)  }  struct value * -mkglobal(char *name, bool private) +mkglobal(char *name, bool private, bool threadlocal)  {  	static unsigned id;  	struct value *v; @@ -137,6 +138,7 @@ mkglobal(char *name, bool private)  	v->kind = VALUE_GLOBAL;  	v->u.name = name;  	v->id = private ? ++id : 0; +	v->threadlocal = threadlocal;  	return v;  } @@ -501,7 +503,7 @@ mkfunc(struct decl *decl, char *name, struct type *t, struct scope *s)  	t = mkarraytype(&typechar, QUALCONST, strlen(name) + 1);  	d = mkdecl("__func__", DECLOBJECT, t, QUALNONE, LINKNONE); -	d->value = mkglobal(d->name, true); +	d->value = mkglobal(d->name, true, false);  	scopeputdecl(s, d);  	f->namedecl = d; @@ -1125,6 +1127,8 @@ emitinst(struct inst **instp, struct inst **instend)  	}  	fputs(instname[inst->kind], stdout);  	putchar(' '); +	if (inst->arg[0]->kind == VALUE_GLOBAL && inst->arg[0]->threadlocal) +		fputs("thread ", stdout);  	emitvalue(inst->arg[0]);  	++instp;  	op = inst->kind; @@ -1152,6 +1156,8 @@ emitinst(struct inst **instp, struct inst **instend)  	default:  		if (inst->arg[1]) {  			fputs(", ", stdout); +			if (inst->arg[1]->kind == VALUE_GLOBAL && inst->arg[1]->threadlocal) +				fputs("thread ", stdout);  			emitvalue(inst->arg[1]);  		}  	} @@ -1322,6 +1328,8 @@ emitdata(struct decl *d, struct init *init)  	align = d->u.obj.align;  	for (cur = init; cur; cur = cur->next)  		cur->expr = eval(cur->expr); +	if (d->value->threadlocal) +		fputs("thread ", stdout);  	if (d->linkage == LINKEXTERN)  		fputs("export ", stdout);  	fputs("data ", stdout); diff --git a/test/thread-local.c b/test/thread-local.c new file mode 100644 index 0000000..3086699 --- /dev/null +++ b/test/thread-local.c @@ -0,0 +1,10 @@ +thread_local int a = 1; +static thread_local int b = 2; +extern thread_local int c = 3; +thread_local int d; +static thread_local int e; +extern thread_local int f; +int main(void) { +	static thread_local int x = 6; +	return a + b + c + d + e - x; +} diff --git a/test/thread-local.qbe b/test/thread-local.qbe new file mode 100644 index 0000000..0e9ba83 --- /dev/null +++ b/test/thread-local.qbe @@ -0,0 +1,23 @@ +thread export data $a = align 4 { w 1, } +thread data $b = align 4 { w 2, } +thread export data $c = align 4 { w 3, } +thread export data $d = align 4 { z 4 } +thread data $e = align 4 { z 4 } +thread data $.Lx.2 = align 4 { w 6, } +export +function w $main() { +@start.1 +@body.2 +	%.1 =w loadw thread $a +	%.2 =w loadw thread $b +	%.3 =w add %.1, %.2 +	%.4 =w loadw thread $c +	%.5 =w add %.3, %.4 +	%.6 =w loadw thread $d +	%.7 =w add %.5, %.6 +	%.8 =w loadw thread $e +	%.9 =w add %.7, %.8 +	%.10 =w loadw thread $.Lx.2 +	%.11 =w sub %.9, %.10 +	ret %.11 +} | 
