harec

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

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:
Minclude/gen.h | 3++-
Minclude/qbe.h | 12+++++++++---
Msrc/gen.c | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/main.c | 6++++--
Msrc/qbe.c | 27+++++++++++++++++++++++++++
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",