shithub: scc

Download patch

ref: 0a156f6de8961950b3e91a5b53b956ae9670452e
parent: fc104bb2dabf97b04570992b6c3a6082f0c1aec2
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Thu Jun 23 11:27:57 EDT 2016

[cc2-qbe] Begin the rewrite of cgen()

This function was known to be wrong, because we do not
control when we are generating code for a lhs or for a rhs.
This commits cleans the full cgen.c file, but it copies it
to cgen.c.old

--- a/cc2/arch/qbe/cgen.c
+++ b/cc2/arch/qbe/cgen.c
@@ -6,509 +6,24 @@
 #include "../../cc2.h"
 #include "../../../inc/sizes.h"
 
-enum lflags {
-	FORCE = 1 << 0,
-	LOADL = 1 << 1,
-	LOADR = 1 << 2
-};
-
-enum sflags {
-	ISTMP  = 1,
-	ISCONS = 2
-};
-
-static char opasmw[] = {
-	[OADD] = ASADDW,
-	[OSUB] = ASSUBW,
-	[OMUL] = ASMULW,
-	[OMOD] = ASMODW,
-	[ODIV] = ASDIVW,
-	[OSHL] = ASSHLW,
-	[OSHR] = ASSHRW,
-	[OLT] = ASLTW,
-	[OGT] = ASGTW,
-	[OLE] = ASLEW,
-	[OGE] = ASGEW,
-	[OEQ] = ASEQW,
-	[ONE] = ASNEW,
-	[OBAND] = ASBANDW,
-	[OBOR] = ASBORW,
-	[OBXOR] = ASBXORW,
-	[OCPL] = ASCPLW
-};
-
-static char opasml[] = {
-	[OADD] = ASADDL,
-	[OSUB] = ASSUBL,
-	[OMUL] = ASMULL,
-	[OMOD] = ASMODL,
-	[ODIV] = ASDIVL,
-	[OSHL] = ASSHLL,
-	[OSHR] = ASSHRL,
-	[OLT] = ASLTL,
-	[OGT] = ASGTL,
-	[OLE] = ASLEL,
-	[OGE] = ASGEL,
-	[OEQ] = ASEQL,
-	[ONE] = ASNEL,
-	[OBAND] = ASBANDL,
-	[OBOR] = ASBORL,
-	[OBXOR] = ASBXORL,
-	[OCPL] = ASCPLL
-};
-
-static char opasms[] = {
-	[OADD] = ASADDS,
-	[OSUB] = ASSUBS,
-	[OMUL] = ASMULS,
-	[OMOD] = ASMODS,
-	[ODIV] = ASDIVS,
-	[OSHL] = ASSHLS,
-	[OSHR] = ASSHRS,
-	[OLT] = ASLTS,
-	[OGT] = ASGTS,
-	[OLE] = ASLES,
-	[OGE] = ASGES,
-	[OEQ] = ASEQS,
-	[ONE] = ASNES,
-	[OBAND] = ASBANDS,
-	[OBOR] = ASBORS,
-	[OBXOR] = ASBXORS,
-	[OCPL] = ASCPLS
-};
-
-static char opasmd[] = {
-	[OADD] = ASADDD,
-	[OSUB] = ASSUBD,
-	[OMUL] = ASMULD,
-	[OMOD] = ASMODD,
-	[ODIV] = ASDIVD,
-	[OSHL] = ASSHLD,
-	[OSHR] = ASSHRD,
-	[OLT] = ASLTD,
-	[OGT] = ASGTD,
-	[OLE] = ASLED,
-	[OGE] = ASGED,
-	[OEQ] = ASEQD,
-	[ONE] = ASNED,
-	[OBAND] = ASBANDD,
-	[OBOR] = ASBORD,
-	[OBXOR] = ASBXORD,
-	[OCPL] = ASCPLD
-};
-
-static Node *
-tmpnode(Node *np)
+Node
+rhs(Node *np)
 {
-	Symbol *sym;
-
-	sym = getsym(TMPSYM);
-	sym->type = np->type;
-	sym->kind = STMP;
-	np->u.sym = sym;
-	np->op = OTMP;
-	np->flags |= ISTMP;
-	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, int flags)
+Node
+lhs(Node *np)
 {
-	int op;
-	Type *tp;
-	Node *child;
-
-	child = (flags & LOADL) ? np->left : np->right;
-	if (!child)
-		return NULL;
-	tp = &child->type;
-
-	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;
-	}
-
-	return (flags & LOADL) ? (np->left = child) : (np->right = child);
 }
 
