Skip to content

Commit 6143463

Browse files
committed
Language: add tlocal keyword for thread local storage class
* allow local and global variables with thread local storage class * most `local` variables in the compiler should be made `tlocal`.
1 parent eaacc45 commit 6143463

9 files changed

Lines changed: 53 additions & 14 deletions

File tree

ast/var_decl.c2

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ type VarDeclBits struct {
6161
u32 addr_used : 1;
6262
AutoAttr auto_attr : 2; // for parameters only
6363
FormatAttr format_attr : 2; // for parameters only
64+
u32 is_tlocal : 1; // local or global variables with thread local storage
6465
}
6566

6667
public type BitFieldLayout struct {
@@ -320,6 +321,15 @@ public fn void VarDecl.setLocal(VarDecl* d, bool has_local) {
320321
d.base.varDeclBits.has_local = has_local;
321322
}
322323

324+
public fn bool VarDecl.isTLocal(const VarDecl* d) {
325+
return d.base.varDeclBits.is_tlocal;
326+
}
327+
328+
public fn void VarDecl.setTLocal(VarDecl* d) {
329+
d.base.varDeclBits.has_local = true;
330+
d.base.varDeclBits.is_tlocal = true;
331+
}
332+
323333
public fn void VarDecl.setInitCall(VarDecl* d, bool has_init_call) {
324334
d.base.varDeclBits.has_init_call = has_init_call;
325335
}

generator/c/c_generator.c2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,7 @@ const char[] C_defines =
14621462

14631463
#define NULL ((void*)0)
14641464
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
1465+
#define tlocal _Thread_local
14651466
```;
14661467

14671468
fn void Generator.emit_external_header(Generator* gen, const char* target) {

generator/c/c_generator_stmt.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import string_buffer;
2121
fn void Generator.emitVarDecl(Generator* gen, VarDecl* vd, string_buffer.Buf* out, bool emit_init, bool first) {
2222
Decl* d = (Decl*)vd;
2323
if (first) {
24-
if (vd.hasLocalQualifier()) out.add("static ");
24+
if (vd.hasLocalQualifier()) out.add(vd.isTLocal() ? "tlocal " : "static ");
2525
gen.emitTypePre(out, d.getType());
2626
} else {
2727
out.add1(',');

generator/c2i/c2i_generator_decl.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ fn void Generator.emitVarDecl(Generator* gen, string_buffer.Buf* out, const VarD
4242
Decl* d = (Decl*)vd;
4343

4444
if (first) {
45-
if (vd.hasLocalQualifier()) out.add("local ");
45+
if (vd.hasLocalQualifier()) out.add(vd.isTLocal() ? "tlocal" : "local ");
4646
gen.emitType(out, d.getType());
4747
} else {
4848
out.add1(',');

parser/c2_parser.c2

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,8 @@ fn bool Parser.parseFunctionParams(Parser* p, DeclList* params, bool is_public,
647647
param_default ::= EQUALS constant_expression.
648648
*/
649649
fn VarDecl* Parser.parseParamDecl(Parser* p, bool is_public, bool accept_default) {
650-
if (p.tok.kind == KW_local) p.error("keyword 'local' is not allowed here");
650+
if (p.tok.kind == KW_local || p.tok.kind == KW_tlocal)
651+
p.error("keyword '%s' is not allowed here", p.tok.kind.str());
651652

652653
TypeRefHolder ref.init();
653654
// Note: dont check arrays in this phase, but in Analyser
@@ -756,6 +757,9 @@ fn void Parser.parseArrayEntry(Parser* p) {
756757
fn void Parser.parseVarDecl(Parser* p, bool is_public) {
757758
if (p.tok.kind == KW_local) p.error("keyword 'local' cannot be used at file scope");
758759

760+
bool has_tlocal = (p.tok.kind == KW_tlocal);
761+
if (has_tlocal) p.consumeToken();
762+
759763
bool need_semi = true;
760764
TypeRefHolder ref.init();
761765
p.parseTypeSpecifier(&ref);
@@ -814,8 +818,9 @@ fn void Parser.parseVarDecl(Parser* p, bool is_public) {
814818
}
815819

816820
bool has_embed = p.builder.hasEmbedAttr();
817-
Decl* d = (Decl*)p.builder.actOnGlobalVarDecl(name, loc, is_public, &ref, assignLoc, has_embed, initValue);
818-
p.applyAttributes(d, num_attr);
821+
VarDecl* vd = p.builder.actOnGlobalVarDecl(name, loc, is_public, &ref, assignLoc, has_embed, initValue);
822+
if (has_tlocal) vd.setTLocal();
823+
p.applyAttributes((Decl*)vd, num_attr);
819824

820825
if (p.tok.kind != Comma)
821826
break;

parser/c2_parser_stmt.c2

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ fn Stmt* Parser.parseStmt(Parser* p) {
5757
case KW_int ... KW_unsigned: // C type keywords
5858
case KW_const:
5959
case KW_local:
60+
case KW_tlocal:
6061
case KW_volatile:
6162
case KW_void:
6263
// checkSemi, allowLocal, !isCondition
@@ -506,10 +507,10 @@ fn Stmt* Parser.parseWhileStmt(Parser* p) {
506507
fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool isCondition) {
507508
VarDecl*[MaxMultiDecl] decls;
508509
u32 num_decls = 0;
509-
bool has_local = false;
510-
if (p.tok.kind == KW_local) {
511-
has_local = true;
512-
if (!allowLocal) p.error("keyword 'local' is not allowed here");
510+
bool has_local = (p.tok.kind == KW_local);
511+
bool has_tlocal = (p.tok.kind == KW_tlocal);
512+
if (has_local | has_tlocal) {
513+
if (!allowLocal) p.error("keyword '%s' is not allowed here", p.tok.kind.str());
513514
p.consumeToken();
514515
}
515516

@@ -548,7 +549,7 @@ fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool i
548549
case Dot:
549550
if (p.peekToken(1) == Identifier
550551
&& p.peekToken(2) == LParen) {
551-
if (has_local)
552+
if (has_local | has_tlocal)
552553
p.error("local qualified variables cannot have an init call");
553554
if (isCondition)
554555
p.error("cannot use an init call inside a condition");
@@ -571,7 +572,9 @@ fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool i
571572
default:
572573
break;
573574
}
574-
decls[num_decls++] = p.builder.actOnVarDecl(name, loc, &ref, assignLoc, initValue, has_local, has_init_call);
575+
VarDecl* vd = p.builder.actOnVarDecl(name, loc, &ref, assignLoc, initValue, has_local, has_init_call);
576+
if (has_tlocal) vd.setTLocal();
577+
decls[num_decls++] = vd;
575578
if (p.tok.kind != Comma)
576579
break;
577580
p.consumeToken();
@@ -628,7 +631,7 @@ fn bool Parser.isDeclaration(Parser* p) {
628631
const Kind kind = p.tok.kind;
629632
if (kind == Identifier) return p.isTypeSpec();
630633
if (kind.isTypeKeyword() && (p.peekToken(1) != Dot)) return true;
631-
if (kind == KW_local) return true;
634+
if (kind == KW_local || kind == KW_tlocal) return true;
632635
if (kind.isQualifier()) return true;
633636
return false;
634637
}

parser/keywords.c2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import token local;
2121
import string;
2222

2323
public type Info struct {
24-
// Note: should be big enough to hold all keywords (4+436+216 with alignment)
25-
Kind[656] indexes;
24+
// Note: should be big enough to hold all keywords (4+436+220 with alignment)
25+
Kind[660] indexes;
2626
u32 max_index;
2727
}
2828

parser/token.c2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ public type Kind enum u8 {
139139
KW_struct,
140140
KW_switch,
141141
KW_template,
142+
KW_tlocal,
142143
KW_to_container,
143144
KW_true,
144145
KW_type,
@@ -298,6 +299,7 @@ const char*[Kind] token_names = {
298299
[KW_struct] = "struct",
299300
[KW_switch] = "switch",
300301
[KW_template] = "template",
302+
[KW_tlocal] = "tlocal",
301303
[KW_to_container] = "to_container",
302304
[KW_true] = "true",
303305
[KW_type] = "type",
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @recipe bin
2+
$warnings no-unused
3+
$backend c
4+
5+
// @file{file1}
6+
module test;
7+
8+
fn void test1() {
9+
tlocal i32 a = 10;
10+
}
11+
12+
// @expect{atleast, cgen/build.c}
13+
14+
static void test_test1(void)
15+
{
16+
tlocal int a = 10;
17+
}
18+

0 commit comments

Comments
 (0)