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:
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 = ¶m->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 = ¶m->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