ref: 36a3a5fa99dc4887ca46c7807436ad44da19422f
parent: 04a014003d9dc62fc5fe80ad51958a39bb9d2f2a
author: Ori Bernstein <[email protected]>
date: Fri May 4 17:40:37 EDT 2012
Work towards generating assembly. New reduction and start of instruction selection code.
--- a/8/Makefile
+++ b/8/Makefile
@@ -1,7 +1,8 @@
BIN=8m
-OBJ=main.o \
+OBJ=isel.o \
+ main.o \
simp.o \
- gen.o \
+ reduce.o \
CFLAGS+=-I../parse
LDFLAGS+=-L../parse -lparse
--- /dev/null
+++ b/8/asm.h
@@ -1,0 +1,56 @@
+#define MaxArg 4
+
+typedef enum {
+#define Insn(val, fmt, attr) val,
+#include "insns.def"
+#undef Insn
+} AsmOp;
+
+typedef enum {
+#define Reg(r, name) r,
+#include "regs.def"
+#undef Reg
+} Reg;
+
+
+typedef enum {
+ Loclbl,
+ Locreg,
+ Locmem,
+ Locmeml, /* label offset */
+ Loclit,
+} LocType;
+
+typedef enum {
+ ModeB,
+ ModeS,
+ ModeL,
+ ModeQ,
+} Mode;
+
+typedef struct Insn Insn;
+typedef struct Loc Loc;
+
+struct Loc {
+ LocType type;
+ Mode mode;
+ union {
+ char *lbl;
+ Reg reg;
+ long lit;
+ /* disp(base + index) */
+ struct {
+ /* only one of lbldisp and constdisp may be used */
+ char *lbldisp;
+ long constdisp;
+ Reg base;
+ Reg idx;
+ } mem;
+ };
+};
+
+struct Insn {
+ AsmOp op;
+ Loc args[MaxArg];
+ int nloc;
+};
--- a/8/gen.c
+++ /dev/null
@@ -1,2 +1,0 @@
-
-
--- a/8/gen.h
+++ b/8/gen.h
@@ -57,3 +57,4 @@
Fn *mkfn(char *name);
Bb *mkbb(void);
void edge(Bb *from, Bb *to);
+Node **reduce(Node *n, int *ret_nn);
--- /dev/null
+++ b/8/insns.def
@@ -1,0 +1,26 @@
+/* Table of instructions. Each instruction
+ is defined by the following macro:
+ Insn(enumval, fmt, attr)
+ The format string 'fmt' has the following expansions:
+ %r - A register
+ %m - A memory location.
+ %l - A location (either register or memory)
+ %x - Any value.
+ %[0-9]*t - Mode of an operand. The optional number
+ preceeding it is the operand desired for
+ the mode.
+ %v - a value (ie, immediate integer or label)
+
+ */
+
+/* Note, the mov instruction is specified in an overly general manner. */
+Insn(Imov, "mov%m %x,%x", 0)
+Insn(Imovz, "movz%0m%1m %x,%x", 0)
+Insn(Imovs, "movs%0m%1m %x,%x", 0)
+
+/* arithmetic instructions. */
+Insn(Iadd, "add%m %r,%x", 0)
+Insn(Iret, "ret", 0)
+
+/* not really an insn... */
+Insn(Ilbl, "%s:", 0)
--- /dev/null
+++ b/8/isel.c
@@ -1,0 +1,190 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "parse.h"
+#include "gen.h"
+#include "asm.h"
+
+typedef struct Isel Isel;
+struct Isel {
+ Insn **il;
+ size_t ni;
+};
+
+char *regnames[] = {
+#define Reg(r, name) name,
+#include "regs.def"
+#undef Reg
+};
+
+char *insnfmts[] = {
+#define Insn(val, fmt, attr) fmt,
+#include "insns.def"
+#undef Insn
+};
+
+void selexpr(Node *n)
+{
+ switch (exprop(n)) {
+ case Obad:
+ case Oadd:
+ case Osub:
+ case Omul:
+ case Odiv:
+ case Omod:
+ case Oneg:
+ case Obor:
+ case Oband:
+ case Obxor:
+ case Obsl:
+ case Obsr:
+ case Obnot:
+ case Opreinc:
+ case Opostinc:
+ case Opredec:
+ case Opostdec:
+ case Oaddr:
+ case Oderef:
+ case Olor:
+ case Oland:
+ case Olnot:
+ case Oeq:
+ case One:
+ case Ogt:
+ case Oge:
+ case Olt:
+ case Ole:
+ case Oasn:
+ case Oaddeq:
+ case Osubeq:
+ case Omuleq:
+ case Odiveq:
+ case Omodeq:
+ case Oboreq:
+ case Obandeq:
+ case Obxoreq:
+ case Obsleq:
+ case Obsreq:
+ case Oidx:
+ case Oslice:
+ case Omemb:
+ case Osize:
+ case Ocall:
+ case Ocast:
+ case Oret:
+ case Ojmp:
+ case Ocjmp:
+ case Ovar:
+ case Olit:
+ case Olbl:
+ break;
+ }
+}
+
+void ilbl(Isel *s, char *name)
+{
+}
+
+void locprint(FILE *fd, Loc *l)
+{
+
+ switch (l->type) {
+ case Loclbl:
+ fprintf(fd, "%s", l->lbl);
+ break;
+ case Locreg:
+ fprintf(fd, "%s", regnames[l->reg]);
+ break;
+ case Locmem:
+ case Locmeml:
+ if (l->type == Locmem) {
+ if (l->mem.constdisp)
+ fprintf(fd, "%ld", l->mem.constdisp);
+ } else {
+ if (l->mem.lbldisp)
+ fprintf(fd, "%s", l->mem.lbldisp);
+ }
+ if (l->mem.base)
+ fprintf(fd, "(%s", regnames[l->mem.base]);
+ if (l->mem.idx)
+ fprintf(fd, ",%s", regnames[l->mem.idx]);
+ if (l->mem.base)
+ fprintf(fd, ")");
+ break;
+ break;
+ case Loclit:
+ break;
+ }
+}
+
+void modeprint(FILE *fd, Loc *l)
+{
+ char mode[] = {'b', 's', 'l', 'q'};
+ fputc(mode[l->mode], fd);
+}
+
+void iprintf(FILE *fd, Insn *insn)
+{
+ char *p;
+ int i;
+ int modeidx;
+
+ p = insnfmts[insn->op];
+ for (; *p; p++) {
+ if (*p != '%') {
+ fputc(*p, fd);
+ continue;
+ }
+
+ /* %-formating */
+ p++;
+ switch (*p) {
+ case '\0':
+ goto done;
+ case 'r':
+ case 'm':
+ case 'l':
+ case 'x':
+ case 'v':
+ locprint(fd, &insn->args[i]);
+ i++;
+ break;
+ case 't':
+ default:
+ if (isdigit(*p))
+ modeidx = strtol(p, &p, 10);
+ else
+ modeidx = 0;
+ modeprint(fd, &insn->args[modeidx]);
+ break;
+ }
+ }
+done:
+ return;
+}
+
+void isel(Node *n)
+{
+ struct Isel is = {0,};
+ switch (n->type) {
+ case Nlbl:
+ ilbl(&is, n->lbl.name);
+ break;
+ case Nexpr:
+ selexpr(n);
+ break;
+ case Ndecl:
+ break;
+ default:
+ die("Bad node type in isel()");
+ break;
+ }
+}
--- /dev/null
+++ b/8/reduce.c
@@ -1,0 +1,249 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "parse.h"
+#include "gen.h"
+
+
+/* takes a list of nodes, and reduces it (and it's subnodes) to a list
+ * following these constraints:
+ * - All nodes are expression nodes
+ * - Nodes with side effects are root nodes
+ * - All nodes operate on machine-primitive types and tuples
+ */
+typedef struct Simp Simp;
+struct Simp {
+ Node **blk;
+ size_t nblk;
+ Node *endlbl;
+ Node *retval;
+};
+
+Node *simp(Simp *s, Node *n);
+
+void append(Simp *s, Node *n)
+{
+ lappend(&s->blk, &s->nblk, n);
+}
+
+int isimpure(Node *n)
+{
+ return 0;
+}
+
+Node *genlbl(void)
+{
+ char buf[128];
+ static int nextlbl;
+
+ snprintf(buf, 128, ".L%d", nextlbl++);
+ return mklbl(-1, buf);
+}
+
+Node *temp(Node *e)
+{
+ char buf[128];
+ static int nexttmp;
+ Node *n;
+ Node *t;
+ Sym *s;
+
+ assert(e->type == Nexpr);
+ snprintf(buf, 128, ".t%d", nexttmp++);
+ n = mkname(-1, buf);
+ s = mksym(-1, n, e->expr.type);
+ t = mkdecl(-1, s);
+ return mkexpr(-1, Ovar, t, NULL);
+}
+
+void cjmp(Simp *s, Node *cond, Node *iftrue, Node *iffalse)
+{
+ Node *jmp;
+
+ jmp = mkexpr(-1, Ocjmp, cond, iftrue, iffalse, NULL);
+ append(s, jmp);
+}
+
+void jmp(Simp *s, Node *lbl)
+{
+ append(s, mkexpr(-1, Ojmp, lbl, NULL));
+}
+
+Node *store(Node *t, Node *n)
+{
+ return mkexpr(-1, Oasn, t, n, NULL);
+}
+
+Node *storetmp(Node *n)
+{
+ return store(temp(n), n);
+}
+
+/* if foo; bar; else baz;;
+ * => cjmp (foo) :bar :baz */
+void simpif(Simp *s, Node *n)
+{
+ Node *l1, *l2;
+ Node *c;
+
+ l1 = genlbl();
+ l2 = genlbl();
+ c = simp(s, n->ifstmt.cond);
+ cjmp(s, c, l1, l2);
+ simp(s, l1);
+ simp(s, n->ifstmt.iftrue);
+ simp(s, l2);
+ simp(s, n->ifstmt.iffalse);
+}
+
+/* init; while cond; body;;
+ * => init
+ * jmp :cond
+ * :body
+ * ...body...
+ * :cond
+ * ...cond...
+ * cjmp (cond) :body :end
+ * :end
+ */
+void simploop(Simp *s, Node *n)
+{
+ Node *lbody;
+ Node *lend;
+ Node *lcond;
+ Node *c;
+
+ lbody = genlbl();
+ lcond = genlbl();
+ lend = genlbl();
+
+ simp(s, n->loopstmt.init);
+ jmp(s, lcond);
+ simp(s, lbody);
+ simp(s, n->loopstmt.body);
+ simp(s, n->loopstmt.step);
+ simp(s, lcond);
+ c = simp(s, n->loopstmt.cond);
+ cjmp(s, c, lbody, lend);
+ simp(s, lend);
+}
+
+void simpblk(Simp *s, Node *n)
+{
+ int i;
+ Node *e;
+
+ for (i = 0; i < n->block.nstmts; i++) {
+ e = simp(s, n->block.stmts[i]);
+ append(s, e);
+ }
+}
+
+Node *simpexpr(Simp *s, Node *n)
+{
+ Node *r, *t;
+ int i;
+
+ switch (exprop(n)) {
+ case Ovar:
+ break;
+ case Oret:
+ if (n->expr.args[0]) {
+ t = storetmp(simp(s, n->expr.args[0]));
+ append(s, t);
+ }
+ jmp(s, s->endlbl);
+ break;
+ default:
+ if (isimpure(n)) {
+ r = simp(s, n);
+ t = storetmp(r);
+ append(s, t);
+ return t;
+ } else {
+ for (i = 0; i < n->expr.nargs; i++)
+ n->expr.args[i] = simp(s, n->expr.args[i]);
+ }
+ }
+ return n;
+}
+
+Node *simp(Simp *s, Node *n)
+{
+ Node *r;
+
+ r = NULL;
+ switch (n->type) {
+ case Nblock:
+ simpblk(s, n);
+ break;
+ case Nifstmt:
+ simpif(s, n);
+ break;
+ case Nloopstmt:
+ simploop(s, n);
+ break;
+ case Nexpr:
+ r = simpexpr(s, n);
+ break;
+ case Nlit:
+ r = n;
+ break;
+ case Ndecl:
+ //declare(s, n);
+ break;
+ case Nlbl:
+ append(s, n);
+ break;
+ default:
+ die("Bad node passsed to simp()");
+ break;
+ }
+ return r;
+}
+
+Node **reduce(Node *n, int *ret_nn)
+{
+ Simp s = {0,};
+
+ s.nblk = 0;
+ s.endlbl = genlbl();
+ s.retval = NULL;
+ switch (n->type) {
+ /* these should never be inside functions */
+ case Nnone:
+ case Nfile:
+ die("Bad node type in func");
+ break;
+ case Nfunc:
+ die("FIXME: generate thunks");
+ break;
+ /* no code generated */
+ case Nuse:
+ break;
+ /* complex nodes */
+ case Nblock:
+ simp(&s, n);
+ break;
+ case Nifstmt:
+ case Nloopstmt:
+ case Nexpr:
+ case Nlit:
+ case Nname:
+ case Ndecl:
+ case Nlbl:
+ break;
+ }
+ append(&s, s.endlbl);
+
+ *ret_nn = s.nblk;
+ return s.blk;
+}
--- /dev/null
+++ b/8/regs.def
@@ -1,0 +1,25 @@
+Reg(Rnone, "%NOREG")
+/* byte regs */
+Reg(Ral, "%al")
+Reg(Rcl, "%cl")
+Reg(Rdl, "%dl")
+Reg(Rbl, "%bl")
+
+/* short regs */
+Reg(Rax, "%ax")
+Reg(Rbx, "%bx")
+Reg(Rcx, "%cx")
+Reg(Rdx, "%dx")
+Reg(Rsi, "%si")
+Reg(Rdi, "%di")
+
+/* long regs */
+Reg(Reax, "%eax")
+Reg(Recx, "%ecx")
+Reg(Redx, "%edx")
+Reg(Rebx, "%ebx")
+Reg(Resi, "%esi")
+Reg(Redi, "%edi")
+Reg(Resp, "%esp")
+Reg(Rebp, "%ebp")
+
--- a/8/simp.c
+++ b/8/simp.c
@@ -18,7 +18,7 @@
static void lowerglobl(Comp *c, char *name, Node *init);
static void lowerif(Comp *c, Fn *fn, Node *cond);
static void lowerloop(Comp *c, Fn *fn, Node *loop);
-static void lowerblock(Comp *c, Fn *fn, Node *blk);
+void lowerblock(Comp *c, Fn *fn, Node *blk);
static void lowerfn(Comp *c, char *name, Node *n);
Fn *mkfn(char *name)
@@ -166,7 +166,7 @@
fn->cur = mkbb();
}
-static void lowerblock(Comp *c, Fn *fn, Node *blk)
+void lowerblock(Comp *c, Fn *fn, Node *blk)
{
Node **n;
size_t nn;
@@ -202,14 +202,12 @@
static void lowerfn(Comp *c, char *name, Node *n)
{
Fn *fn;
+ Node **nl;
+ int nn;
int i;
- Bb *fix;
- Node *last;
/* unwrap to the function body */
- assert(n->type == Nexpr && exprop(n) == Olit);
n = n->expr.args[0];
- assert(n->type == Nlit && n->lit.littype == Lfunc);
n = n->lit.fnval;
assert(n->type == Nfunc);
@@ -217,21 +215,11 @@
fn = mkfn(name);
fn = zalloc(sizeof(Fn));
fn->name = strdup(name);
- lowerblock(c, fn, n->func.body);
- lappend(&c->func, &c->nfunc, fn);
- for (i = 0; i < fn->nfixup; i++) {
- fix = fn->fixup[i];
- last = fix->n[fix->nn - 1];
- switch (exprop(last)) {
- case Ocjmp:
- break;
- case Ojmp:
- break;
- default:
- die("Invalid last node in BB");
- break;
- }
+ nl = reduce(n->func.body, &nn);
+
+ for (i = 0; i < nn; i++) {
+ dump(nl[i], stdout);
}
}