harec

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

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:
Minclude/qbe.h | 21++++++++++++++++++---
Msrc/emit.c | 38++++++++++++++++++++++++++++++++++----
Msrc/gen.c | 3++-
Msrc/qbe.c | 4++--
Msrc/qtype.c | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
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 }