diff options
author | Drew DeVault <sir@cmpwn.com> | 2023-01-31 19:33:47 +0100 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2024-04-19 20:30:01 -0700 |
commit | 0c1f837141457574bd71ef0d761613ba6a941380 (patch) | |
tree | 78877e94444d1e26d4c4d9e9448e4c1508db0697 | |
parent | d345c729b2418f5f536e7fc401047a9a473bdf01 (diff) |
implement _Thread_local storage class
Implements: https://todo.sr.ht/~mcf/cproc/8
-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 +} |