harec

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

commit 9e4e4d40ca274f1dc50e87700b291b6a35833890
parent e53dc8299d6493abf22127e2f67d4f27026134de
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu,  4 Feb 2021 10:54:24 -0500

gen: emit test_array entries for @tests

Diffstat:
Minclude/qbe.h | 2+-
Msrc/emit.c | 6++++--
Msrc/gen.c | 304++++++++++++++++++++++++++++++++++++++++++-------------------------------------
3 files changed, 168 insertions(+), 144 deletions(-)

diff --git a/include/qbe.h b/include/qbe.h @@ -239,7 +239,7 @@ struct qbe_data_item { struct qbe_data { size_t align; - char *section; + char *section, *secflags; struct qbe_data_item items; }; diff --git a/src/emit.c b/src/emit.c @@ -235,8 +235,10 @@ emit_data(struct qbe_def *def, FILE *out) { assert(def->kind == Q_DATA); fprintf(out, "%sdata ", def->exported ? "export " : ""); - if (def->data.section) { - // XXX: Presumes section name does not need to be escaped + if (def->data.section && def->data.secflags) { + fprintf(out, "section \"%s\" \"%s\" ", + def->data.section, def->data.secflags); + } else if (def->data.section) { fprintf(out, "section \"%s\" ", def->data.section); } fprintf(out, "$%s = { ", def->name); diff --git a/src/gen.c b/src/gen.c @@ -2148,139 +2148,7 @@ gen_expression(struct gen_context *ctx, } } -static void -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 & FN_TEST)); // TODO - - struct qbe_def *qdef = xcalloc(1, sizeof(struct qbe_def)); - qdef->kind = Q_FUNC; - qdef->exported = decl->exported; - qdef->name = decl->symbol ? strdup(decl->symbol) : ident_to_sym(&decl->ident); - qdef->func.returns = qtype_for_type(ctx, fntype->func.result, false); - ctx->current = &qdef->func; - - struct qbe_statement start_label = {0}; - genl(&start_label, &ctx->id, "start.%d"); - push(&qdef->func.prelude, &start_label); - - struct qbe_func_param *param, **next = &qdef->func.params; - struct scope_object *obj = decl->func.scope->objects; - while (obj) { - param = *next = xcalloc(1, sizeof(struct qbe_func_param)); - assert(!obj->ident.ns); // Invariant - param->name = strdup(obj->ident.name); - param->type = qtype_for_type(ctx, obj->type, false); - - if (type_is_aggregate(obj->type)) { - struct gen_binding *binding = - xcalloc(1, sizeof(struct gen_binding)); - binding->name = strdup(param->name); - binding->object = obj; - binding->next = ctx->bindings; - ctx->bindings = binding; - } else { - struct qbe_value val; - binding_alloc(ctx, obj, &val, "param.%d"); - struct qbe_value src = { - .kind = QV_TEMPORARY, - .type = param->type, - .name = param->name, - }; - gen_store(ctx, &val, &src); - } - - obj = obj->next; - next = &param->next; - } - - struct qbe_statement end_label = {0}; - struct qbe_value end_label_v = { - .kind = QV_LABEL, - .name = strdup(genl(&end_label, &ctx->id, "end.%d")), - }; - ctx->end_label = &end_label_v; - - struct qbe_value rval = {0}; - if (fntype->func.result->storage != TYPE_STORAGE_VOID) { - alloc_temp(ctx, &rval, fntype->func.result, "ret.%d"); - if (type_is_aggregate(fntype->func.result)) { - rval.indirect = false; - } - ctx->return_value = &rval; - } else { - ctx->return_value = NULL; - } - - push_scope(ctx, SCOPE_FUNC, &end_label_v); - pushl(&qdef->func, &ctx->id, "body.%d"); - gen_expression(ctx, func->body, ctx->return_value); - gen_defers(ctx, ctx->scope); - push(&qdef->func.body, &end_label); - pop_scope(ctx); - - if (fntype->func.result->storage != TYPE_STORAGE_VOID) { - if (type_is_aggregate(fntype->func.result)) { - pushi(&qdef->func, NULL, Q_RET, ctx->return_value, NULL); - } else { - struct qbe_value load = {0}; - gen_loadtemp(ctx, &load, ctx->return_value, - qdef->func.returns, - type_is_signed(fntype->func.result)); - pushi(&qdef->func, NULL, Q_RET, &load, NULL); - } - } else { - pushi(&qdef->func, NULL, Q_RET, NULL); - } - - // Free bindings - struct gen_binding *binding = ctx->bindings; - while (binding) { - struct gen_binding *next = binding->next; - free(binding->name); - free(binding); - binding = next; - } - ctx->bindings = NULL; - - 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 +static struct qbe_data_item * gen_data_item(struct gen_context *ctx, struct expression *expr, struct qbe_data_item *item) { @@ -2335,10 +2203,7 @@ gen_data_item(struct gen_context *ctx, struct expression *expr, size_t n = type->array.length; for (struct array_constant *c = constant->array; c && n; c = c->next ? c->next : c, --n) { - gen_data_item(ctx, c->value, item); - while (item->next) { - item = item->next; - } + item = gen_data_item(ctx, c->value, item); if (n > 1 || c->next) { item->next = xcalloc(1, sizeof(struct qbe_data_item)); @@ -2415,10 +2280,7 @@ gen_data_item(struct gen_context *ctx, struct expression *expr, case TYPE_STORAGE_STRUCT: for (struct struct_constant *f = constant->_struct; f; f = f->next) { - gen_data_item(ctx, f->value, item); - while (item->next) { - item = item->next; - } + item = gen_data_item(ctx, f->value, item); if (f->next) { const struct struct_field *f1 = f->field; const struct struct_field *f2 = f->next->field; @@ -2448,6 +2310,166 @@ gen_data_item(struct gen_context *ctx, struct expression *expr, case TYPE_STORAGE_VOID: assert(0); // Invariant } + + return item; +} + +static void +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; + + struct qbe_def *qdef = xcalloc(1, sizeof(struct qbe_def)); + qdef->kind = Q_FUNC; + qdef->exported = decl->exported; + qdef->name = decl->symbol ? strdup(decl->symbol) : ident_to_sym(&decl->ident); + qdef->func.returns = qtype_for_type(ctx, fntype->func.result, false); + ctx->current = &qdef->func; + + struct qbe_statement start_label = {0}; + genl(&start_label, &ctx->id, "start.%d"); + push(&qdef->func.prelude, &start_label); + + struct qbe_func_param *param, **next = &qdef->func.params; + struct scope_object *obj = decl->func.scope->objects; + while (obj) { + param = *next = xcalloc(1, sizeof(struct qbe_func_param)); + assert(!obj->ident.ns); // Invariant + param->name = strdup(obj->ident.name); + param->type = qtype_for_type(ctx, obj->type, false); + + if (type_is_aggregate(obj->type)) { + struct gen_binding *binding = + xcalloc(1, sizeof(struct gen_binding)); + binding->name = strdup(param->name); + binding->object = obj; + binding->next = ctx->bindings; + ctx->bindings = binding; + } else { + struct qbe_value val; + binding_alloc(ctx, obj, &val, "param.%d"); + struct qbe_value src = { + .kind = QV_TEMPORARY, + .type = param->type, + .name = param->name, + }; + gen_store(ctx, &val, &src); + } + + obj = obj->next; + next = &param->next; + } + + struct qbe_statement end_label = {0}; + struct qbe_value end_label_v = { + .kind = QV_LABEL, + .name = strdup(genl(&end_label, &ctx->id, "end.%d")), + }; + ctx->end_label = &end_label_v; + + struct qbe_value rval = {0}; + if (fntype->func.result->storage != TYPE_STORAGE_VOID) { + alloc_temp(ctx, &rval, fntype->func.result, "ret.%d"); + if (type_is_aggregate(fntype->func.result)) { + rval.indirect = false; + } + ctx->return_value = &rval; + } else { + ctx->return_value = NULL; + } + + push_scope(ctx, SCOPE_FUNC, &end_label_v); + pushl(&qdef->func, &ctx->id, "body.%d"); + gen_expression(ctx, func->body, ctx->return_value); + gen_defers(ctx, ctx->scope); + push(&qdef->func.body, &end_label); + pop_scope(ctx); + + if (fntype->func.result->storage != TYPE_STORAGE_VOID) { + if (type_is_aggregate(fntype->func.result)) { + pushi(&qdef->func, NULL, Q_RET, ctx->return_value, NULL); + } else { + struct qbe_value load = {0}; + gen_loadtemp(ctx, &load, ctx->return_value, + qdef->func.returns, + type_is_signed(fntype->func.result)); + pushi(&qdef->func, NULL, Q_RET, &load, NULL); + } + } else { + pushi(&qdef->func, NULL, Q_RET, NULL); + } + + // Free bindings + struct gen_binding *binding = ctx->bindings; + while (binding) { + struct gen_binding *next = binding->next; + free(binding->name); + free(binding); + binding = next; + } + ctx->bindings = NULL; + + 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); + } + + if (func->flags & FN_TEST) { + struct qbe_def *tdef = xcalloc(1, sizeof(struct qbe_def)); + tdef->kind = Q_DATA; + int l = snprintf(NULL, 0, ".test.%s", qdef->name); + tdef->name = xcalloc(l + 1, 1); + snprintf(tdef->name, l + 1, ".test.%s", qdef->name); + tdef->data.align = 8; + tdef->data.section = strdup(".test_array"); + tdef->data.secflags = strdup("aw"); + + struct qbe_data_item *item = &tdef->data.items; + struct expression name = { + .type = EXPR_CONSTANT, + .result = &builtin_type_str, + }; + name.constant.string.value = identifier_unparse(&decl->ident); + name.constant.string.len = strlen(name.constant.string.value); + item = gen_data_item(ctx, &name, item); + item->next = xcalloc(1, sizeof(struct qbe_data_item)); + item = item->next; + item->type = QD_VALUE; + item->value.kind = QV_GLOBAL; + item->value.type = &qbe_long; + item->value.name = strdup(qdef->name); + qbe_append_def(ctx->out, tdef); + } } static void