commit 9aaf10d1ac82911b2154d8bf033d800ac3e19786
parent 873099fe3bd1eed3a6fc6d043caefad035a348f1
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 28 Dec 2020 15:33:32 -0500
gen: initial support for aggregate types
Turns out the C ABI does not use aggregate types per-se for arrays, so
most of this is useless -_-
Diffstat:
5 files changed, 130 insertions(+), 13 deletions(-)
diff --git a/include/qbe.h b/include/qbe.h
@@ -15,9 +15,22 @@ enum qbe_stype {
Q__AGGREGATE = 'A',
};
+struct type;
+struct qbe_type;
+
+struct qbe_field {
+ const struct qbe_type *type;
+ size_t count;
+ struct qbe_field *next;
+};
+
struct qbe_type {
enum qbe_stype stype;
- // TODO: Aggregate type details
+ // Aggregate types only:
+ char *name;
+ size_t align;
+ struct qbe_field fields;
+ const struct type *base;
};
// Simple type singletons
@@ -203,7 +216,7 @@ struct qbe_func {
struct qbe_statements prelude, body;
};
-enum qbe_deftype {
+enum qbe_defkind {
Q_TYPE,
Q_FUNC,
Q_DATA,
@@ -211,16 +224,18 @@ enum qbe_deftype {
struct qbe_def {
char *name;
- enum qbe_deftype type;
+ enum qbe_defkind kind;
bool exported;
union {
struct qbe_func func;
+ struct qbe_type type;
};
struct qbe_def *next;
};
struct qbe_program {
struct qbe_def *defs;
+ struct qbe_def **next;
};
void qbe_append_def(struct qbe_program *prog, struct qbe_def *def);
diff --git a/src/emit.c b/src/emit.c
@@ -16,13 +16,42 @@ emit_qtype(const struct qbe_type *type, FILE *out)
fprintf(out, "%c", (char)type->stype);
break;
case Q__AGGREGATE:
- assert(0); // TODO
+ fprintf(out, ":%s", type->name);
+ break;
case Q__VOID:
break; // no-op
}
}
static void
+emit_type(const struct qbe_def *def, FILE *out)
+{
+ assert(def->kind == Q_TYPE);
+ fprintf(out, "type :%s =", def->name);
+ if (def->type.align != (size_t)-1) {
+ fprintf(out, " align %zu", def->type.align);
+ }
+ fprintf(out, " {");
+
+ const struct qbe_field *field = &def->type.fields;
+ while (field) {
+ if (field->type) {
+ fprintf(out, " ");
+ emit_qtype(field->type, out);
+ }
+ if (field->count) {
+ fprintf(out, " %zu", field->count);
+ }
+ if (field->next) {
+ fprintf(out, ",");
+ }
+ field = field->next;
+ }
+
+ fprintf(out, " }\n\n");
+}
+
+static void
emit_const(struct qbe_value *val, FILE *out)
{
switch (val->type->stype) {
@@ -131,7 +160,7 @@ emit_stmt(struct qbe_statement *stmt, FILE *out)
static void
emit_func(struct qbe_def *def, FILE *out)
{
- assert(def->type == Q_FUNC);
+ assert(def->kind == Q_FUNC);
fprintf(out, "%sfunction ", def->exported ? "export " : "");
emit_qtype(def->func.returns, out);
fprintf(out, " $%s(", def->name);
@@ -162,9 +191,10 @@ emit_func(struct qbe_def *def, FILE *out)
static void
emit_def(struct qbe_def *def, FILE *out)
{
- switch (def->type) {
+ switch (def->kind) {
case Q_TYPE:
- assert(0); // TODO
+ emit_type(def, out);
+ break;
case Q_FUNC:
emit_func(def, out);
break;
diff --git a/src/gen.c b/src/gen.c
@@ -674,7 +674,7 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
assert(func->flags == 0); // TODO
struct qbe_def *qdef = xcalloc(1, sizeof(struct qbe_def));
- qdef->type = Q_FUNC;
+ qdef->kind = Q_FUNC;
qdef->exported = decl->exported;
qdef->name = func->symbol ? strdup(func->symbol)
: ident_to_sym(&decl->ident);
@@ -775,6 +775,7 @@ gen(const struct unit *unit, struct qbe_program *out)
.out = out,
.ns = unit->ns,
};
+ ctx.out->next = &ctx.out->defs;
const struct declarations *decls = unit->declarations;
assert(decls); // At least one is required
trenter(TR_GEN, "gen");
diff --git a/src/qbe.c b/src/qbe.c
@@ -150,8 +150,8 @@ const char *qbe_instr[Q_LAST_INSTR] = {
void
qbe_append_def(struct qbe_program *prog, struct qbe_def *def)
{
- def->next = prog->defs;
- prog->defs = def;
+ *prog->next = def;
+ prog->next = &def->next;
}
struct qbe_value *
diff --git a/src/qtype.c b/src/qtype.c
@@ -1,8 +1,10 @@
#include <assert.h>
#include <stdbool.h>
+#include <stdio.h>
#include "gen.h"
#include "qbe.h"
#include "types.h"
+#include "util.h"
enum qbe_stype
qstype_for_type(const struct type *type)
@@ -91,6 +93,75 @@ qxtype_for_type(const struct type *type)
assert(0);
}
+static const struct qbe_type *
+lookup_aggregate(struct gen_context *ctx, const struct type *type)
+{
+ for (struct qbe_def *def = ctx->out->defs; def; def = def->next) {
+ if (def->kind == Q_TYPE && def->type.base == type) {
+ return &def->type;
+ }
+ }
+
+ switch (type->storage) {
+ // Special cases
+ case TYPE_STORAGE_ARRAY:
+ return &qbe_long;
+ default:
+ break;
+ }
+
+ int n = snprintf(NULL, 0, "type.%zd", ctx->id);
+ char *name = xcalloc(1, n + 1);
+ snprintf(name, n + 1, "type.%zd", ctx->id);
+ ++ctx->id;
+
+ struct qbe_def *def = xcalloc(1, sizeof(struct qbe_def));
+ def->kind = Q_TYPE,
+ def->name = name,
+ def->exported = false,
+ def->type.stype = Q__AGGREGATE;
+ def->type.base = type;
+ def->type.name = name;
+ def->type.align = SIZE_UNDEFINED;
+
+ switch (type->storage) {
+ case TYPE_STORAGE_ENUM:
+ case TYPE_STORAGE_SLICE:
+ case TYPE_STORAGE_STRING:
+ case TYPE_STORAGE_STRUCT:
+ case TYPE_STORAGE_TAGGED_UNION:
+ case TYPE_STORAGE_UNION:
+ assert(0); // TODO
+ case TYPE_STORAGE_ARRAY:
+ case TYPE_STORAGE_ALIAS:
+ case TYPE_STORAGE_CHAR:
+ case TYPE_STORAGE_I8:
+ case TYPE_STORAGE_U8:
+ case TYPE_STORAGE_I16:
+ case TYPE_STORAGE_U16:
+ case TYPE_STORAGE_BOOL:
+ case TYPE_STORAGE_I32:
+ case TYPE_STORAGE_U32:
+ case TYPE_STORAGE_RUNE:
+ case TYPE_STORAGE_INT:
+ case TYPE_STORAGE_UINT:
+ case TYPE_STORAGE_I64:
+ case TYPE_STORAGE_U64:
+ case TYPE_STORAGE_SIZE:
+ case TYPE_STORAGE_UINTPTR:
+ case TYPE_STORAGE_POINTER:
+ case TYPE_STORAGE_NULL:
+ case TYPE_STORAGE_F32:
+ case TYPE_STORAGE_F64:
+ case TYPE_STORAGE_VOID:
+ case TYPE_STORAGE_FUNCTION:
+ assert(0); // Invariant
+ }
+
+ qbe_append_def(ctx->out, def);
+ return &def->type;
+}
+
const struct qbe_type *
qtype_for_type(struct gen_context *ctx, const struct type *type, bool extended)
{
@@ -121,17 +192,17 @@ qtype_for_type(struct gen_context *ctx, const struct type *type, bool extended)
case TYPE_STORAGE_VOID:
return qtype_for_xtype(qstype_for_type(type));
case TYPE_STORAGE_ARRAY:
- return qtype_for_xtype(Q__AGGREGATE);
- case TYPE_STORAGE_ALIAS:
case TYPE_STORAGE_ENUM:
case TYPE_STORAGE_SLICE:
case TYPE_STORAGE_STRING:
case TYPE_STORAGE_STRUCT:
case TYPE_STORAGE_TAGGED_UNION:
case TYPE_STORAGE_UNION:
- assert(0); // TODO
+ return lookup_aggregate(ctx, type);
case TYPE_STORAGE_FUNCTION:
return qtype_for_xtype(Q__AGGREGATE);
+ case TYPE_STORAGE_ALIAS:
+ assert(0); // TODO
}
assert(0); // Unreachable
}