commit 40faec131c8e46d9a621e6bc98220538c4ac177b
parent 5befc342b962af9abb3829b13a7c720552b63deb
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 1 Jul 2021 10:28:25 -0400
gen: basic implementation of constants
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
M | include/gen.h | | | 22 | ++++++++++++++++------ |
M | src/gen.c | | | 105 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
M | src/qinstr.c | | | 52 | ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/qtype.c | | | 12 | +++++++++++- |
4 files changed, 174 insertions(+), 17 deletions(-)
diff --git a/include/gen.h b/include/gen.h
@@ -12,23 +12,33 @@ enum fixed_aborts {
ABORT_STATIC_EXCEEDED = 3,
};
-struct unit;
+struct gen_temp {
+ char *name;
+ const struct type *type;
+};
-void gen(const struct unit *unit, struct qbe_program *out);
+struct gen_arch {
+ const struct qbe_type *ptr;
+};
struct gen_context {
struct qbe_program *out;
struct identifier *ns;
struct qbe_func *current;
+ struct gen_temp *rval;
+ struct gen_arch arch;
uint64_t id;
};
-struct gen_temp {
- char *name;
- const struct type *type;
-};
+struct unit;
+void gen(const struct unit *unit, struct qbe_program *out);
// qinstr.c
enum qbe_instr alloc_for_align(size_t align);
+enum qbe_instr store_for_type(const struct type *type);
+
+// qtype.c
+const struct qbe_type *qtype_lookup(struct gen_context *ctx,
+ const struct type *type);
#endif
diff --git a/src/gen.c b/src/gen.c
@@ -1,4 +1,5 @@
#include <assert.h>
+#include <stdlib.h>
#include <string.h>
#include "check.h"
#include "expr.h"
@@ -17,6 +18,14 @@ gen_name(struct gen_context *ctx, const char *fmt)
return str;
}
+static void
+qval_temp(struct gen_context *ctx, struct qbe_value *out, struct gen_temp *temp)
+{
+ out->kind = QV_TEMPORARY;
+ out->type = qtype_lookup(ctx, temp->type);
+ out->name = temp->name;
+}
+
static struct gen_temp *
alloc_temp(struct gen_context *ctx, const struct type *type, const char *fmt)
{
@@ -26,22 +35,86 @@ alloc_temp(struct gen_context *ctx, const struct type *type, const char *fmt)
temp->type = type;
temp->name = gen_name(ctx, fmt);
- // TODO: Look up qbe type
- assert(type_dealias(type)->storage == STORAGE_INT);
struct qbe_value out = {
.kind = QV_TEMPORARY,
- .type = &qbe_word,
+ .type = ctx->arch.ptr,
.name = temp->name,
};
struct qbe_value size;
constl(&size, type->size);
pushprei(ctx->current, &out, alloc_for_align(type->align), &size, NULL);
-
return temp;
}
static void
-gen_expr(struct gen_context *ctx, const struct expression *expr)
+gen_expr_constant(struct gen_context *ctx,
+ const struct expression *expr,
+ struct gen_temp *out)
+{
+ if (out == NULL) {
+ pushc(ctx->current, "Useless constant expression dropped");
+ return;
+ }
+ const struct expression_constant *constexpr = &expr->constant;
+ assert(constexpr->object == NULL); // TODO
+
+ struct qbe_value qout, qval = {0};
+ qval_temp(ctx, &qout, out);
+
+ switch (type_dealias(expr->result)->storage) {
+ case STORAGE_CHAR:
+ case STORAGE_I8:
+ case STORAGE_U8:
+ constw(&qval, constexpr->uval);
+ break;
+ case STORAGE_I16:
+ case STORAGE_U16:
+ constw(&qval, constexpr->uval);
+ break;
+ case STORAGE_I32:
+ case STORAGE_U32:
+ case STORAGE_INT:
+ case STORAGE_UINT:
+ case STORAGE_RUNE:
+ case STORAGE_BOOL:
+ constw(&qval, constexpr->uval);
+ break;
+ case STORAGE_I64:
+ case STORAGE_U64:
+ case STORAGE_SIZE:
+ case STORAGE_UINTPTR:
+ constl(&qval, constexpr->uval);
+ break;
+ case STORAGE_POINTER:
+ case STORAGE_F32:
+ case STORAGE_F64:
+ case STORAGE_ENUM:
+ assert(0); // TODO
+ case STORAGE_ARRAY:
+ case STORAGE_NULL:
+ case STORAGE_SLICE:
+ case STORAGE_STRING:
+ case STORAGE_STRUCT:
+ case STORAGE_TAGGED:
+ case STORAGE_TUPLE:
+ case STORAGE_UNION:
+ assert(0); // TODO
+ case STORAGE_ICONST:
+ case STORAGE_FCONST:
+ case STORAGE_VOID:
+ case STORAGE_ALIAS:
+ case STORAGE_FUNCTION:
+ abort(); // Invariant
+ }
+
+ enum qbe_instr instr = store_for_type(expr->result);
+ pushi(ctx->current, NULL, instr, &qval, &qout, NULL);
+}
+
+static void
+gen_expr(struct gen_context *ctx,
+ const struct expression *expr,
+ struct gen_temp *out)
{
switch (expr->type) {
case EXPR_ACCESS:
@@ -55,7 +128,10 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
case EXPR_CONTINUE:
case EXPR_CALL:
case EXPR_CAST:
+ assert(0); // TODO
case EXPR_CONSTANT:
+ gen_expr_constant(ctx, expr, out);
+ break;
case EXPR_DEFER:
case EXPR_DELETE:
case EXPR_FOR:
@@ -101,10 +177,8 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
push(&qdef->func.prelude, &start_label);
if (type_dealias(fntype->func.result)->storage != STORAGE_VOID) {
- alloc_temp(ctx, fntype->func.result, "rval.%d");
- // TODO: Look up qbe type
- assert(type_dealias(fntype->func.result)->storage == STORAGE_INT);
- qdef->func.returns = &qbe_word;
+ ctx->rval = alloc_temp(ctx, fntype->func.result, "rval.%d");
+ qdef->func.returns = qtype_lookup(ctx, fntype->func.result);
} else {
qdef->func.returns = &qbe_void;
}
@@ -113,7 +187,15 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
assert(!func->scope->objects);
pushl(&qdef->func, &ctx->id, "body.%d");
- gen_expr(ctx, func->body);
+ gen_expr(ctx, func->body, ctx->rval);
+
+ if (type_dealias(fntype->func.result)->storage != STORAGE_VOID) {
+ struct qbe_value rval = {0};
+ qval_temp(ctx, &rval, ctx->rval);
+ pushi(ctx->current, NULL, Q_RET, &rval, NULL);
+ } else {
+ pushi(ctx->current, NULL, Q_RET, NULL);
+ }
qbe_append_def(ctx->out, qdef);
ctx->current = NULL;
@@ -140,6 +222,9 @@ gen(const struct unit *unit, struct qbe_program *out)
struct gen_context ctx = {
.out = out,
.ns = unit->ns,
+ .arch = {
+ .ptr = &qbe_long,
+ },
};
ctx.out->next = &ctx.out->defs;
const struct declarations *decls = unit->declarations;
diff --git a/src/qinstr.c b/src/qinstr.c
@@ -1,4 +1,7 @@
+#include <assert.h>
+#include <stdlib.h>
#include "qbe.h"
+#include "types.h"
enum qbe_instr
alloc_for_align(size_t align)
@@ -14,3 +17,52 @@ alloc_for_align(size_t align)
return Q_ALLOC16;
}
}
+
+enum qbe_instr
+store_for_type(const struct type *type)
+{
+ switch (type->storage) {
+ case STORAGE_CHAR:
+ case STORAGE_I8:
+ case STORAGE_U8:
+ return Q_STOREB;
+ case STORAGE_I16:
+ case STORAGE_U16:
+ return Q_STOREH;
+ case STORAGE_I32:
+ case STORAGE_U32:
+ case STORAGE_INT:
+ case STORAGE_UINT:
+ case STORAGE_RUNE:
+ case STORAGE_BOOL:
+ return Q_STOREW;
+ case STORAGE_I64:
+ case STORAGE_U64:
+ return Q_STOREL;
+ case STORAGE_F32:
+ return Q_STORES;
+ case STORAGE_F64:
+ return Q_STORED;
+ 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
+}
diff --git a/src/qtype.c b/src/qtype.c
@@ -1,2 +1,12 @@
-void placeholder_qtype() {
+#include <assert.h>
+#include "gen.h"
+#include "qbe.h"
+#include "types.h"
+
+const struct qbe_type *qtype_lookup(
+ struct gen_context *ctx,
+ const struct type *type) {
+ // TODO
+ assert(type->storage == STORAGE_INT);
+ return &qbe_word;
}