-static Node *
-cast(Node *nd)
+Node
+expr(Node *np)
 {
-	Type *ts, *td;
-	Node *tmp, *ns;
-	int op, disint, sisint;
-	extern Type uint32type, int32type;
-
-	ns = load(nd, LOADL);
-	td = &nd->type;
-	ts = &ns->type;
-	disint = (td->flags & INTF) != 0;
-	sisint = (ts->flags & INTF) != 0;
-
-	if (disint && sisint) {
-		if (td->size <= ts->size)
-			return nd;
-		assert(td->size == 4 || td->size == 8);
-		switch (ts->size) {
-		case 1:
-			op = (td->size == 4) ? ASEXTBW : ASEXTBL;
-			break;
-		case 2:
-			op = (td->size == 4) ? ASEXTHW : ASEXTHL;
-			break;
-		case 4:
-			op = ASEXTWL;
-			break;
-		default:
-			abort();
-		}
-		/*
-		 * unsigned version of operations are always +1 the
-		 * signed version
-		 */
-		op += (td->flags & SIGNF) == 0;
-	} else if (disint) {
-		/* conversion from float to int */
-		switch (ts->size) {
-		case 4:
-			op = (td->size == 8) ? ASSTOL : ASSTOW;
-			break;
-		case 8:
-			op = (td->size == 8) ? ASDTOL : ASDTOW;
-			break;
-		default:
-			abort();
-		}
-		/* TODO: Add signess */
-	} else if (sisint) {
-		/* conversion from int to float */
-		switch (ts->size) {
-		case 1:
-		case 2:
-			tmp = tmpnode(newnode(ONOP));
-			tmp->type = (ts->flags&SIGNF) ? int32type : uint32type;
-			tmp->left = ns;
-			nd->left = ns = cast(tmp);
-		case 4:
-			op = (td->size == 8) ? ASSWTOD : ASSWTOS;
-			break;
-		case 8:
-			op = (td->size == 8) ? ASSLTOD : ASSLTOS;
-			break;
-		default:
-			abort();
-		}
-		/* TODO: Add signess */
-	} else {
-		/* conversion from float to float */
-		op = (td->size == 4) ? ASEXTS : ASTRUNCD;
-	}
-	code(op, tmpnode(nd), ns, NULL);
-	return nd;
 }
 
-static Node *
-call(Node *np)
-{
-	int n, op;
-	Type *tp = &np->type;
-	Node **q, *tmp, *p, *pars[NR_FUNPARAM];
-
-	for (n = 0, p = np->right; p; p = p->right) {
-		cgen(p->left);
-		pars[n++] = load(p, LOADL);
-	}
-
-	switch (tp->size) {
-	case 0:
-		np->left = tmpnode(newnode(OTMP));
-		op = ASCALLW;
-		break;
-	case 1:
-		op = ASCALLB;
-		break;
-	case 2:
-		op = ASCALLH;
-		break;
-	case 4:
-		op = (tp->flags & INTF) ? ASCALLW : ASCALLS;
-		break;
-	case 8:
-		op = (tp->flags & INTF) ? ASCALLL : ASCALLD;
-		break;
-	default:
-		abort();
-	}
-	code(op, tmpnode(np), np->left, NULL);
-
-	for (q = pars; q < &pars[n]; ++q) {
-		op = (q == &pars[n-1]) ? ASPARE : ASPAR;
-		p = newnode(OTMP);
-		p->type = (*q)->type;
-		code(op, NULL, *q, tmpnode(p));
-	}
-	code(ASCALL, NULL, NULL, NULL);
-
-	return np;
-}
-
-static Node *
-abbrev(Node *np)
-{
-	Node *tmp;
-
-	if (np->u.subop == 0)
-		return np->right;
-	tmp = newnode(np->u.subop);
-	tmp->type = np->type;
-	tmp->right = np->right;
-	tmp->left = np->left;
-	return np->right = cgen(tmp);
-}
-
-static Node *
-assign(Node *to, Node *from)
-{
-	Type *tp = &to->type;
-	int op;
-
-	switch (tp->size) {
-	case 1:
-		op = ASSTB;
-		break;
-	case 2:
-		op = ASSTH;
-		break;
-	case 4:
-		op = (tp->flags & INTF) ? ASSTW : ASSTS;
-		break;
-	case 8:
-		op = (tp->flags & INTF) ? ASSTL : ASSTD;
-		break;
-	default:
-		abort();
-	}
-	code(op, to, from, NULL);
-	return from;
-}
-
-static Node *
-ternary(Node *np)
-{
-	Symbol *yes, *no, *phi;
-	Node *ifyes, *ifno, *phinode, *colon;
-
-	tmpnode(np);
-	phi = newlabel();
-	yes = newlabel();
-	no = newlabel();
-
-	ifyes = label2node(yes);
-	ifno = label2node(no);
-	phinode = label2node(phi);
-
-	colon = np->right;
-	cgen(np->left);
-	code(ASBRANCH, load(np, LOADL), ifyes, ifno);
-
-	setlabel(yes);
-	cgen(colon->left);
-	assign(np, load(colon, LOADL));
-	code(ASJMP, NULL, phinode, NULL);
-
-	setlabel(no);
-	cgen(colon->right);
-	assign(np, load(colon, LOADR));
-	setlabel(phi);
-
-	deltree(ifyes);
-	deltree(ifno);
-	deltree(phinode);
-
-	return np;
-}
-
-static Node *
-function(void)
-{
-	Symbol *p;
-
-	/* allocate stack space for parameters */
-	for (p = locals; p && (p->type.flags & PARF) != 0; p = p->next)
-		code(ASALLOC, label2node(p), NULL, NULL);
-
-	/* allocate stack space for local variables) */
-	for ( ; p && p->id != TMPSYM; p = p->next) {
-		if (p->kind != SAUTO)
-			continue;
-		code(ASALLOC, label2node(p), NULL, NULL);
-	}
-	/* store formal parameters in parameters */
-	for (p = locals; p; p = p->next) {
-		if ((p->type.flags & PARF) == 0)
-			break;
-		code(ASFORM, label2node(p), NULL, NULL);
-	}
-	return NULL;
-}
-
-/* TODO: Fix "memory leaks" */
 Node *
 cgen(Node *np)
 {
-	Node *ifyes, *ifno, *next;
-	Symbol *sym;
-	Type *tp;
-	int op, off;
-	char *tbl;
-
-	if (!np)
-		return NULL;
-
-	setlabel(np->label);
-	if (np->op != OCALL && np->op != OASK) {
-		np->left = cgen(np->left);
-		np->right = cgen(np->right);
-	}
-	tp = &np->type;
-
-	switch (np->op) {
-	case OSTRING:
-		abort();
-	case OBFUN:
-		return function();
-	case OEFUN:
-		return NULL;
-	case OCONST:
-	case OLABEL:
-		np->flags |= ISCONS;
-	case OMEM:
-	case OAUTO:
-		return np;
-	case OSHR:
-	case OMOD:
-	case ODIV:
-	case OLT:
-	case OGT:
-	case OLE:
-	case OGE:
-		/*
-		 * unsigned version of operations are always +1 the
-		 * signed version
-		 */
-		off = (tp->flags & SIGNF) == 0;
-		goto binary;
-	case OADD:
-	case OSUB:
-	case OMUL:
-	case OSHL:
-	case OBAND:
-	case OBOR:
-	case OBXOR:
-	case OEQ:
-	case ONE:
-		off = 0;
-	binary:
-		switch (tp->size) {
-		case 4:
-			tbl = (tp->flags & INTF) ? opasmw : opasms;
-			break;
-		case 8:
-			tbl = (tp->flags & INTF) ? opasml : opasmd;
-			break;
-		default:
-			abort();
-		}
-		op = tbl[np->op] + off;
-		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);
-	case OADDR:
-		np->flags |= ISTMP;
-		np->op = OTMP;
-		np->u.sym = np->left->u.sym;
-		return np;
-	case OPTR:
-		load(np, LOADL);
-		load(np, LOADL|FORCE);
-		return np->left;
-	case OCPL:
-	case ONEG:
-	case OINC:
-	case ODEC:
-		abort();
-	case OASSIG:
-		abbrev(np);
-		return assign(np->left, load(np, LOADR));
-	case OCOMMA:
-		return np->right;
-	case OCALL:
-		return call(np);
-	case OFIELD:
-	case OAND:
-	case OOR:
-		abort();
-	case OASK:
-		return ternary(np);
-	case OBRANCH:
-		next = np->next;
-		load(np, LOADL);
-		if (!next->label)
-			next->label = newlabel();
-		ifyes = label2node(np->u.sym);
-		ifno = label2node(next->label);
-		op = ASBRANCH;
-		np = np->left;
-		goto emit_jump;
-	case OJMP:
-		ifyes = label2node(np->u.sym);
-		op = ASJMP;
-		np = ifno = NULL;
-	emit_jump:
-		code(op, np, ifyes, ifno);
-		deltree(ifyes);
-		deltree(ifno);
-		return NULL;
-	case ORET:
-		code(ASRET, NULL, load(np, LOADL), NULL);
-		return NULL;
-	case OCASE:
-	case ODEFAULT:
-	case OESWITCH:
-	case OBSWITCH:
-	default:
-		abort();
-	}
 }
 
 /*
@@ -521,7 +36,7 @@
  *     CONST => 11         $value
  * These values of addressability are not used in the code generation.
  * They are only used to calculate the Sethi-Ullman numbers. Since
- * QBE is AMD64 targered we could do a better job here, and try to
+ * QBE is AMD64 targered we could do a better job there, and try to
  * detect some of the complex addressing modes of these processors.
  */
 Node *
--- /dev/null
+++ b/cc2/arch/qbe/cgen.c.old
@@ -1,0 +1,568 @@
+/* See LICENSE file for copyright and license details. */
+#include <assert.h>
+#include <stdlib.h>
+
+#include "arch.h"
+#include "../../cc2.h"
+#include "../../../inc/sizes.h"
+
+enum lflags {
+	FORCE = 1 << 0,
+	LOADL = 1 << 1,
+	LOADR = 1 << 2
+};
+
+enum sflags {
+	ISTMP  = 1,
+	ISCONS = 2
+};
+
+static char opasmw[] = {
+	[OADD] = ASADDW,
+	[OSUB] = ASSUBW,
+	[OMUL] = ASMULW,
+	[OMOD] = ASMODW,
+	[ODIV] = ASDIVW,
+	[OSHL] = ASSHLW,
+	[OSHR] = ASSHRW,
+	[OLT] = ASLTW,
+	[OGT] = ASGTW,
+	[OLE] = ASLEW,
+	[OGE] = ASGEW,
+	[OEQ] = ASEQW,
+	[ONE] = ASNEW,
+	[OBAND] = ASBANDW,
+	[OBOR] = ASBORW,
+	[OBXOR] = ASBXORW,
+	[OCPL] = ASCPLW
+};
+
+static char opasml[] = {
+	[OADD] = ASADDL,
+	[OSUB] = ASSUBL,
+	[OMUL] = ASMULL,
+	[OMOD] = ASMODL,
+	[ODIV] = ASDIVL,
+	[OSHL] = ASSHLL,
+	[OSHR] = ASSHRL,
+	[OLT] = ASLTL,
+	[OGT] = ASGTL,
+	[OLE] = ASLEL,
+	[OGE] = ASGEL,
+	[OEQ] = ASEQL,
+	[ONE] = ASNEL,
+	[OBAND] = ASBANDL,
+	[OBOR] = ASBORL,
+	[OBXOR] = ASBXORL,
+	[OCPL] = ASCPLL
+};
+
+static char opasms[] = {
+	[OADD] = ASADDS,
+	[OSUB] = ASSUBS,
+	[OMUL] = ASMULS,
+	[OMOD] = ASMODS,
+	[ODIV] = ASDIVS,
+	[OSHL] = ASSHLS,
+	[OSHR] = ASSHRS,
+	[OLT] = ASLTS,
+	[OGT] = ASGTS,
+	[OLE] = ASLES,
+	[OGE] = ASGES,
+	[OEQ] = ASEQS,
+	[ONE] = ASNES,
+	[OBAND] = ASBANDS,
+	[OBOR] = ASBORS,
+	[OBXOR] = ASBXORS,
+	[OCPL] = ASCPLS
+};
+
+static char opasmd[] = {
+	[OADD] = ASADDD,
+	[OSUB] = ASSUBD,
+	[OMUL] = ASMULD,
+	[OMOD] = ASMODD,
+	[ODIV] = ASDIVD,
+	[OSHL] = ASSHLD,
+	[OSHR] = ASSHRD,
+	[OLT] = ASLTD,
+	[OGT] = ASGTD,
+	[OLE] = ASLED,
+	[OGE] = ASGED,
+	[OEQ] = ASEQD,
+	[ONE] = ASNED,
+	[OBAND] = ASBANDD,
+	[OBOR] = ASBORD,
+	[OBXOR] = ASBXORD,
+	[OCPL] = ASCPLD
+};
+
+static Node *
+tmpnode(Node *np)
+{
+	Symbol *sym;
+
+	sym = getsym(TMPSYM);
+	sym->type = np->type;
+	sym->kind = STMP;
+	np->u.sym = sym;
+	np->op = OTMP;
+	np->flags |= ISTMP;
+	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, int flags)
+{
+	int op;
+	Type *tp;
+	Node *child;
+
+	child = (flags & LOADL) ? np->left : np->right;
+	if (!child)
+		return NULL;
+	tp = &child->type;
+
+	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;
+	}
+
+	return (flags & LOADL) ? (np->left = child) : (np->right = child);
+}
+
+static Node *
+cast(Node *nd)
+{
+	Type *ts, *td;
+	Node *tmp, *ns;
+	int op, disint, sisint;
+	extern Type uint32type, int32type;
+
+	ns = load(nd, LOADL);
+	td = &nd->type;
+	ts = &ns->type;
+	disint = (td->flags & INTF) != 0;
+	sisint = (ts->flags & INTF) != 0;
+
+	if (disint && sisint) {
+		if (td->size <= ts->size)
+			return nd;
+		assert(td->size == 4 || td->size == 8);
+		switch (ts->size) {
+		case 1:
+			op = (td->size == 4) ? ASEXTBW : ASEXTBL;
+			break;
+		case 2:
+			op = (td->size == 4) ? ASEXTHW : ASEXTHL;
+			break;
+		case 4:
+			op = ASEXTWL;
+			break;
+		default:
+			abort();
+		}
+		/*
+		 * unsigned version of operations are always +1 the
+		 * signed version
+		 */
+		op += (td->flags & SIGNF) == 0;
+	} else if (disint) {
+		/* conversion from float to int */
+		switch (ts->size) {
+		case 4:
+			op = (td->size == 8) ? ASSTOL : ASSTOW;
+			break;
+		case 8:
+			op = (td->size == 8) ? ASDTOL : ASDTOW;
+			break;
+		default:
+			abort();
+		}
+		/* TODO: Add signess */
+	} else if (sisint) {
+		/* conversion from int to float */
+		switch (ts->size) {
+		case 1:
+		case 2:
+			tmp = tmpnode(newnode(ONOP));
+			tmp->type = (ts->flags&SIGNF) ? int32type : uint32type;
+			tmp->left = ns;
+			nd->left = ns = cast(tmp);
+		case 4:
+			op = (td->size == 8) ? ASSWTOD : ASSWTOS;
+			break;
+		case 8:
+			op = (td->size == 8) ? ASSLTOD : ASSLTOS;
+			break;
+		default:
+			abort();
+		}
+		/* TODO: Add signess */
+	} else {
+		/* conversion from float to float */
+		op = (td->size == 4) ? ASEXTS : ASTRUNCD;
+	}
+	code(op, tmpnode(nd), ns, NULL);
+	return nd;
+}
+
+static Node *
+call(Node *np)
+{
+	int n, op;
+	Type *tp = &np->type;
+	Node **q, *tmp, *p, *pars[NR_FUNPARAM];
+
+	for (n = 0, p = np->right; p; p = p->right) {
+		cgen(p->left);
+		pars[n++] = load(p, LOADL);
+	}
+
+	switch (tp->size) {
+	case 0:
+		np->left = tmpnode(newnode(OTMP));
+		op = ASCALLW;
+		break;
+	case 1:
+		op = ASCALLB;
+		break;
+	case 2:
+		op = ASCALLH;
+		break;
+	case 4:
+		op = (tp->flags & INTF) ? ASCALLW : ASCALLS;
+		break;
+	case 8:
+		op = (tp->flags & INTF) ? ASCALLL : ASCALLD;
+		break;
+	default:
+		abort();
+	}
+	code(op, tmpnode(np), np->left, NULL);
+
+	for (q = pars; q < &pars[n]; ++q) {
+		op = (q == &pars[n-1]) ? ASPARE : ASPAR;
+		p = newnode(OTMP);
+		p->type = (*q)->type;
+		code(op, NULL, *q, tmpnode(p));
+	}
+	code(ASCALL, NULL, NULL, NULL);
+
+	return np;
+}
+
+static Node *
+abbrev(Node *np)
+{
+	Node *tmp;
+
+	if (np->u.subop == 0)
+		return np->right;
+	tmp = newnode(np->u.subop);
+	tmp->type = np->type;
+	tmp->right = np->right;
+	tmp->left = np->left;
+	return np->right = cgen(tmp);
+}
+
+static Node *
+assign(Node *to, Node *from)
+{
+	Type *tp = &to->type;
+	int op;
+
+	switch (tp->size) {
+	case 1:
+		op = ASSTB;
+		break;
+	case 2:
+		op = ASSTH;
+		break;
+	case 4:
+		op = (tp->flags & INTF) ? ASSTW : ASSTS;
+		break;
+	case 8:
+		op = (tp->flags & INTF) ? ASSTL : ASSTD;
+		break;
+	default:
+		abort();
+	}
+	code(op, to, from, NULL);
+	return from;
+}
+
+static Node *
+ternary(Node *np)
+{
+	Symbol *yes, *no, *phi;
+	Node *ifyes, *ifno, *phinode, *colon;
+
+	tmpnode(np);
+	phi = newlabel();
+	yes = newlabel();
+	no = newlabel();
+
+	ifyes = label2node(yes);
+	ifno = label2node(no);
+	phinode = label2node(phi);
+
+	colon = np->right;
+	cgen(np->left);
+	code(ASBRANCH, load(np, LOADL), ifyes, ifno);
+
+	setlabel(yes);
+	cgen(colon->left);
+	assign(np, load(colon, LOADL));
+	code(ASJMP, NULL, phinode, NULL);
+
+	setlabel(no);
+	cgen(colon->right);
+	assign(np, load(colon, LOADR));
+	setlabel(phi);
+
+	deltree(ifyes);
+	deltree(ifno);
+	deltree(phinode);
+
+	return np;
+}
+
+static Node *
+function(void)
+{
+	Symbol *p;
+
+	/* allocate stack space for parameters */
+	for (p = locals; p && (p->type.flags & PARF) != 0; p = p->next)
+		code(ASALLOC, label2node(p), NULL, NULL);
+
+	/* allocate stack space for local variables) */
+	for ( ; p && p->id != TMPSYM; p = p->next) {
+		if (p->kind != SAUTO)
+			continue;
+		code(ASALLOC, label2node(p), NULL, NULL);
+	}
+	/* store formal parameters in parameters */
+	for (p = locals; p; p = p->next) {
+		if ((p->type.flags & PARF) == 0)
+			break;
+		code(ASFORM, label2node(p), NULL, NULL);
+	}
+	return NULL;
+}
+
+/* TODO: Fix "memory leaks" */
+Node *
+cgen(Node *np)
+{
+	Node *ifyes, *ifno, *next;
+	Symbol *sym;
+	Type *tp;
+	int op, off;
+	char *tbl;
+
+	if (!np)
+		return NULL;
+
+	setlabel(np->label);
+	if (np->op != OCALL && np->op != OASK) {
+		np->left = cgen(np->left);
+		np->right = cgen(np->right);
+	}
+	tp = &np->type;
+
+	switch (np->op) {
+	case OSTRING:
+		abort();
+	case OBFUN:
+		return function();
+	case OEFUN:
+		return NULL;
+	case OCONST:
+	case OLABEL:
+		np->flags |= ISCONS;
+	case OMEM:
+	case OAUTO:
+		return np;
+	case OSHR:
+	case OMOD:
+	case ODIV:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		/*
+		 * unsigned version of operations are always +1 the
+		 * signed version
+		 */
+		off = (tp->flags & SIGNF) == 0;
+		goto binary;
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case OSHL:
+	case OBAND:
+	case OBOR:
+	case OBXOR:
+	case OEQ:
+	case ONE:
+		off = 0;
+	binary:
+		switch (tp->size) {
+		case 4:
+			tbl = (tp->flags & INTF) ? opasmw : opasms;
+			break;
+		case 8:
+			tbl = (tp->flags & INTF) ? opasml : opasmd;
+			break;
+		default:
+			abort();
+		}
+		op = tbl[np->op] + off;
+		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);
+	case OADDR:
+		np->flags |= ISTMP;
+		np->op = OTMP;
+		np->u.sym = np->left->u.sym;
+		return np;
+	case OPTR:
+		load(np, LOADL);
+		load(np, LOADL|FORCE);
+		return np->left;
+	case OCPL:
+	case ONEG:
+	case OINC:
+	case ODEC:
+		abort();
+	case OASSIG:
+		abbrev(np);
+		return assign(np->left, load(np, LOADR));
+	case OCOMMA:
+		return np->right;
+	case OCALL:
+		return call(np);
+	case OFIELD:
+	case OAND:
+	case OOR:
+		abort();
+	case OASK:
+		return ternary(np);
+	case OBRANCH:
+		next = np->next;
+		load(np, LOADL);
+		if (!next->label)
+			next->label = newlabel();
+		ifyes = label2node(np->u.sym);
+		ifno = label2node(next->label);
+		op = ASBRANCH;
+		np = np->left;
+		goto emit_jump;
+	case OJMP:
+		ifyes = label2node(np->u.sym);
+		op = ASJMP;
+		np = ifno = NULL;
+	emit_jump:
+		code(op, np, ifyes, ifno);
+		deltree(ifyes);
+		deltree(ifno);
+		return NULL;
+	case ORET:
+		code(ASRET, NULL, load(np, LOADL), NULL);
+		return NULL;
+	case OCASE:
+	case ODEFAULT:
+	case OESWITCH:
+	case OBSWITCH:
+	default:
+		abort();
+	}
+}
+
+/*
+ * This is strongly influenced by
+ * http://plan9.bell-labs.com/sys/doc/compiler.ps (/sys/doc/compiler.ps)
+ * calculate addresability as follows
+ *     AUTO => 11          value+fp
+ *     REG => 11           reg
+ *     STATIC => 11        (value)
+ *     CONST => 11         $value
+ * These values of addressability are not used in the code generation.
+ * They are only used to calculate the Sethi-Ullman numbers. Since
+ * QBE is AMD64 targered we could do a better job here, and try to
+ * detect some of the complex addressing modes of these processors.
+ */
+Node *
+sethi(Node *np)
+{
+	Node *lp, *rp;
+
+	if (!np)
+		return np;
+
+	np->complex = 0;
+	np->address = 0;
+	lp = np->left;
+	rp = np->right;
+
+	switch (np->op) {
+	case OAUTO:
+	case OREG:
+	case OMEM:
+	case OCONST:
+		np->address = 11;
+		break;
+	default:
+		sethi(lp);
+		sethi(rp);
+		break;
+	}
+
+	if (np->address > 10)
+		return np;
+	if (lp)
+		np->complex = lp->complex;
+	if (rp) {
+		int d = np->complex - rp->complex;
+
+		if (d == 0)
+			++np->complex;
+		else if (d < 0)
+			np->complex = rp->complex;
+	}
+	if (np->complex == 0)
+		++np->complex;
+	return np;
+}