harec

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

commit d6104b30f8dd959bde6187ba08ad7a362b9b495b
parent 726eade9e9697bf0e5393ec9323a47d80099521c
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon, 26 Jul 2021 17:40:09 +0200

gen: implement constants

Diffstat:
Minclude/gen.h | 25++++++++++++++++---------
Msrc/gen.c | 112++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/genutil.c | 22++++++++++++++++++++++
3 files changed, 144 insertions(+), 15 deletions(-)

diff --git a/include/gen.h b/include/gen.h @@ -13,15 +13,22 @@ enum fixed_aborts { ABORT_STATIC_EXCEEDED = 3, }; -// A gen temporary is a reference to a qbe temporary by name, and the -// corresponding Hare type. If indirect is true, the qbe temporary is a pointer -// to the actual storage; otherwise the type will be representable as a qbe -// primitive. -struct gen_temp { - char *name; +enum gen_value_kind { + GV_CONST, + GV_GLOBAL, + GV_TEMP, +}; + +struct gen_value { + enum gen_value_kind kind; const struct type *type; - bool indirect; - bool is_global; + union { + char *name; + uint32_t wval; + uint64_t lval; + float sval; + double dval; + }; }; struct gen_arch { @@ -40,7 +47,6 @@ struct gen_context { struct qbe_func *current; const struct type *functype; const char *end; - struct gen_temp *rval; }; struct unit; @@ -51,6 +57,7 @@ void gen(const struct unit *unit, // genutil.c char *gen_name(struct gen_context *ctx, const char *fmt); +struct qbe_value mkqval(struct gen_context *ctx, struct gen_value *value); // qinstr.c enum qbe_instr alloc_for_align(size_t align); diff --git a/src/gen.c b/src/gen.c @@ -8,6 +8,99 @@ #include "types.h" #include "util.h" +static struct gen_value +gen_expr_const(struct gen_context *ctx, const struct expression *expr) +{ + struct gen_value val = { + .kind = GV_CONST, + .type = expr->result, + }; + + // Special cases + switch (expr->result->storage) { + case STORAGE_BOOL: + val.wval = expr->constant.bval ? 1 : 0; + return val; + case STORAGE_VOID: + return val; + case STORAGE_NULL: + val.lval = 0; + return val; + case STORAGE_ARRAY: + assert(0); // TODO + case STORAGE_STRING: + assert(0); // TODO + default: + // Moving right along + break; + } + + const struct qbe_type *qtype = qtype_lookup(ctx, expr->result, false); + switch (qtype->stype) { + case Q_BYTE: + case Q_HALF: + case Q_WORD: + val.wval = (uint32_t)expr->constant.uval; + return val; + case Q_LONG: + val.lval = expr->constant.uval; + return val; + case Q_SINGLE: + val.sval = (float)expr->constant.fval; + return val; + case Q_DOUBLE: + val.dval = expr->constant.fval; + return val; + case Q__VOID: + return val; + case Q__AGGREGATE: + assert(0); // Invariant + } + + abort(); // Invariant +} + +static struct gen_value +gen_expr(struct gen_context *ctx, const struct expression *expr) +{ + switch (expr->type) { + case EXPR_ACCESS: + case EXPR_ALLOC: + case EXPR_APPEND: + case EXPR_ASSERT: + case EXPR_ASSIGN: + case EXPR_BINARITHM: + case EXPR_BINDING: + case EXPR_BREAK: + case EXPR_CALL: + case EXPR_CAST: + assert(0); // TODO + case EXPR_CONSTANT: + return gen_expr_const(ctx, expr); + case EXPR_CONTINUE: + case EXPR_DEFER: + case EXPR_DELETE: + case EXPR_FOR: + case EXPR_FREE: + case EXPR_IF: + case EXPR_INSERT: + case EXPR_LIST: + case EXPR_MATCH: + case EXPR_MEASURE: + assert(0); // TODO + case EXPR_PROPAGATE: + assert(0); // Lowered in check (for now?) + case EXPR_RETURN: + case EXPR_SLICE: + case EXPR_STRUCT: + case EXPR_SWITCH: + case EXPR_TUPLE: + case EXPR_UNARITHM: + assert(0); // TODO + } + abort(); // Unreachable +} + static void gen_function_decl(struct gen_context *ctx, const struct declaration *decl) { @@ -32,18 +125,25 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl) ctx->end = genl(&end_label, &ctx->id, "end.%d"); push(&qdef->func.prelude, &start_label); - assert(type_dealias(fntype->func.result)->storage == STORAGE_VOID); - // TODO: non-void return type - qdef->func.returns = &qbe_void; + if (type_dealias(fntype->func.result)->storage != STORAGE_VOID) { + qdef->func.returns = qtype_lookup( + ctx, fntype->func.result, false); + } else { + qdef->func.returns = &qbe_void; + } assert(!decl->func.scope->objects); // TODO: Parameters pushl(&qdef->func, &ctx->id, "body.%d"); - // TODO: Generate body + struct gen_value ret = gen_expr(ctx, decl->func.body); push(&qdef->func.body, &end_label); - // TODO: non-void return value - pushi(ctx->current, NULL, Q_RET, NULL); + if (type_dealias(fntype->func.result)->storage != STORAGE_VOID) { + struct qbe_value qret = mkqval(ctx, &ret); + pushi(ctx->current, NULL, Q_RET, &qret, NULL); + } else { + pushi(ctx->current, NULL, Q_RET, NULL); + } qbe_append_def(ctx->out, qdef); ctx->current = NULL; diff --git a/src/genutil.c b/src/genutil.c @@ -13,3 +13,25 @@ gen_name(struct gen_context *ctx, const char *fmt) ++ctx->id; return str; } + +struct qbe_value +mkqval(struct gen_context *ctx, struct gen_value *value) +{ + struct qbe_value qval = {0}; + switch (value->kind) { + case GV_CONST: + qval.kind = QV_CONST; + qval.lval = value->lval; // XXX: Kind of hacky + break; + case GV_GLOBAL: + qval.kind = QV_GLOBAL; + qval.name = value->name; + break; + case GV_TEMP: + qval.kind = QV_TEMPORARY; + qval.name = value->name; + break; + } + qval.type = qtype_lookup(ctx, value->type, true); + return qval; +}