commit 4e8cc2de3ce1764671fab1c29d64cf1bb686ab34
parent ce4f47284a6be1724af247120b6142f40affc749
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 20 Dec 2020 11:50:05 -0500
gen: implement some basic instruction handling
Diffstat:
7 files changed, 221 insertions(+), 10 deletions(-)
diff --git a/configure b/configure
@@ -12,6 +12,7 @@ harec() {
src/main.c \
src/parse.c \
src/qbe.c \
+ src/qinstr.c \
src/qtype.c \
src/trace.c \
src/type_store.c \
diff --git a/include/gen.h b/include/gen.h
@@ -12,14 +12,19 @@ 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 type;
+// qtype.c
enum qbe_stype qstype_for_type(const struct type *type);
enum qbe_stype qxtype_for_type(const struct type *type);
const struct qbe_type *qtype_for_type(struct gen_context *ctx,
const struct type *type, bool extended);
+// qinstr.c
+enum qbe_instr alignment_to_qbe_alloc(size_t align);
+
#endif
diff --git a/include/qbe.h b/include/qbe.h
@@ -5,6 +5,7 @@
#include <stdint.h>
enum qbe_stype {
+ Q__VOID = 0,
Q_BYTE = 'b',
Q_HALF = 'h',
Q_WORD = 'w',
@@ -12,7 +13,6 @@ enum qbe_stype {
Q_SINGLE = 's',
Q_DOUBLE = 'd',
Q__AGGREGATE,
- Q__VOID,
};
struct qbe_type {
@@ -44,7 +44,10 @@ struct qbe_value {
const struct qbe_type *type;
union {
char *name;
- // TODO: const storage
+ uint32_t wval;
+ uint64_t lval;
+ float sval;
+ double dval;
};
};
@@ -152,6 +155,7 @@ struct qbe_statement {
union {
struct {
enum qbe_instr instr;
+ struct qbe_value *out;
struct qbe_arguments *args;
};
char *label;
@@ -191,9 +195,11 @@ void qbe_append_def(struct qbe_program *prog, struct qbe_def *def);
// provide to the given instruction. The "l" family takes a printf-compatible
// set of values to match with fmt to produce a label (plus the ID postfix,
// which is added for you).
-void geni(struct qbe_statement *stmt, enum qbe_instr instr, ...);
+void geni(struct qbe_statement *stmt, enum qbe_instr instr, const struct qbe_value *out, ...);
void genl(struct qbe_statement *stmt, uint64_t *id, const char *fmt, ...);
-void pushi(struct qbe_func *func, enum qbe_instr instr, ...);
+void pushi(struct qbe_func *func, enum qbe_instr instr, const struct qbe_value *out, ...);
void pushl(struct qbe_func *func, uint64_t *id, const char *fmt, ...);
+void constl(struct qbe_value *val, uint64_t l);
+
#endif
diff --git a/src/emit.c b/src/emit.c
@@ -23,6 +23,73 @@ emit_qtype(const struct qbe_type *type, FILE *out)
}
static void
+emit_const(struct qbe_value *val, FILE *out)
+{
+ switch (val->type->stype) {
+ case Q_BYTE:
+ case Q_HALF:
+ case Q_WORD:
+ fprintf(out, "%u ", val->wval);
+ break;
+ case Q_LONG:
+ fprintf(out, "%lu ", val->lval);
+ break;
+ case Q_SINGLE:
+ fprintf(out, "%f ", val->sval);
+ break;
+ case Q_DOUBLE:
+ fprintf(out, "%f ", val->dval);
+ break;
+ case Q__VOID:
+ case Q__AGGREGATE:
+ assert(0); // Invariant
+ }
+}
+
+static void
+emit_value(struct qbe_value *val, FILE *out)
+{
+ switch (val->kind) {
+ case QV_CONST:
+ emit_const(val, out);
+ break;
+ case QV_GLOBAL:
+ assert(0); // TODO
+ case QV_LABEL:
+ assert(0); // TODO
+ case QV_TEMPORARY:
+ fprintf(out, "%%%s", val->name);
+ break;
+ }
+}
+
+static void
+emit_stmt(struct qbe_statement *stmt, FILE *out)
+{
+ switch (stmt->type) {
+ case Q_INSTR:
+ fprintf(out, "\t");
+ if (stmt->out != NULL) {
+ emit_value(stmt->out, out);
+ fprintf(out, " =");
+ assert(stmt->out->type->stype != Q__AGGREGATE); // TODO
+ emit_qtype(stmt->out->type, out);
+ }
+ fprintf(out, "%s", qbe_instr[stmt->instr]);
+ struct qbe_arguments *arg = stmt->args;
+ while (arg) {
+ fprintf(out, " ");
+ emit_value(&arg->value, out);
+ arg = arg->next;
+ }
+ fprintf(out, "\n");
+ break;
+ case Q_LABEL:
+ assert(0); // TODO
+ }
+}
+
+static void
emit_func(struct qbe_def *def, FILE *out)
{
assert(def->type == Q_FUNC);
@@ -30,7 +97,12 @@ emit_func(struct qbe_def *def, FILE *out)
fprintf(out, "%sfunction ", def->exported ? "export " : "");
emit_qtype(def->func.returns, out);
fprintf(out, "$%s() {\n", def->name); // TODO: Parameters
- // TODO: Body
+
+ for (size_t i = 0; i < def->func.blen; ++i) {
+ struct qbe_statement *stmt = &def->func.body[i];
+ emit_stmt(stmt, out);
+ }
+
fprintf(out, "}\n\n");
}
diff --git a/src/gen.c b/src/gen.c
@@ -31,6 +31,43 @@ ident_to_sym(const struct identifier *ident)
}
static void
+gen_temp(struct gen_context *ctx, struct qbe_value *val,
+ const struct qbe_type *type, char *fmt)
+{
+ val->kind = QV_TEMPORARY;
+ val->type = type;
+
+ int n = snprintf(NULL, 0, fmt, ctx->id);
+ char *str = calloc(1, n + 1);
+ snprintf(str, n + 1, fmt, ctx->id);
+ ++ctx->id;
+
+ val->name = str;
+}
+
+static void
+alloc_temp(struct gen_context *ctx, struct qbe_value *val,
+ const struct type *type, char *fmt)
+{
+ const struct qbe_type *qtype = qtype_for_type(ctx, type, false);
+ gen_temp(ctx, val, qtype, fmt);
+
+ struct qbe_value size;
+ constl(&size, type->size);
+ pushi(ctx->current, alignment_to_qbe_alloc(type->align),
+ val, &size, NULL);
+}
+
+static void
+gen_expression(struct gen_context *ctx,
+ struct qbe_func *body,
+ const struct expression *expr,
+ struct qbe_value *out)
+{
+ //assert(0); // TODO
+}
+
+static void
gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
{
assert(decl->type == DECL_FUNC);
@@ -44,12 +81,18 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
qdef->name = func->symbol ? strdup(func->symbol)
: ident_to_sym(&decl->ident);
qdef->func.returns = qtype_for_type(ctx, fntype->func.result, true);
+ ctx->current = &qdef->func;
assert(fntype->func.params == NULL); // TODO
- // TODO: Gen function body
+ // TODO: Update for void type
+ struct qbe_value rval;
+ alloc_temp(ctx, &rval, fntype->func.result, "return.%d");
+ gen_expression(ctx, &qdef->func, func->body, &rval);
+ pushi(&qdef->func, Q_RET, NULL, &rval, NULL);
qbe_append_def(ctx->out, qdef);
+ ctx->current = NULL;
}
static void
diff --git a/src/qbe.c b/src/qbe.c
@@ -1,6 +1,7 @@
#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <string.h>
#include "qbe.h"
// Simple type singletons
@@ -143,10 +144,46 @@ qbe_append_def(struct qbe_program *prog, struct qbe_def *def)
prog->defs = def;
}
+static struct qbe_value *
+qval_dup(const struct qbe_value *val)
+{
+ struct qbe_value *new = calloc(1, sizeof(struct qbe_value));
+ *new = *val;
+ if (val->kind != QV_CONST) {
+ new->name = strdup(val->name);
+ }
+ return new;
+}
+
+static void
+va_geni(struct qbe_statement *stmt, enum qbe_instr instr,
+ const struct qbe_value *out, va_list ap)
+{
+ stmt->type = Q_INSTR;
+ stmt->instr = instr;
+
+ if (out) {
+ stmt->out = qval_dup(out);
+ }
+
+ struct qbe_arguments **next = &stmt->args;
+ struct qbe_value *val;
+ while ((val = va_arg(ap, struct qbe_value *))) {
+ struct qbe_arguments *arg = calloc(1, sizeof(struct qbe_arguments));
+ arg->value = *val;
+ *next = arg;
+ next = &arg->next;
+ }
+}
+
void
-geni(struct qbe_statement *stmt, enum qbe_instr instr, ...)
+geni(struct qbe_statement *stmt, enum qbe_instr instr,
+ const struct qbe_value *out, ...)
{
- assert(0); // TODO
+ va_list ap;
+ va_start(ap, out);
+ va_geni(stmt, instr, out, ap);
+ va_end(ap);
}
void
@@ -155,10 +192,34 @@ genl(struct qbe_statement *stmt, uint64_t *id, const char *fmt, ...)
assert(0); // TODO
}
+static void
+push(struct qbe_func *func, struct qbe_statement *stmt)
+{
+ if (!func->body) {
+ func->bsiz = 256;
+ func->blen = 0;
+ func->body = calloc(1, sizeof(struct qbe_statement) * func->bsiz);
+ assert(func->body);
+ }
+ if (func->blen + 1 < func->bsiz) {
+ func->bsiz *= 2;
+ struct qbe_statement *new = realloc(func->body, func->bsiz);
+ func->body = new;
+ assert(func->body);
+ }
+ func->body[func->blen++] = *stmt;
+}
+
void
-pushi(struct qbe_func *func, enum qbe_instr instr, ...)
+pushi(struct qbe_func *func, enum qbe_instr instr,
+ const struct qbe_value *out, ...)
{
- assert(0); // TODO
+ struct qbe_statement stmt = {0};
+ va_list ap;
+ va_start(ap, out);
+ va_geni(&stmt, instr, out, ap);
+ va_end(ap);
+ push(func, &stmt);
}
void
@@ -166,3 +227,11 @@ pushl(struct qbe_func *func, uint64_t *id, const char *fmt, ...)
{
assert(0); // TODO
}
+
+void
+constl(struct qbe_value *val, uint64_t l)
+{
+ val->kind = QV_CONST;
+ val->type = &qbe_long;
+ val->lval = l;
+}
diff --git a/src/qinstr.c b/src/qinstr.c
@@ -0,0 +1,15 @@
+#include "gen.h"
+#include "qbe.h"
+
+enum qbe_instr
+alignment_to_qbe_alloc(size_t align)
+{
+ switch (align) {
+ case 4:
+ return Q_ALLOC4;
+ case 8:
+ return Q_ALLOC8;
+ default:
+ return Q_ALLOC16;
+ }
+}