Skip to content

Commit 79644e5

Browse files
committed
Add thread-local variable
1 parent f284c82 commit 79644e5

File tree

7 files changed

+77
-11
lines changed

7 files changed

+77
-11
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ $(OBJS): chibicc.h
1515

1616
test/%.exe: chibicc test/%.c
1717
./chibicc -Iinclude -Itest -c -o test/$*.o test/$*.c
18-
$(CC) -o $@ test/$*.o -xc test/common
18+
$(CC) -pthread -o $@ test/$*.o -xc test/common
1919

2020
test: $(TESTS)
2121
for i in $^; do echo $$i; ./$$i || exit 1; echo; done
@@ -35,7 +35,7 @@ stage2/%.o: chibicc %.c
3535
stage2/test/%.exe: stage2/chibicc test/%.c
3636
mkdir -p stage2/test
3737
./stage2/chibicc -Iinclude -Itest -c -o stage2/test/$*.o test/$*.c
38-
$(CC) -o $@ stage2/test/$*.o -xc test/common
38+
$(CC) -pthread -o $@ stage2/test/$*.o -xc test/common
3939

4040
test-stage2: $(TESTS:test/%=stage2/test/%)
4141
for i in $^; do echo $$i; ./$$i || exit 1; echo; done

chibicc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ struct Obj {
138138

139139
// Global variable
140140
bool is_tentative;
141+
bool is_tls;
141142
char *init_data;
142143
Relocation *rel;
143144

codegen.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ static void gen_addr(Node *node) {
6666
return;
6767
}
6868

69+
// Thread-local variable
70+
if (node->var->is_tls) {
71+
println(" mov %%fs:0, %%rax");
72+
println(" add $%s@tpoff, %%rax", node->var->name);
73+
return;
74+
}
75+
6976
// Here, we generate an absolute address of a function or a global
7077
// variable. Even though they exist at a certain address at runtime,
7178
// their addresses are not known at link-time for the following
@@ -1135,13 +1142,19 @@ static void emit_data(Obj *prog) {
11351142
? MAX(16, var->align) : var->align;
11361143
println(" .align %d", align);
11371144

1138-
if (opt_fcommon && var->is_tentative) {
1145+
// Common symbol
1146+
if (opt_fcommon && var->is_tentative && !var->is_tls) {
11391147
println(" .comm %s, %d, %d", var->name, var->ty->size, align);
11401148
continue;
11411149
}
11421150

1151+
// .data or .tdata
11431152
if (var->init_data) {
1144-
println(" .data");
1153+
if (var->is_tls)
1154+
println(" .section .tdata,\"awT\",@progbits");
1155+
else
1156+
println(" .data");
1157+
11451158
println("%s:", var->name);
11461159

11471160
Relocation *rel = var->rel;
@@ -1158,7 +1171,12 @@ static void emit_data(Obj *prog) {
11581171
continue;
11591172
}
11601173

1161-
println(" .bss");
1174+
// .bss or .tbss
1175+
if (var->is_tls)
1176+
println(" .section .tbss,\"awT\",@nobits");
1177+
else
1178+
println(" .bss");
1179+
11621180
println("%s:", var->name);
11631181
println(" .zero %d", var->ty->size);
11641182
}

parse.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ typedef struct {
5757
bool is_static;
5858
bool is_extern;
5959
bool is_inline;
60+
bool is_tls;
6061
int align;
6162
} VarAttr;
6263

@@ -417,7 +418,7 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) {
417418
while (is_typename(tok)) {
418419
// Handle storage class specifiers.
419420
if (equal(tok, "typedef") || equal(tok, "static") || equal(tok, "extern") ||
420-
equal(tok, "inline")) {
421+
equal(tok, "inline") || equal(tok, "_Thread_local") || equal(tok, "__thread")) {
421422
if (!attr)
422423
error_tok(tok, "storage class specifier is not allowed in this context");
423424

@@ -427,11 +428,15 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) {
427428
attr->is_static = true;
428429
else if (equal(tok, "extern"))
429430
attr->is_extern = true;
430-
else
431+
else if (equal(tok, "inline"))
431432
attr->is_inline = true;
433+
else
434+
attr->is_tls = true;
432435

433-
if (attr->is_typedef && attr->is_static + attr->is_extern + attr->is_inline > 1)
434-
error_tok(tok, "typedef may not be used together with static, extern or inline");
436+
if (attr->is_typedef &&
437+
attr->is_static + attr->is_extern + attr->is_inline + attr->is_tls > 1)
438+
error_tok(tok, "typedef may not be used together with static,"
439+
" extern, inline, __thread or _Thread_local");
435440
tok = tok->next;
436441
continue;
437442
}
@@ -1411,6 +1416,7 @@ static bool is_typename(Token *tok) {
14111416
"typedef", "enum", "static", "extern", "_Alignas", "signed", "unsigned",
14121417
"const", "volatile", "auto", "register", "restrict", "__restrict",
14131418
"__restrict__", "_Noreturn", "float", "double", "typeof", "inline",
1419+
"_Thread_local", "__thread",
14141420
};
14151421

14161422
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
@@ -2941,6 +2947,7 @@ static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) {
29412947
Obj *var = new_gvar(get_ident(ty->name), ty);
29422948
var->is_definition = !attr->is_extern;
29432949
var->is_static = attr->is_static;
2950+
var->is_tls = attr->is_tls;
29442951
if (attr->align)
29452952
var->align = attr->align;
29462953

preprocess.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,6 @@ void init_macros(void) {
10201020
define_macro("__STDC_HOSTED__", "1");
10211021
define_macro("__STDC_NO_ATOMICS__", "1");
10221022
define_macro("__STDC_NO_COMPLEX__", "1");
1023-
define_macro("__STDC_NO_THREADS__", "1");
10241023
define_macro("__STDC_NO_VLA__", "1");
10251024
define_macro("__STDC_UTF_16__", "1");
10261025
define_macro("__STDC_UTF_32__", "1");

test/tls.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include "test.h"
2+
#include <stdio.h>
3+
#include <threads.h>
4+
5+
thread_local int v1;
6+
thread_local int v2 = 5;
7+
int v3 = 7;
8+
9+
int thread_main(void *unused) {
10+
ASSERT(0, v1);
11+
ASSERT(5, v2);
12+
ASSERT(7, v3);
13+
14+
v1 = 1;
15+
v2 = 2;
16+
v3 = 3;
17+
18+
ASSERT(1, v1);
19+
ASSERT(2, v2);
20+
ASSERT(3, v3);
21+
22+
return 0;
23+
}
24+
25+
int main() {
26+
thrd_t thr;
27+
28+
ASSERT(0, v1);
29+
ASSERT(5, v2);
30+
ASSERT(7, v3);
31+
32+
ASSERT(thrd_success, thrd_create(&thr, thread_main, NULL));
33+
ASSERT(thrd_success, thrd_join(thr, NULL));
34+
35+
ASSERT(0, v1);
36+
ASSERT(5, v2);
37+
ASSERT(3, v3);
38+
39+
printf("OK\n");
40+
return 0;
41+
}

tokenize.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ static bool is_keyword(Token *tok) {
149149
"default", "extern", "_Alignof", "_Alignas", "do", "signed",
150150
"unsigned", "const", "volatile", "auto", "register", "restrict",
151151
"__restrict", "__restrict__", "_Noreturn", "float", "double",
152-
"typeof", "asm",
152+
"typeof", "asm", "_Thread_local", "__thread",
153153
};
154154

155155
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)

0 commit comments

Comments
 (0)