harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 5be49d19fb6c5901e243cfa3255c2a44458f1682
parent 2afdcd49101ac94d37c0ea9cf924a05610e54899
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 12 Jan 2021 15:40:05 -0500

Implement @init/@fini

Diffstat:
Minclude/qbe.h | 1+
Mrt/rtmain.ha | 18++++++++++++++++++
Msrc/check.c | 4++++
Msrc/emit.c | 9++++++---
Msrc/gen.c | 32+++++++++++++++++++++++++++++++-
Msrc/parse.c | 9+++++++--
Mtests/09-funcs.ha | 13+++++++++++++
Mtests/run | 9++++++++-
8 files changed, 88 insertions(+), 7 deletions(-)

diff --git a/include/qbe.h b/include/qbe.h @@ -238,6 +238,7 @@ struct qbe_data_item { struct qbe_data { size_t align; + char *section; struct qbe_data_item items; }; diff --git a/rt/rtmain.ha b/rt/rtmain.ha @@ -1,7 +1,25 @@ @symbol("main") fn main() int; fn exit(status: int) void; +let @symbol("__init_array_start") init_start: [*]*fn() void; +let @symbol("__init_array_end") init_end: [*]*fn() void; +let @symbol("__fini_array_start") fini_start: [*]*fn() void; +let @symbol("__fini_array_end") fini_end: [*]*fn() void; + export fn start_ha(iv: [*]uintptr) void = { + const ninit = (&init_end: uintptr - &init_start: uintptr): size + / size(*fn() void); + for (let i = 0z; i < ninit; i += 1z) { + init_start[i](); + }; + main(); + + const nfini = (&fini_end: uintptr - &fini_start: uintptr): size + / size(*fn() void); + for (let i = 0z; i < nfini; i += 1z) { + fini_start[i](); + }; + exit(0); }; diff --git a/src/check.c b/src/check.c @@ -1006,6 +1006,10 @@ check_global(struct context *ctx, const struct ast_decl *adecl) { const struct ast_global_decl *agdecl = &adecl->global; + if (!agdecl->init) { + return NULL; // Forward declaration + } + const struct type *type = type_store_lookup_atype( &ctx->store, agdecl->type); diff --git a/src/emit.c b/src/emit.c @@ -223,9 +223,12 @@ static void emit_data(struct qbe_def *def, FILE *out) { assert(def->kind == Q_DATA); - fprintf(out, "%sdata $%s = { ", - def->exported ? "export " : "", - def->name); + fprintf(out, "%sdata ", def->exported ? "export " : ""); + if (def->data.section) { + // XXX: Presumes section name does not need to be escaped + fprintf(out, "section \"%s\" ", def->data.section); + } + fprintf(out, "$%s = { ", def->name); struct qbe_data_item *item = &def->data.items; while (item) { diff --git a/src/gen.c b/src/gen.c @@ -1200,7 +1200,7 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl) assert(decl->type == DECL_FUNC); const struct function_decl *func = &decl->func; const struct type *fntype = func->type; - assert(func->flags == 0); // TODO + assert(!(func->flags & FN_TEST)); // TODO struct qbe_def *qdef = xcalloc(1, sizeof(struct qbe_def)); qdef->kind = Q_FUNC; @@ -1284,6 +1284,36 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl) qbe_append_def(ctx->out, qdef); ctx->current = NULL; + + if (func->flags & FN_INIT) { + struct qbe_def *idef = xcalloc(1, sizeof(struct qbe_def)); + idef->kind = Q_DATA; + int l = snprintf(NULL, 0, ".init.%s", qdef->name); + idef->name = xcalloc(l + 1, 1); + snprintf(idef->name, l + 1, ".init.%s", qdef->name); + idef->data.align = 8; + idef->data.section = strdup(".init_array"); + idef->data.items.type = QD_VALUE; + idef->data.items.value.kind = QV_GLOBAL; + idef->data.items.value.type = &qbe_long; + idef->data.items.value.name = strdup(qdef->name); + qbe_append_def(ctx->out, idef); + } + + if (func->flags & FN_FINI) { + struct qbe_def *fdef = xcalloc(1, sizeof(struct qbe_def)); + fdef->kind = Q_DATA; + int l = snprintf(NULL, 0, ".fini.%s", qdef->name); + fdef->name = xcalloc(l + 1, 1); + snprintf(fdef->name, l + 1, ".fini.%s", qdef->name); + fdef->data.align = 8; + fdef->data.section = strdup(".fini_array"); + fdef->data.items.type = QD_VALUE; + fdef->data.items.value.kind = QV_GLOBAL; + fdef->data.items.value.type = &qbe_long; + fdef->data.items.value.name = strdup(qdef->name); + qbe_append_def(ctx->out, fdef); + } } static void diff --git a/src/parse.c b/src/parse.c @@ -1882,8 +1882,13 @@ parse_global_decl(struct lexer *lexer, enum lexical_token mode, if (mode == T_CONST) { i->type->flags |= TYPE_CONST; } - want(lexer, T_EQUAL, NULL); - i->init = parse_simple_expression(lexer); + + if (lex(lexer, &tok) == T_EQUAL) { + i->init = parse_simple_expression(lexer); + } else { + unlex(lexer, &tok); + } + switch (lex(lexer, &tok)) { case T_COMMA: lex(lexer, &tok); diff --git a/tests/09-funcs.ha b/tests/09-funcs.ha @@ -1,3 +1,5 @@ +@noreturn fn rt::exit(status: int) void; + fn addone(x: *int) void = { *x += 1; }; @@ -21,7 +23,18 @@ fn vaargs(expected: []int, values: int...) void = { }; }; +let x: int = 42; + +@init fn init() void = { + x = 1337; +}; + +@fini fn fini() void = { + rt::exit(42); // Magic number +}; + export fn main() void = { pointers(); vaargs([1, 2, 3], 1, 2, 3); + assert(x == 1337); }; diff --git a/tests/run b/tests/run @@ -13,7 +13,14 @@ do ntests=$((ntests+1)) name="$(basename "$f")" printf '%-40s ...' "$name" - if $f + if [ "$name" = "09-funcs" ] + then + expected=42 + else + expected=0 + fi + $f + if [ $? -eq $expected ] then npass=$((npass+1)) printf 'PASS\n'