commit 732522cb68bf3fd61ad9e3003cb57d293c8b2762
parent 8da76fb718bc17bc9b3993935393bce14a8586df
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 20 Dec 2020 10:37:55 -0500
gen: flesh out initial qbe type system
Diffstat:
5 files changed, 180 insertions(+), 19 deletions(-)
diff --git a/include/gen.h b/include/gen.h
@@ -3,7 +3,8 @@
#include <stdio.h>
struct unit;
+struct qbe_program;
-void gen(const struct unit *unit, FILE *out);
+void gen(const struct unit *unit, struct qbe_program *out);
#endif
diff --git a/include/qbe.h b/include/qbe.h
@@ -1,6 +1,7 @@
#ifndef HAREC_QBE_H
#define HAREC_QBE_H
#include <stdarg.h>
+#include <stdbool.h>
#include <stdint.h>
enum qbe_stype {
@@ -26,7 +27,10 @@ extern const struct qbe_type
qbe_word,
qbe_long,
qbe_single,
- qbe_double;
+ qbe_double,
+ qbe_void;
+
+const struct qbe_type *qtype_for_xtype(enum qbe_stype type);
enum qbe_value_kind {
QV_CONST,
@@ -155,8 +159,8 @@ struct qbe_statement {
};
struct qbe_func {
- char *name;
- // TODO: Parameters, return type
+ const struct qbe_type *returns;
+ // TODO: Parameters
size_t blen, bsiz;
struct qbe_statement *body;
};
@@ -168,7 +172,9 @@ enum qbe_deftype {
};
struct qbe_def {
+ char *name;
enum qbe_deftype type;
+ bool exported;
union {
struct qbe_func func;
};
diff --git a/src/gen.c b/src/gen.c
@@ -1,4 +1,5 @@
#include <assert.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -12,7 +13,7 @@
#include "types.h"
struct gen_context {
- FILE *out;
+ struct qbe_program *out;
struct identifier *ns;
uint64_t id;
};
@@ -35,24 +36,148 @@ ident_to_sym(const struct identifier *ident)
return strdup(ident->name);
}
+static enum qbe_stype
+qstype_for_type(const struct type *type)
+{
+ switch (type->storage) {
+ case TYPE_STORAGE_CHAR:
+ case TYPE_STORAGE_I8:
+ case TYPE_STORAGE_U8:
+ // Implemented as Q_WORD
+ case TYPE_STORAGE_I16:
+ case TYPE_STORAGE_U16:
+ // Implemented as Q_WORD
+ case TYPE_STORAGE_BOOL:
+ case TYPE_STORAGE_I32:
+ case TYPE_STORAGE_U32:
+ case TYPE_STORAGE_RUNE:
+ case TYPE_STORAGE_INT: // XXX: Architecture dependent
+ case TYPE_STORAGE_UINT: // XXX: Architecture dependent
+ return Q_WORD;
+ case TYPE_STORAGE_I64:
+ case TYPE_STORAGE_U64:
+ case TYPE_STORAGE_SIZE:
+ case TYPE_STORAGE_UINTPTR: // XXX: Architecture dependent
+ case TYPE_STORAGE_POINTER: // XXX: Architecture dependent
+ return Q_LONG;
+ case TYPE_STORAGE_F32:
+ return Q_SINGLE;
+ case TYPE_STORAGE_F64:
+ return Q_DOUBLE;
+ case TYPE_STORAGE_VOID:
+ return Q__VOID;
+ case TYPE_STORAGE_ALIAS:
+ assert(0); // TODO
+ case TYPE_STORAGE_ARRAY:
+ case TYPE_STORAGE_SLICE:
+ case TYPE_STORAGE_STRING:
+ case TYPE_STORAGE_STRUCT:
+ case TYPE_STORAGE_TAGGED_UNION:
+ case TYPE_STORAGE_UNION:
+ case TYPE_STORAGE_FUNCTION:
+ assert(0); // Invariant
+ }
+ assert(0);
+}
+
+static enum qbe_stype
+qxtype_for_type(const struct type *type)
+{
+ switch (type->storage) {
+ case TYPE_STORAGE_CHAR:
+ case TYPE_STORAGE_I8:
+ case TYPE_STORAGE_U8:
+ return Q_BYTE;
+ case TYPE_STORAGE_I16:
+ case TYPE_STORAGE_U16:
+ return Q_HALF;
+ case TYPE_STORAGE_BOOL:
+ case TYPE_STORAGE_I32:
+ case TYPE_STORAGE_U32:
+ case TYPE_STORAGE_RUNE:
+ case TYPE_STORAGE_INT: // XXX: Architecture dependent
+ case TYPE_STORAGE_UINT: // XXX: Architecture dependent
+ case TYPE_STORAGE_I64:
+ case TYPE_STORAGE_U64:
+ case TYPE_STORAGE_SIZE:
+ case TYPE_STORAGE_UINTPTR: // XXX: Architecture dependent
+ case TYPE_STORAGE_POINTER: // XXX: Architecture dependent
+ case TYPE_STORAGE_F32:
+ case TYPE_STORAGE_F64:
+ case TYPE_STORAGE_VOID:
+ case TYPE_STORAGE_ALIAS:
+ case TYPE_STORAGE_ARRAY:
+ case TYPE_STORAGE_SLICE:
+ case TYPE_STORAGE_STRING:
+ case TYPE_STORAGE_STRUCT:
+ case TYPE_STORAGE_TAGGED_UNION:
+ case TYPE_STORAGE_UNION:
+ case TYPE_STORAGE_FUNCTION:
+ return qstype_for_type(type);
+ }
+ assert(0);
+}
+
+static const struct qbe_type *
+qtype_for_type(struct gen_context *ctx, const struct type *type, bool extended)
+{
+ switch (type->storage) {
+ case TYPE_STORAGE_CHAR:
+ case TYPE_STORAGE_I8:
+ case TYPE_STORAGE_U8:
+ case TYPE_STORAGE_I16:
+ case TYPE_STORAGE_U16:
+ if (extended) {
+ return qtype_for_xtype(qxtype_for_type(type));
+ }
+ // Fallthrough
+ 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_F32:
+ case TYPE_STORAGE_F64:
+ case TYPE_STORAGE_VOID:
+ return qtype_for_xtype(qstype_for_type(type));
+ case TYPE_STORAGE_ALIAS:
+ case TYPE_STORAGE_ARRAY:
+ 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_FUNCTION:
+ assert(0); // Invariant
+ }
+ assert(0); // Unreachable
+}
+
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;
- // TODO: All of these cases:
- assert(func->flags == 0);
- assert(func->symbol == NULL);
- assert(fntype->func.result == &builtin_type_void);
- assert(fntype->func.params == NULL);
+ assert(func->flags == 0); // TODO
+
+ struct qbe_def *qdef = calloc(1, sizeof(struct qbe_def));
+ qdef->type = Q_FUNC;
+ qdef->exported = decl->exported;
+ qdef->name = func->symbol ? strdup(func->symbol)
+ : ident_to_sym(&decl->ident);
+ qdef->func.returns = qtype_for_type(ctx, fntype->func.result, true);
+
+ assert(fntype->func.params == NULL); // TODO
- char *sym = ident_to_sym(&decl->ident);
- fprintf(ctx->out, "%sfunction $%s() {\n",
- decl->exported ? "export " : "", sym);
- fprintf(ctx->out, "\t# TODO: Emit function body\n");
- fprintf(ctx->out, "}\n\n");
- free(sym);
+ // TODO: Gen function body
}
static void
@@ -70,7 +195,7 @@ gen_decl(struct gen_context *ctx, const struct declaration *decl)
}
void
-gen(const struct unit *unit, FILE *out)
+gen(const struct unit *unit, struct qbe_program *out)
{
struct gen_context ctx = {
.out = out,
diff --git a/src/main.c b/src/main.c
@@ -3,9 +3,10 @@
#include <string.h>
#include "ast.h"
#include "check.h"
+#include "gen.h"
#include "lex.h"
#include "parse.h"
-#include "gen.h"
+#include "qbe.h"
enum stage {
STAGE_LEX,
@@ -60,6 +61,7 @@ main(int argc, char *argv[])
return 0;
}
- gen(&unit, stdout);
+ struct qbe_program prog = {0};
+ gen(&unit, &prog);
return 0;
}
diff --git a/src/qbe.c b/src/qbe.c
@@ -22,8 +22,35 @@ qbe_single = {
},
qbe_double = {
.stype = Q_DOUBLE,
+},
+qbe_void = {
+ .stype = Q__VOID,
};
+const struct qbe_type *
+qtype_for_xtype(enum qbe_stype type)
+{
+ switch (type) {
+ case Q_BYTE:
+ return &qbe_byte;
+ case Q_HALF:
+ return &qbe_half;
+ case Q_WORD:
+ return &qbe_word;
+ case Q_LONG:
+ return &qbe_long;
+ case Q_SINGLE:
+ return &qbe_single;
+ case Q_DOUBLE:
+ return &qbe_double;
+ case Q__VOID:
+ return &qbe_void;
+ case Q__AGGREGATE:
+ assert(0); // Invariant
+ }
+ assert(0); // Unreachable
+}
+
const char *qbe_instr[Q_LAST_INSTR] = {
[Q_ADD] = "add",
[Q_ALLOC16] = "alloc16",