Skip to content

Commit

Permalink
Add thread-local variable
Browse files Browse the repository at this point in the history
  • Loading branch information
rui314 committed Sep 30, 2020
1 parent f284c82 commit 79644e5
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 11 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ $(OBJS): chibicc.h

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

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

test-stage2: $(TESTS:test/%=stage2/test/%)
for i in $^; do echo $$i; ./$$i || exit 1; echo; done
Expand Down
1 change: 1 addition & 0 deletions chibicc.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ struct Obj {

// Global variable
bool is_tentative;
bool is_tls;
char *init_data;
Relocation *rel;

Expand Down
24 changes: 21 additions & 3 deletions codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ static void gen_addr(Node *node) {
return;
}

// Thread-local variable
if (node->var->is_tls) {
println(" mov %%fs:0, %%rax");
println(" add $%s@tpoff, %%rax", node->var->name);
return;
}

// Here, we generate an absolute address of a function or a global
// variable. Even though they exist at a certain address at runtime,
// their addresses are not known at link-time for the following
Expand Down Expand Up @@ -1135,13 +1142,19 @@ static void emit_data(Obj *prog) {
? MAX(16, var->align) : var->align;
println(" .align %d", align);

if (opt_fcommon && var->is_tentative) {
// Common symbol
if (opt_fcommon && var->is_tentative && !var->is_tls) {
println(" .comm %s, %d, %d", var->name, var->ty->size, align);
continue;
}

// .data or .tdata
if (var->init_data) {
println(" .data");
if (var->is_tls)
println(" .section .tdata,\"awT\",@progbits");
else
println(" .data");

println("%s:", var->name);

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

println(" .bss");
// .bss or .tbss
if (var->is_tls)
println(" .section .tbss,\"awT\",@nobits");
else
println(" .bss");

println("%s:", var->name);
println(" .zero %d", var->ty->size);
}
Expand Down
15 changes: 11 additions & 4 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ typedef struct {
bool is_static;
bool is_extern;
bool is_inline;
bool is_tls;
int align;
} VarAttr;

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

Expand All @@ -427,11 +428,15 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) {
attr->is_static = true;
else if (equal(tok, "extern"))
attr->is_extern = true;
else
else if (equal(tok, "inline"))
attr->is_inline = true;
else
attr->is_tls = true;

if (attr->is_typedef && attr->is_static + attr->is_extern + attr->is_inline > 1)
error_tok(tok, "typedef may not be used together with static, extern or inline");
if (attr->is_typedef &&
attr->is_static + attr->is_extern + attr->is_inline + attr->is_tls > 1)
error_tok(tok, "typedef may not be used together with static,"
" extern, inline, __thread or _Thread_local");
tok = tok->next;
continue;
}
Expand Down Expand Up @@ -1411,6 +1416,7 @@ static bool is_typename(Token *tok) {
"typedef", "enum", "static", "extern", "_Alignas", "signed", "unsigned",
"const", "volatile", "auto", "register", "restrict", "__restrict",
"__restrict__", "_Noreturn", "float", "double", "typeof", "inline",
"_Thread_local", "__thread",
};

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

Expand Down
1 change: 0 additions & 1 deletion preprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,6 @@ void init_macros(void) {
define_macro("__STDC_HOSTED__", "1");
define_macro("__STDC_NO_ATOMICS__", "1");
define_macro("__STDC_NO_COMPLEX__", "1");
define_macro("__STDC_NO_THREADS__", "1");
define_macro("__STDC_NO_VLA__", "1");
define_macro("__STDC_UTF_16__", "1");
define_macro("__STDC_UTF_32__", "1");
Expand Down
41 changes: 41 additions & 0 deletions test/tls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "test.h"
#include <stdio.h>
#include <threads.h>

thread_local int v1;
thread_local int v2 = 5;
int v3 = 7;

int thread_main(void *unused) {
ASSERT(0, v1);
ASSERT(5, v2);
ASSERT(7, v3);

v1 = 1;
v2 = 2;
v3 = 3;

ASSERT(1, v1);
ASSERT(2, v2);
ASSERT(3, v3);

return 0;
}

int main() {
thrd_t thr;

ASSERT(0, v1);
ASSERT(5, v2);
ASSERT(7, v3);

ASSERT(thrd_success, thrd_create(&thr, thread_main, NULL));
ASSERT(thrd_success, thrd_join(thr, NULL));

ASSERT(0, v1);
ASSERT(5, v2);
ASSERT(3, v3);

printf("OK\n");
return 0;
}
2 changes: 1 addition & 1 deletion tokenize.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ static bool is_keyword(Token *tok) {
"default", "extern", "_Alignof", "_Alignas", "do", "signed",
"unsigned", "const", "volatile", "auto", "register", "restrict",
"__restrict", "__restrict__", "_Noreturn", "float", "double",
"typeof", "asm",
"typeof", "asm", "_Thread_local", "__thread",
};

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

0 comments on commit 79644e5

Please sign in to comment.