commit ef3e7d022fcfaeeda8a7bb9a133a1e33a55e4305
parent 370029bac49b44a3f43fea025a89f44b2f20e8c7
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 27 Jul 2022 14:02:38 +0200
Implement @threadlocal globals
Diffstat:
14 files changed, 45 insertions(+), 10 deletions(-)
diff --git a/include/ast.h b/include/ast.h
@@ -360,6 +360,7 @@ struct ast_expression {
struct ast_global_decl {
char *symbol;
+ bool threadlocal;
struct identifier ident;
struct ast_type *type;
struct ast_expression *init;
diff --git a/include/check.h b/include/check.h
@@ -68,6 +68,7 @@ struct function_decl {
struct global_decl {
const struct type *type;
struct expression *value; // EXPR_CONSTANT
+ bool threadlocal;
};
enum declaration_type {
diff --git a/include/gen.h b/include/gen.h
@@ -28,6 +28,7 @@ enum gen_value_kind {
struct gen_value {
enum gen_value_kind kind;
+ bool threadlocal;
const struct type *type;
union {
char *name;
diff --git a/include/lex.h b/include/lex.h
@@ -15,6 +15,7 @@ enum lexical_token {
T_ATTR_OFFSET,
T_ATTR_SYMBOL,
T_ATTR_TEST,
+ T_ATTR_THREADLOCAL,
T_UNDERSCORE,
T_ABORT,
T_ALLOC,
diff --git a/include/qbe.h b/include/qbe.h
@@ -55,6 +55,7 @@ enum qbe_value_kind {
struct qbe_value {
enum qbe_value_kind kind;
+ bool threadlocal;
const struct qbe_type *type;
union {
char *name;
@@ -233,6 +234,7 @@ struct qbe_data_item {
struct qbe_data {
size_t align;
char *section, *secflags;
+ bool threadlocal;
struct qbe_data_item items;
};
diff --git a/include/scope.h b/include/scope.h
@@ -18,6 +18,7 @@ struct scope_object {
// name is the name of the object within this scope (for lookups)
// ident is the global identifier (these may be different in some cases)
struct identifier name, ident;
+ bool threadlocal;
const struct type *type;
struct expression *value; // For O_CONST
@@ -82,12 +83,12 @@ void scope_object_init(struct scope_object *obj, enum object_type otype,
void scope_insert_from_object(struct scope *scope, struct scope_object *object);
-const struct scope_object *scope_insert(
+struct scope_object *scope_insert(
struct scope *scope, enum object_type otype,
const struct identifier *ident, const struct identifier *name,
const struct type *type, struct expression *value);
-const struct scope_object *scope_lookup(struct scope *scope,
+struct scope_object *scope_lookup(struct scope *scope,
const struct identifier *ident);
#endif
diff --git a/src/check.c b/src/check.c
@@ -3275,6 +3275,7 @@ check_global(struct context *ctx,
struct declaration *decl = xcalloc(1, sizeof(struct declaration));
decl->type = DECL_GLOBAL;
decl->global.type = type;
+ decl->global.threadlocal = adecl->threadlocal;
if (adecl->symbol) {
decl->symbol = strdup(adecl->symbol);
@@ -3616,7 +3617,7 @@ scan_global(struct context *ctx, const struct ast_global_decl *decl)
expect(ctx, &decl->type->loc, decl->init,
"Cannot infer array length without an initializer");
- // TODO: Free initialier
+ // TODO: Free initializer
struct expression *initializer =
xcalloc(1, sizeof(struct expression));
check_expression(ctx, decl->init, initializer, type);
@@ -3638,7 +3639,10 @@ scan_global(struct context *ctx, const struct ast_global_decl *decl)
} else {
mkident(ctx, &ident, &decl->ident);
}
- return scope_insert(ctx->unit, O_DECL, &ident, &decl->ident, type, NULL);
+ struct scope_object *global = scope_insert(ctx->unit, O_DECL,
+ &ident, &decl->ident, type, NULL);
+ global->threadlocal = decl->threadlocal;
+ return global;
}
const struct scope_object *
@@ -4079,8 +4083,10 @@ load_import(struct context *ctx, struct ast_imports *import,
expect(ctx, &member->loc, false, "Unknown object '%s'",
identifier_unparse(&ident));
}
- scope_insert(scope, obj->otype, &obj->ident,
- &name, obj->type, obj->value);
+ struct scope_object *new = scope_insert(
+ scope, obj->otype, &obj->ident,
+ &name, obj->type, obj->value);
+ new->threadlocal = obj->threadlocal;
if (obj->otype != O_TYPE
|| type_dealias(obj->type)->storage
!= STORAGE_ENUM) {
@@ -4110,10 +4116,12 @@ load_import(struct context *ctx, struct ast_imports *import,
continue;
}
+ struct scope_object *new;
if (!(import->mode & AST_IMPORT_ALIAS)
&& import->ident.ns != NULL) {
- scope_insert(scope, obj->otype, &obj->ident,
+ new = scope_insert(scope, obj->otype, &obj->ident,
&obj->name, obj->type, obj->value);
+ new->threadlocal = obj->threadlocal;
}
struct identifier ns, name = {
@@ -4128,8 +4136,9 @@ load_import(struct context *ctx, struct ast_imports *import,
};
name.ns = &ns;
};
- scope_insert(scope, obj->otype, &obj->ident,
+ new = scope_insert(scope, obj->otype, &obj->ident,
&name, obj->type, obj->value);
+ new->threadlocal = obj->threadlocal;
}
}
}
diff --git a/src/emit.c b/src/emit.c
@@ -119,6 +119,9 @@ emit_value(struct qbe_value *val, FILE *out)
emit_const(val, out);
break;
case QV_GLOBAL:
+ if (val->threadlocal) {
+ fprintf(out, "thread ");
+ }
fprintf(out, "$%s", val->name);
break;
case QV_LABEL:
@@ -310,6 +313,12 @@ emit_data(struct qbe_def *def, FILE *out)
def->data.section, def->data.secflags);
} else if (def->data.section) {
fprintf(out, "section \"%s\"", def->data.section);
+ } else if (def->data.threadlocal) {
+ if (is_zeroes(&def->data.items)) {
+ fprintf(out, "section \".tbss\" \"awT\"");
+ } else {
+ fprintf(out, "section \".tdata\" \"awT\"");
+ }
} else if (is_zeroes(&def->data.items)) {
fprintf(out, "section \".bss.%s\"", def->name);
} else {
diff --git a/src/gen.c b/src/gen.c
@@ -246,6 +246,7 @@ gen_access_ident(struct gen_context *ctx, const struct expression *expr)
.kind = GV_GLOBAL,
.type = obj->type,
.name = ident_to_sym(&obj->ident),
+ .threadlocal = obj->threadlocal,
};
case O_CONST:
case O_TYPE:
@@ -3692,6 +3693,7 @@ gen_global_decl(struct gen_context *ctx, const struct declaration *decl)
struct qbe_def *qdef = xcalloc(1, sizeof(struct qbe_def));
qdef->kind = Q_DATA;
qdef->data.align = ALIGN_UNDEFINED;
+ qdef->data.threadlocal = global->threadlocal;
qdef->exported = decl->exported;
qdef->name = ident_to_sym(&decl->ident);
gen_data_item(ctx, global->value, &qdef->data.items);
diff --git a/src/genutil.c b/src/genutil.c
@@ -28,6 +28,7 @@ mkqval(struct gen_context *ctx, struct gen_value *value)
case GV_GLOBAL:
qval.kind = QV_GLOBAL;
qval.name = value->name;
+ qval.threadlocal = value->threadlocal;
break;
case GV_TEMP:
qval.kind = QV_TEMPORARY;
diff --git a/src/lex.c b/src/lex.c
@@ -22,6 +22,7 @@ static const char *tokens[] = {
[T_ATTR_OFFSET] = "@offset",
[T_ATTR_SYMBOL] = "@symbol",
[T_ATTR_TEST] = "@test",
+ [T_ATTR_THREADLOCAL] = "@threadlocal",
[T_UNDERSCORE] = "_",
[T_ABORT] = "abort",
[T_ALLOC] = "alloc",
diff --git a/src/parse.c b/src/parse.c
@@ -2434,6 +2434,9 @@ parse_global_decl(struct lexer *lexer, enum lexical_token mode,
case T_ATTR_SYMBOL:
i->symbol = parse_attr_symbol(lexer);
break;
+ case T_ATTR_THREADLOCAL:
+ i->threadlocal = true;
+ break;
default:
unlex(lexer, &tok);
break;
diff --git a/src/scope.c b/src/scope.c
@@ -116,7 +116,7 @@ scope_insert_from_object(struct scope *scope, struct scope_object *object)
*bucket = object;
}
-const struct scope_object *
+struct scope_object *
scope_insert(struct scope *scope, enum object_type otype,
const struct identifier *ident, const struct identifier *name,
const struct type *type, struct expression *value)
@@ -127,7 +127,7 @@ scope_insert(struct scope *scope, enum object_type otype,
return o;
}
-const struct scope_object *
+struct scope_object *
scope_lookup(struct scope *scope, const struct identifier *ident)
{
uint32_t hash = name_hash(FNV1A_INIT, ident);
diff --git a/src/typedef.c b/src/typedef.c
@@ -397,6 +397,9 @@ emit_decl_global(struct declaration *decl, FILE *out)
if (decl->symbol) {
fprintf(out, "@symbol(\"%s\") ", decl->symbol);
}
+ if (decl->global.threadlocal) {
+ fprintf(out, "@threadlocal ");
+ }
fprintf(out, "%s: ", ident);
emit_exported_type(decl->global.type, out, ident);
fprintf(out, ";\n");