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:
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
+}