aboutsummaryrefslogtreecommitdiff
path: root/src/prc1/cgen/qbe/qbe.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/prc1/cgen/qbe/qbe.c')
-rw-r--r--src/prc1/cgen/qbe/qbe.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/prc1/cgen/qbe/qbe.c b/src/prc1/cgen/qbe/qbe.c
new file mode 100644
index 0000000..c27bad6
--- /dev/null
+++ b/src/prc1/cgen/qbe/qbe.c
@@ -0,0 +1,187 @@
+#include "cgen.h"
+#include "cgen/prv.h"
+#include "fn.h"
+#include "lex.h"
+#include "lit.h"
+#include "parse.h"
+#include "qbe.h"
+#include "storage.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *cgen_sz(const size_t sz)
+{
+ switch (sz)
+ {
+ case 1:
+ return "b";
+ case 2:
+ return "h";
+ case 4:
+ return "w";
+ case 8:
+ return "l";
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+const char *cgen_tmp2(struct cgen *c)
+{
+ struct fn_cgen *fnc = c->fnc;
+
+ for (size_t i = 0; i < sizeof fnc->tmp - 1; i++)
+ {
+ char *s = &fnc->tmp[i];
+
+ if (!*s)
+ *s = 'a';
+ else if (*s >= 'z')
+ *s = 'A';
+ else if (*s >= 'Z')
+ continue;
+ else
+ (*s)++;
+
+ return s;
+ }
+
+ fprintf(stderr, "%s: ran out of temporaries\n", __func__);
+ return NULL;
+}
+
+const char *cgen_tmp(const size_t sz)
+{
+ switch (sz)
+ {
+ case 1:
+ return "vb";
+ case 2:
+ return "vh";
+ case 4:
+ return "vw";
+ case 8:
+ return "vl";
+ default:
+ break;
+ }
+
+ return "v";
+}
+
+const char *cgen_type(const struct type *t)
+{
+ switch (t->sz)
+ {
+ case 1:
+ return t->sign ? "b" : "ub";
+ case 2:
+ return t->sign ? "h" : "uh";
+ case 4:
+ return t->sign ? "w" : "uw";
+ case 8:
+ return t->sign ? "l" : "ul";
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+const char *cgen_abity(const struct type *t)
+{
+ switch (t->sz)
+ {
+ case 1:
+ return t->sign ? "b" : "ub";
+ case 2:
+ return t->sign ? "h" : "uh";
+ case 4:
+ return "w";
+ case 8:
+ return "l";
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+const char *cgen_load(const struct type *t)
+{
+ switch (t->sz)
+ {
+ case 1:
+ return t->sign ? "sb" : "ub";
+ case 2:
+ return t->sign ? "sh" : "uh";
+ case 4:
+ return t->sign ? "sw" : "uw";
+ case 8:
+ return "l";
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+void cgen_printvar(const struct fn *fn, const struct stentry *e)
+{
+ const char *name = e->tk->s;
+
+ if (cgen_global(fn, e))
+ printf("$%s", name);
+ else
+ printf("%%%s_", name);
+}
+
+static void pushfmt(const char *type, const char *fmt)
+{
+ printf("data $____fmt%s = { b \"%s\" , b 0 }\n", type, fmt);
+}
+
+int cgen_qbe(const struct ast *ast, struct cgen *c)
+{
+ static const struct cgen_drv drv =
+ {
+ .print = qbe_print,
+ .call = qbe_call,
+ .free = qbe_free,
+ .set = qbe_set,
+ .gl = qbe_gl,
+ .ws = qbe_ws,
+ .fn = qbe_fn
+ };
+
+ c->drv = &drv;
+ /* generate literals to use with printf(3) */
+ pushfmt("b", "%hhd");
+ pushfmt("h", "%hd");
+ pushfmt("w", "%d");
+ pushfmt("l", "%ld");
+ pushfmt("ub", "%hhu");
+ pushfmt("uh", "%hu");
+ pushfmt("uw", "%u");
+ pushfmt("ul", "%lu");
+ pushfmt("bx", "%#hhx");
+ pushfmt("hx", "%#hx");
+ pushfmt("wx", "%#x");
+ pushfmt("lx", "%#lx");
+
+ for (const struct lit *l = ast->lits; l; l = l->next)
+ if (lit_cgen(l))
+ return-1;
+
+ for (size_t i = 0; i < ast->nfns; i++)
+ if (fn_cgen((c->fn = &ast->fns[i]), c))
+ return -1;
+
+ return 0;
+}