commit a2713249b19b81223cac003d65a94bbd597fe19a
parent a60d3783c8fec5fc133cc1bddd8552e48c1399a1
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 15 Jan 2021 12:44:14 -0500
gen: generate qbe type for tagged unions
Diffstat:
3 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/include/qbe.h b/include/qbe.h
@@ -30,6 +30,7 @@ struct qbe_type {
// Aggregate types only:
char *name;
size_t align;
+ bool is_union;
struct qbe_field fields;
const struct type *base;
};
diff --git a/src/emit.c b/src/emit.c
@@ -40,6 +40,9 @@ emit_type(const struct qbe_def *def, FILE *out)
const struct qbe_field *field = &def->type.fields;
while (field) {
+ if (def->type.is_union) {
+ fprintf(out, " {");
+ }
if (field->type) {
fprintf(out, " ");
emit_qtype(field->type, true, out);
@@ -47,7 +50,9 @@ emit_type(const struct qbe_def *def, FILE *out)
if (field->count) {
fprintf(out, " %zu", field->count);
}
- if (field->next) {
+ if (def->type.is_union) {
+ fprintf(out, " }");
+ } else if (field->next) {
fprintf(out, ",");
}
field = field->next;
diff --git a/src/qtype.c b/src/qtype.c
@@ -94,6 +94,42 @@ qxtype_for_type(const struct type *type)
}
static const struct qbe_type *
+tagged_qtype(struct gen_context *ctx, const struct type *type)
+{
+ int n = snprintf(NULL, 0, "tags.%zd", ctx->id);
+ char *name = xcalloc(1, n + 1);
+ snprintf(name, n + 1, "tags.%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;
+ def->type.is_union = true;
+
+ struct qbe_field *field = &def->type.fields;
+ for (const struct type_tagged_union *tu = &type->tagged;
+ tu; tu = tu->next) {
+ if (tu->type->size == 0) {
+ continue;
+ }
+ field->type = qtype_for_type(ctx, tu->type, true);
+ field->count = 1;
+ if (tu->next) {
+ field->next = xcalloc(1, sizeof(struct qbe_field));
+ field = field->next;
+ }
+ }
+
+ qbe_append_def(ctx->out, def);
+ return &def->type;
+}
+
+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) {
@@ -116,9 +152,9 @@ lookup_aggregate(struct gen_context *ctx, const struct type *type)
++ctx->id;
struct qbe_def *def = xcalloc(1, sizeof(struct qbe_def));
- def->kind = Q_TYPE,
- def->name = name,
- def->exported = false,
+ def->kind = Q_TYPE;
+ def->name = name;
+ def->exported = false;
def->type.stype = Q__AGGREGATE;
def->type.base = type;
def->type.name = name;
@@ -148,8 +184,18 @@ lookup_aggregate(struct gen_context *ctx, const struct type *type)
field->type = &qbe_long; // XXX: ARCH
field->count = 3;
break;
- case TYPE_STORAGE_ENUM:
case TYPE_STORAGE_TAGGED_UNION:
+ def->type.align = type->align;
+ field->type = &qbe_long; // XXX: ARCH
+ field->count = 1;
+ if (type->size != builtin_type_size.size) {
+ field->next = xcalloc(1, sizeof(struct qbe_field));
+ field = field->next;
+ field->type = tagged_qtype(ctx, type);
+ field->count = 1;
+ }
+ break;
+ case TYPE_STORAGE_ENUM:
assert(0); // TODO
case TYPE_STORAGE_ARRAY:
case TYPE_STORAGE_ALIAS: