scc

Simple C99 Compiler
Log | Files | Refs | README | LICENSE

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:
cc2/Makefile | 5+++--
cc2/arch/amd64-sysv/optm.c | 9+++++++++
cc2/arch/i386-sysv/optm.c | 9+++++++++
cc2/arch/qbe/arch.h | 1+
cc2/arch/qbe/cgen.c | 118+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
cc2/arch/qbe/code.c | 17+++++++++++++++--
cc2/arch/qbe/optm.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cc2/arch/z80/optm.c | 9+++++++++
cc2/cc2.h | 8+++++---
cc2/code.c | 14+++++++++++---
cc2/node.c | 18++++++++----------
cc2/optm.c | 45---------------------------------------------
cc2/parser.c | 4++--
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