harec

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

commit 036246e166e19d370bd7cf22dbc07d8a1e1b1736
parent ec7703e4c151033430e508661189279927d4848b
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu,  1 Jul 2021 12:57:33 -0400

gen: implement loading values from temporaries

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Minclude/gen.h | 1+
Msrc/gen.c | 38++++++++++++++++++++++++++++++++++----
Msrc/qinstr.c | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 87 insertions(+), 4 deletions(-)

diff --git a/include/gen.h b/include/gen.h @@ -40,6 +40,7 @@ void gen(const struct unit *unit, // qinstr.c enum qbe_instr alloc_for_align(size_t align); enum qbe_instr store_for_type(const struct type *type); +enum qbe_instr load_for_type(const struct type *type); // qtype.c const struct qbe_type *qtype_lookup(struct gen_context *ctx, diff --git a/src/gen.c b/src/gen.c @@ -18,14 +18,19 @@ gen_name(struct gen_context *ctx, const char *fmt) return str; } +// Initializes a qval with a reference to a gen temporary. static void -qval_temp(struct gen_context *ctx, struct qbe_value *out, struct gen_temp *temp) +qval_temp(struct gen_context *ctx, + struct qbe_value *out, + const struct gen_temp *temp) { out->kind = QV_TEMPORARY; out->type = qtype_lookup(ctx, temp->type); out->name = temp->name; } +// Allocates a temporary of the given type on the stack in this function's +// preamble. static struct gen_temp * alloc_temp(struct gen_context *ctx, const struct type *type, const char *fmt) { @@ -46,6 +51,33 @@ alloc_temp(struct gen_context *ctx, const struct type *type, const char *fmt) return temp; } +// Loads a gen temporary into a qbe temporary. For types representable in qbe's +// type system, this loads the actual value into a qbe temporary. Otherwise, +// this behaves equivalently to qval_temp, but sets the temporary type to the +// platform's pointer type (e.g. =l). +static void +load_temp(struct gen_context *ctx, + struct qbe_value *out, + const struct gen_temp *temp) +{ + const struct qbe_type *qtype = qtype_lookup(ctx, temp->type); + assert(qtype->stype != Q__VOID); + + out->kind = QV_TEMPORARY; + if (qtype->stype == Q__AGGREGATE) { + out->name = temp->name; + out->type = ctx->arch.ptr; + } else { + out->name = gen_name(ctx, "load.%d"); + out->type = qtype; + + struct qbe_value addr; + qval_temp(ctx, &addr, temp); + enum qbe_instr instr = load_for_type(temp->type); + pushi(ctx->current, out, instr, &addr, NULL); + } +} + static void gen_expr_constant(struct gen_context *ctx, const struct expression *expr, @@ -190,10 +222,8 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl) gen_expr(ctx, func->body, ctx->rval); if (type_dealias(fntype->func.result)->storage != STORAGE_VOID) { - // XXX: This is incorrect; we need to load the value from the - // stack struct qbe_value rval = {0}; - qval_temp(ctx, &rval, ctx->rval); + load_temp(ctx, &rval, ctx->rval); pushi(ctx->current, NULL, Q_RET, &rval, NULL); } else { pushi(ctx->current, NULL, Q_RET, NULL); diff --git a/src/qinstr.c b/src/qinstr.c @@ -66,3 +66,55 @@ store_for_type(const struct type *type) } abort(); // Unreachable } + +enum qbe_instr +load_for_type(const struct type *type) +{ + switch (type->storage) { + case STORAGE_I8: + return Q_LOADSB; + case STORAGE_CHAR: + case STORAGE_U8: + return Q_LOADUB; + case STORAGE_I16: + return Q_LOADSH; + case STORAGE_U16: + return Q_LOADUH; + case STORAGE_U32: + case STORAGE_UINT: + case STORAGE_RUNE: + case STORAGE_BOOL: + return Q_LOADUW; + case STORAGE_I32: + case STORAGE_INT: + return Q_LOADSW; + case STORAGE_I64: + case STORAGE_U64: + return Q_LOADL; + case STORAGE_F32: + return Q_LOADS; + case STORAGE_F64: + return Q_LOADD; + case STORAGE_ENUM: + case STORAGE_POINTER: + case STORAGE_SIZE: + case STORAGE_UINTPTR: + assert(0); // TODO + case STORAGE_ALIAS: + return store_for_type(type->alias.type); + case STORAGE_ARRAY: + case STORAGE_FCONST: + case STORAGE_FUNCTION: + case STORAGE_ICONST: + case STORAGE_NULL: + case STORAGE_SLICE: + case STORAGE_STRING: + case STORAGE_STRUCT: + case STORAGE_TAGGED: + case STORAGE_TUPLE: + case STORAGE_UNION: + case STORAGE_VOID: + abort(); // Invariant + } + abort(); // Unreachable +}