commit 4c1ed4e19f1113c2162387719b4ca88ed92e60af
parent a662ba437aec0bcbd206ebd4637474a203dbe358
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Mon, 9 May 2016 16:56:27 +0200
Merge branch 'master' into quinq
Diffstat:
13 files changed, 210 insertions(+), 114 deletions(-)
diff --git a/cc2/Makefile b/cc2/Makefile
@@ -2,8 +2,9 @@
include ../config.mk
-OBJS = main.o parser.o optm.o peep.o symbol.o node.o code.o\
- arch/$(ARCH)/code.o arch/$(ARCH)/cgen.o arch/$(ARCH)/types.o
+OBJS = main.o parser.o peep.o symbol.o node.o code.o\
+ arch/$(ARCH)/code.o arch/$(ARCH)/cgen.o \
+ arch/$(ARCH)/types.o arch/$(ARCH)/optm.o
all: cc2
diff --git a/cc2/arch/amd64-sysv/optm.c b/cc2/arch/amd64-sysv/optm.c
@@ -0,0 +1,9 @@
+
+#include "arch.h"
+#include "../../cc2.h"
+
+Node *
+optm(Node *np)
+{
+ return np;
+}
diff --git a/cc2/arch/i386-sysv/optm.c b/cc2/arch/i386-sysv/optm.c
@@ -0,0 +1,9 @@
+
+#include "arch.h"
+#include "../../cc2.h"
+
+Node *
+optm(Node *np)
+{
+ return np;
+}
diff --git a/cc2/arch/qbe/arch.h b/cc2/arch/qbe/arch.h
@@ -131,5 +131,6 @@ enum asmop {
ASTRUNCD,
ASJMP,
+ ASBRANCH,
ASRET,
};
diff --git a/cc2/arch/qbe/cgen.c b/cc2/arch/qbe/cgen.c
@@ -5,6 +5,12 @@
#include "arch.h"
#include "../../cc2.h"
+enum lflags {
+ FORCE = 1 << 0,
+ LOADL = 1 << 1,
+ LOADR = 1 << 2
+};
+
enum sflags {
ISTMP = 1,
ISCONS = 2
@@ -104,47 +110,58 @@ tmpnode(Node *np)
return np;
}
+/*
+ * load() load the address passed in a child of np in a temporary
+ * if it is not already in a temporay. It can be forced to load
+ * using the FORCE flag
+ */
static Node *
-load(Node *np)
+load(Node *np, int flags)
{
int op;
- Node *new = tmpnode(newnode(ONOP));
- Type *tp = &np->type;
+ Type *tp;
+ Node *child;
- new->left = np;
- new->type = *tp;
+ child = (flags & LOADL) ? np->left : np->right;
+ tp = &child->type;
- switch (tp->size) {
- case 1:
- op = ASLDB;
- break;
- case 2:
- op = ASLDH;
- break;
- case 4:
- op = (tp->flags & INTF) ? ASLDW : ASLDS;
- break;
- case 8:
- op = (tp->flags & INTF) ? ASLDL : ASLDD;
- break;
- default:
- abort();
+ if ((flags & FORCE) || !(child->flags & (ISTMP|ISCONS))) {
+ Node *new = tmpnode(newnode(OTMP));
+ new->type = *tp;
+ new->left = child;
+
+ switch (tp->size) {
+ case 1:
+ op = ASLDB;
+ break;
+ case 2:
+ op = ASLDH;
+ break;
+ case 4:
+ op = (tp->flags & INTF) ? ASLDW : ASLDS;
+ break;
+ case 8:
+ op = (tp->flags & INTF) ? ASLDL : ASLDD;
+ break;
+ default:
+ abort();
+ }
+ code(op, new, child, NULL);
+ child = new;
}
- code(op, new, np, NULL);
- return new;
+ return (flags & LOADL) ? (np->left = child) : (np->right = child);
}
static Node *
-cast(Node *nd, Node *ns)
+cast(Node *nd)
{
Type *ts, *td;
- Node *tmp;
+ Node *tmp, *ns;
int op, disint, sisint;
extern Type uint32type, int32type;
- if ((ns->flags & (ISTMP|ISCONS)) == 0)
- ns = nd->left = load(ns);
+ ns = load(nd, LOADL);
td = &nd->type;
ts = &ns->type;
disint = (td->flags & INTF) != 0;
@@ -193,7 +210,7 @@ cast(Node *nd, Node *ns)
tmp = tmpnode(newnode(ONOP));
tmp->type = (ts->flags&SIGNF) ? int32type : uint32type;
tmp->left = ns;
- nd->left = ns = cast(tmp, ns);
+ nd->left = ns = cast(tmp);
case 4:
op = (td->size == 8) ? ASSWTOD : ASSWTOS;
break;
@@ -215,7 +232,7 @@ cast(Node *nd, Node *ns)
Node *
cgen(Node *np)
{
- Node *l, *r;
+ Node *l, *r, *ifyes, *ifno, *next;
Symbol *sym;
Type *tp;
int op, off;
@@ -224,13 +241,7 @@ cgen(Node *np)
if (!np)
return NULL;
- if (np->label) {
- setlabel(np->label);
- if (np->next == NULL) {
- addstmt(newnode(ORET));
- prevstmt();
- }
- }
+ setlabel(np->label);
l = cgen(np->left);
r = cgen(np->right);
tp = &np->type;
@@ -279,25 +290,23 @@ cgen(Node *np)
abort();
}
op = tbl[np->op] + off;
- if ((l->flags & (ISTMP|ISCONS)) == 0)
- l = np->left = load(l);
- if ((r->flags & (ISTMP|ISCONS)) == 0)
- r = np->right = load(r);
- code(op, tmpnode(np), l, r);
+ code(op, tmpnode(np), load(np, LOADL), load(np, LOADR));
return np;
case ONOP:
case OBLOOP:
case OELOOP:
return NULL;
case OCAST:
- return cast(np, l);
+ return cast(np);
case OADDR:
np->flags |= ISTMP;
np->op = OTMP;
np->u.sym = l->u.sym;
return np;
case OPTR:
- np->left = load(load(l));
+ load(np, LOADL);
+ /* FIXME: The type of the loaded value is not np->type */
+ load(np, LOADL|FORCE);
return tmpnode(np);
case OCPL:
case OPAR:
@@ -333,14 +342,29 @@ cgen(Node *np)
case OOR:
abort();
case OBRANCH:
- abort();
+ next = np->next;
+ l = load(np, LOADL);
+ if (next->label) {
+ sym = getsym(TMPSYM);
+ sym->kind = SLABEL;
+ next->label = sym;
+ }
+ ifyes = label(np->u.sym);
+ ifno = label(next->label);
+ op = ASBRANCH;
+ np = np->left;
+ goto emit_jump;
case OJMP:
- code(ASJMP, np, NULL, NULL);
+ ifyes = label(np->u.sym);
+ op = ASJMP;
+ np = ifno = NULL;
+ emit_jump:
+ code(op, np, ifyes, ifno);
+ deltree(ifyes);
+ deltree(ifno);
return NULL;
case ORET:
- if (l && (l->flags & (ISTMP|ISCONS)) == 0)
- l = np->left = load(l);
- code(ASRET, l, NULL, NULL);
+ code(ASRET, load(np, LOADL), NULL, NULL);
return NULL;
case OCASE:
case ODEFAULT:
diff --git a/cc2/arch/qbe/code.c b/cc2/arch/qbe/code.c
@@ -9,7 +9,8 @@
#define ADDR_LEN (IDENTSIZ+64)
-static void binary(void), unary(void), store(void), jmp(void), ret(void);
+static void binary(void), unary(void), store(void), jmp(void), ret(void),
+ branch(void);
static struct opdata {
void (*fun)(void);
@@ -122,6 +123,7 @@ static struct opdata {
[ASEXTS] = {.fun = unary, .txt = "exts", .letter = 'd'},
[ASSLTOS]= {.fun = unary, .txt = "truncd", .letter = 's'},
+ [ASBRANCH] = {.fun = branch},
[ASJMP] = {.fun = jmp},
[ASRET] = {.fun = ret},
};
@@ -403,7 +405,18 @@ ret(void)
static void
jmp(void)
{
- printf("\t\tjmp\t%s\n", addr2txt(&pc->to));
+ printf("\t\tjmp\t%s\n", addr2txt(&pc->from1));
+}
+
+static void
+branch(void)
+{
+ char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
+
+ strcpy(to, addr2txt(&pc->to));
+ strcpy(from1, addr2txt(&pc->from1));
+ strcpy(from2, addr2txt(&pc->from2));
+ printf("\t\tjnz\t%s,%s,%s\n", to, from1, from2);
}
void
diff --git a/cc2/arch/qbe/optm.c b/cc2/arch/qbe/optm.c
@@ -0,0 +1,67 @@
+
+#include <stddef.h>
+
+#include "arch.h"
+#include "../../cc2.h"
+
+Node *
+optm(Node *np)
+{
+ int op = np->op;
+ Node *p, *dst, *next = np->next;
+ Symbol *sym, *osym;
+
+ if (!next) {
+ /*
+ * In QBE we need at the end of a basic block
+ * a jump, so we have to ensure that the last
+ * statement of the function is a ret, a jmp
+ * or a branch. In the same way, QBE does
+ * not accept labels at the end of a function
+ * (ONOP is used for labels) so we have to add
+ * a ret there, and in the case of branches
+ * we need a label for the next statement
+ */
+ if (op == ONOP || op == OBRANCH || (op != ORET && op != OJMP))
+ addstmt(newnode(ORET), KEEPCUR);
+ next = np->next;
+ }
+
+ switch (op) {
+ case ONOP:
+ if (next->op == ONOP) {
+ sym = np->u.sym;
+ osym = next->u.sym;
+ osym->id = sym->id;
+ osym->numid = sym->id;
+ osym->u.stmt = sym->u.stmt;
+ return NULL;
+ }
+ break;
+ case OBRANCH:
+ if (!next->label) {
+ sym = getsym(TMPSYM);
+ sym->kind = SLABEL;
+ next->label = sym;
+ }
+ case OJMP:
+ for (;;) {
+ dst = np->u.sym->u.stmt;
+ if (dst->op != OJMP)
+ break;
+ np->u.sym = dst->u.sym;
+ }
+ for (p = np->next; p; p = p->next) {
+ if (p == dst)
+ return NULL;
+ if (p->op == ONOP ||
+ p->op == OBLOOP ||
+ p->op == OELOOP) {
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+ return np;
+}
diff --git a/cc2/arch/z80/optm.c b/cc2/arch/z80/optm.c
@@ -0,0 +1,9 @@
+
+#include "arch.h"
+#include "../../cc2.h"
+
+Node *
+optm(Node *np)
+{
+ return np;
+}
diff --git a/cc2/cc2.h b/cc2/cc2.h
@@ -202,16 +202,18 @@ extern void writeout(void), endinit(void), newfun(void);
extern void code(int op, Node *to, Node *from1, Node *from2);
extern void defvar(Symbol *), defpar(Symbol *), defglobal(Symbol *);
extern void setlabel(Symbol *sym);
+extern Node *label(Symbol *sym);
/* node.c */
+#define SETCUR 1
+#define KEEPCUR 0
extern void apply(Node *(*fun)(Node *));
extern void cleannodes(void);
extern void delnode(Node *np);
extern void deltree(Node *np);
extern Node *newnode(int op);
-extern Node *addstmt(Node *np);
-extern Node *prevstmt(void), *nextstmt(void);
-
+extern Node *addstmt(Node *np, int flags);
+extern Node *nextstmt(void);
/* symbol.c */
#define TMPSYM 0
diff --git a/cc2/code.c b/cc2/code.c
@@ -38,7 +38,6 @@ addr(Node *np, Addr *addr)
addr->kind = OCONST;
addr->u.i = np->u.i;
break;
- case OJMP:
case OLABEL:
addr->kind = SLABEL;
goto symbol;
@@ -50,11 +49,20 @@ addr(Node *np, Addr *addr)
symbol:
addr->u.sym = np->u.sym;
break;
- default:
- abort();
}
}
+Node *
+label(Symbol *sym)
+{
+ Node *np;
+
+ np = newnode(OLABEL);
+ np->u.sym = sym;
+
+ return np;
+}
+
void
setlabel(Symbol *sym)
{
diff --git a/cc2/node.c b/cc2/node.c
@@ -49,15 +49,19 @@ newnode(int op)
}
Node *
-addstmt(Node *np)
+addstmt(Node *np, int flag)
{
+ if (curstmt)
+ np->next = curstmt->next;
+ np->prev = curstmt;
+
if (!curfun->u.stmt)
curfun->u.stmt = np;
else
curstmt->next = np;
- np->next = NULL;
- np->prev = curstmt;
- curstmt = np;
+
+ if (flag == SETCUR)
+ curstmt = np;
return np;
}
@@ -86,12 +90,6 @@ nextstmt(void)
return curstmt = curstmt->next;
}
-Node *
-prevstmt(void)
-{
- return curstmt = curstmt->prev;
-}
-
void
delnode(Node *np)
{
diff --git a/cc2/optm.c b/cc2/optm.c
@@ -1,45 +0,0 @@
-
-#include <stddef.h>
-
-#include "arch.h"
-#include "cc2.h"
-
-Node *
-optm(Node *np)
-{
- Node *p, *dst, *next = np->next;
- Symbol *sym, *osym;
-
- switch (np->op) {
- case ONOP:
- if (next && next->op == ONOP) {
- sym = np->u.sym;
- osym = next->u.sym;
- osym->id = sym->id;
- osym->numid = sym->id;
- osym->u.stmt = sym->u.stmt;
- return NULL;
- }
- break;
- case OJMP:
- case OBRANCH:
- for (;;) {
- dst = np->u.sym->u.stmt;
- if (dst->op != OJMP)
- break;
- np->u.sym = dst->u.sym;
- }
- for (p = np->next; p; p = p->next) {
- if (p == dst)
- return NULL;
- if (p->op == ONOP ||
- p->op == OBLOOP ||
- p->op == OELOOP) {
- continue;
- }
- break;
- }
- break;
- }
- return np;
-}
diff --git a/cc2/parser.c b/cc2/parser.c
@@ -556,7 +556,7 @@ labeldcl(void)
sym->kind = SLABEL;
sym->u.stmt = np;
np->label = sym;
- addstmt(np);
+ addstmt(np, SETCUR);
}
static void
@@ -570,7 +570,7 @@ stmt(void)
deltree(np);
return;
}
- addstmt(np);
+ addstmt(np, SETCUR);
}
static void