commit 5befc342b962af9abb3829b13a7c720552b63deb
parent 56eac2ff6b4b6750b6eeef5ae7862497758c4f50
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 1 Jul 2021 10:04:57 -0400
gen: basic temporary allocation
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
5 files changed, 106 insertions(+), 28 deletions(-)
diff --git a/include/gen.h b/include/gen.h
@@ -1,7 +1,9 @@
#ifndef HAREC_GEN_H
#define HAREC_GEN_H
+#include <stddef.h>
#include "identifier.h"
#include "qbe.h"
+#include "types.h"
enum fixed_aborts {
ABORT_OOB = 0,
@@ -17,7 +19,16 @@ void gen(const struct unit *unit, struct qbe_program *out);
struct gen_context {
struct qbe_program *out;
struct identifier *ns;
+ struct qbe_func *current;
uint64_t id;
};
+struct gen_temp {
+ char *name;
+ const struct type *type;
+};
+
+// qinstr.c
+enum qbe_instr alloc_for_align(size_t align);
+
#endif
diff --git a/include/qbe.h b/include/qbe.h
@@ -2,6 +2,7 @@
#define HAREC_QBE_H
#include <stdarg.h>
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
enum qbe_stype {
@@ -54,27 +55,9 @@ enum qbe_value_kind {
QV_TEMPORARY,
};
-// Represents a value which can be an argument to a QBE instruction.
-//
-// If the value is a non-aggregate type, indirect determines if it is a pointer
-// to the value, or the value itself.
-//
-// let x = 10; // %x =l alloc4 4; storew 10, %x
-// // qbe_value{QV_TEMPORARY, =l, true, %x}
-// x; // %temp =w loadw %x
-// // qbe_value{QV_TEMPORARY, =w, false, %temp}
-//
-// Aggregate types cannot be directly stored in temporaries, so if direct is
-// set, the value is still a pointer to an aggregate type.
-//
-// let x = [1, 2, 3]; // %x =l alloc4 12; storew 1, %x; ...
-// // qbe_value{QV_TEMPORARY, :aggregate, true, %x }
-// let y = &x; // %y =l alloc8 8; storel %x, %y
-// // qbe_value{QV_TEMPORARY, =l, true, %y }
struct qbe_value {
enum qbe_value_kind kind;
const struct qbe_type *type;
- bool indirect;
union {
char *name;
uint32_t wval;
diff --git a/src/gen.c b/src/gen.c
@@ -4,12 +4,78 @@
#include "expr.h"
#include "gen.h"
#include "scope.h"
+#include "types.h"
#include "util.h"
+static char *
+gen_name(struct gen_context *ctx, const char *fmt)
+{
+ int n = snprintf(NULL, 0, fmt, ctx->id);
+ char *str = xcalloc(1, n + 1);
+ snprintf(str, n + 1, fmt, ctx->id);
+ ++ctx->id;
+ return str;
+}
+
+static struct gen_temp *
+alloc_temp(struct gen_context *ctx, const struct type *type, const char *fmt)
+{
+ assert(type->size != 0 && type->size != SIZE_UNDEFINED);
+
+ struct gen_temp *temp = xcalloc(1, sizeof(struct gen_temp));
+ 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,
+ .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)
{
- assert(0); // TODO
+ 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_CONTINUE:
+ case EXPR_CALL:
+ case EXPR_CAST:
+ case EXPR_CONSTANT:
+ 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 (XXX: for now...)
+ case EXPR_RETURN:
+ case EXPR_SLICE:
+ case EXPR_STRUCT:
+ case EXPR_SWITCH:
+ case EXPR_TUPLE:
+ case EXPR_UNARITHM:
+ assert(0); // TODO
+ }
}
static void
@@ -28,20 +94,29 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
qdef->exported = decl->exported;
qdef->name = decl->symbol ? strdup(decl->symbol)
: ident_to_sym(&decl->ident);
+ ctx->current = &qdef->func;
struct qbe_statement start_label = {0};
genl(&start_label, &ctx->id, "start.%d");
push(&qdef->func.prelude, &start_label);
- // TODO: Allocate parameters, return value
- assert(fntype->func.result->storage == STORAGE_VOID);
+ 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;
+ } else {
+ qdef->func.returns = &qbe_void;
+ }
+
+ // TODO: Allocate parameters
assert(!func->scope->objects);
- qdef->func.returns = &qbe_void;
pushl(&qdef->func, &ctx->id, "body.%d");
gen_expr(ctx, func->body);
qbe_append_def(ctx->out, qdef);
+ ctx->current = NULL;
}
static void
diff --git a/src/qbe.c b/src/qbe.c
@@ -315,7 +315,6 @@ constw(struct qbe_value *val, uint32_t w)
val->kind = QV_CONST;
val->type = &qbe_word;
val->wval = w;
- val->indirect = false;
}
void
@@ -324,7 +323,6 @@ constl(struct qbe_value *val, uint64_t l)
val->kind = QV_CONST;
val->type = &qbe_long;
val->lval = l;
- val->indirect = false;
}
void
@@ -333,7 +331,6 @@ consts(struct qbe_value *val, float s)
val->kind = QV_CONST;
val->type = &qbe_single;
val->sval = s;
- val->indirect = false;
}
void
@@ -342,7 +339,6 @@ constd(struct qbe_value *val, double d)
val->kind = QV_CONST;
val->type = &qbe_double;
val->dval = d;
- val->indirect = false;
}
void
@@ -350,5 +346,4 @@ const_void(struct qbe_value *val)
{
val->kind = QV_CONST;
val->type = &qbe_void;
- val->indirect = false;
}
diff --git a/src/qinstr.c b/src/qinstr.c
@@ -1,2 +1,16 @@
-void placeholder_qinstr() {
+#include "qbe.h"
+
+enum qbe_instr
+alloc_for_align(size_t align)
+{
+ switch (align) {
+ case 1:
+ case 2:
+ case 4:
+ return Q_ALLOC4;
+ case 8:
+ return Q_ALLOC8;
+ default:
+ return Q_ALLOC16;
+ }
}