shithub: scc

Download patch

ref: 51726ed12da4175bb9f73f8bf72e02fe5a816fd1
parent: 1344701bd8e23e73e5f94096485553b534ba4890
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Sun Aug 27 15:05:17 EDT 2017

[cc1+cc2] Initial work needed for qbe_arm64

This patch prepare the tree for qbe_arm64 and add empty files for
cc1/target/arch.c and cc2/target/types.c

diff: cannot open b/cc1/target/arm64-sysv//null: file does not exist: 'b/cc1/target/arm64-sysv//null' diff: cannot open b/cc2/target/arm64-sysv//null: file does not exist: 'b/cc2/target/arm64-sysv//null' diff: cannot open b/cc2/target/qbe//null: file does not exist: 'b/cc2/target/qbe//null' diff: cannot open b/cc2/target/qbe_arm64-sysv//null: file does not exist: 'b/cc2/target/qbe_arm64-sysv//null'
--- /dev/null
+++ b/cc2/target/qbe/arch.h
@@ -1,0 +1,137 @@
+/* See LICENSE file for copyright and license details. */
+
+enum asmop {
+	ASNOP = 0,
+	ASSTB,
+	ASSTH,
+	ASSTW,
+	ASSTL,
+	ASSTM,
+	ASSTS,
+	ASSTD,
+
+	ASLDSB,
+	ASLDUB,
+	ASLDSH,
+	ASLDUH,
+	ASLDSW,
+	ASLDUW,
+	ASLDL,
+	ASLDS,
+	ASLDD,
+
+	ASADDW,
+	ASSUBW,
+	ASMULW,
+	ASMODW,
+	ASUMODW,
+	ASDIVW,
+	ASUDIVW,
+	ASSHLW,
+	ASSHRW,
+	ASUSHRW,
+	ASLTW,
+	ASULTW,
+	ASGTW,
+	ASUGTW,
+	ASLEW,
+	ASULEW,
+	ASGEW,
+	ASUGEW,
+	ASEQW,
+	ASNEW,
+	ASBANDW,
+	ASBORW,
+	ASBXORW,
+
+	ASADDL,
+	ASSUBL,
+	ASMULL,
+	ASMODL,
+	ASUMODL,
+	ASDIVL,
+	ASUDIVL,
+	ASSHLL,
+	ASSHRL,
+	ASUSHRL,
+	ASLTL,
+	ASULTL,
+	ASGTL,
+	ASUGTL,
+	ASLEL,
+	ASULEL,
+	ASGEL,
+	ASUGEL,
+	ASEQL,
+	ASNEL,
+	ASBANDL,
+	ASBORL,
+	ASBXORL,
+
+	ASADDS,
+	ASSUBS,
+	ASMULS,
+	ASDIVS,
+	ASLTS,
+	ASGTS,
+	ASLES,
+	ASGES,
+	ASEQS,
+	ASNES,
+
+	ASADDD,
+	ASSUBD,
+	ASMULD,
+	ASDIVD,
+	ASLTD,
+	ASGTD,
+	ASLED,
+	ASGED,
+	ASEQD,
+	ASNED,
+
+	ASEXTBW,
+	ASUEXTBW,
+	ASEXTBL,
+	ASUEXTBL,
+	ASEXTHW,
+	ASUEXTHW,
+	ASEXTHL,
+	ASUEXTHL,
+	ASEXTWL,
+	ASUEXTWL,
+
+	ASSTOL,
+	ASSTOW,
+	ASDTOL,
+	ASDTOW,
+
+	ASSWTOD,
+	ASSWTOS,
+	ASSLTOD,
+	ASSLTOS,
+
+	ASEXTS,
+	ASTRUNCD,
+
+	ASJMP,
+	ASBRANCH,
+	ASRET,
+	ASCALL,
+	ASCALLE,
+	ASCALLEX,
+	ASPAR,
+	ASPARE,
+	ASALLOC,
+	ASFORM,
+
+	ASCOPYB,
+	ASCOPYH,
+	ASCOPYW,
+	ASCOPYL,
+	ASCOPYS,
+	ASCOPYD,
+
+	ASVSTAR,
+	ASVARG,
+};
--- /dev/null
+++ b/cc2/target/qbe/cgen.c
@@ -1,0 +1,731 @@
+/* See LICENSE file for copyright and license details. */
+static char sccsid[] = "@(#) ./cc2/arch/qbe/cgen.c";
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <cstd.h>
+#include "arch.h"
+#include "../../../inc/scc.h"
+#include "../../cc2.h"
+
+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,
+};
+
+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,
+};
+
+static char opasms[] = {
+	[OADD] = ASADDS,
+	[OSUB] = ASSUBS,
+	[OMUL] = ASMULS,
+	[ODIV] = ASDIVS,
+	[OLT] = ASLTS,
+	[OGT] = ASGTS,
+	[OLE] = ASLES,
+	[OGE] = ASGES,
+	[OEQ] = ASEQS,
+	[ONE] = ASNES,
+};
+static char opasmd[] = {
+	[OADD] = ASADDD,
+	[OSUB] = ASSUBD,
+	[OMUL] = ASMULD,
+	[ODIV] = ASDIVD,
+	[OLT] = ASLTD,
+	[OGT] = ASGTD,
+	[OLE] = ASLED,
+	[OGE] = ASGED,
+	[OEQ] = ASEQD,
+	[ONE] = ASNED,
+};
+
+extern Type int32type, uint32type, ptrtype;
+
+static Node *
+tmpnode(Node *np, Type *tp)
+{
+	char flags;
+	Symbol *sym;
+
+	if (!np)
+		np = newnode(OTMP);
+	sym = getsym(TMPSYM);
+	sym->type = np->type = *tp;
+	flags = tp->flags & ~(PARF|INITF);
+	sym->type.flags = np->type.flags = flags;
+	sym->kind = STMP;
+	np->left = np->right = NULL;
+	np->u.sym = sym;
+	np->op = OTMP;
+	np->flags |= ISTMP;
+	return np;
+}
+
+static Node *
+load(Type *tp, Node *np, Node *new)
+{
+	int op;
+	int flags = tp->flags;
+
+	if (flags & (AGGRF|FUNF)) {
+		*new = *np;
+		return new;
+	}
+	switch (tp->size) {
+	case 1:
+		op = ASLDSB;
+		break;
+	case 2:
+		op = ASLDSH;
+		break;
+	case 4:
+		op = (flags & FLOATF) ? ASLDS : ASLDSW;
+		break;
+	case 8:
+		op = (flags & FLOATF) ? ASLDD : ASLDL;
+		break;
+	default:
+		abort();
+	}
+	/*
+	 * unsigned version of operations are always +1 the
+	 * signed version
+	 */
+	if ((flags & (INTF|SIGNF)) == INTF && tp->size < 8)
+		++op;
+
+	code(op, tmpnode(new, tp), np, NULL);
+
+	return new;
+}
+
+static Node *rhs(Node *np, Node *new);
+
+static Node *
+cast(Type *td, Node *ns, Node *nd)
+{
+	Type *ts;
+	Node aux1, aux2;
+	int op, d_isint, s_isint;
+
+	ts = &ns->type;
+	d_isint = (td->flags & INTF) != 0;
+	s_isint = (ts->flags & INTF) != 0;
+
+	if (d_isint && s_isint) {
+		if (td->size <= ts->size) {
+			*nd = *ns;
+			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 += (ts->flags & SIGNF) == 0;
+	} else if (d_isint) {
+		/* 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 (s_isint) {
+		/* conversion from int to float */
+		switch (ts->size) {
+		case 1:
+		case 2:
+			ts = (ts->flags&SIGNF) ? &int32type : &uint32type;
+			ns = cast(ts, ns, tmpnode(&aux2, ts));
+		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, td), ns, NULL);
+	return nd;
+}
+
+static Node *rhs(Node *np, Node *new);
+
+static Node *
+call(Node *np, Node *fun, Node *ret)
+{
+	int n, op;
+	Type *tp;
+	Node aux, **q, *p, *pars[NR_FUNPARAM];
+
+	for (n = 0, p = np->right; p; p = p->right)
+		pars[n++] = rhs(p->left, newnode(OTMP));
+
+	tp = &np->type;
+	code(ASCALL, tmpnode(ret, tp), fun, NULL);
+
+	for (q = pars; q < &pars[n]; ++q) {
+		op = (q == &pars[n-1]) ? ASPARE : ASPAR;
+		tmpnode(&aux, &(*q)->type);
+		code(op, NULL, *q, &aux);
+	}
+	code((np->op == OCALL) ? ASCALLE : ASCALLEX, NULL, NULL, NULL);
+
+	return ret;
+}
+
+static Node *
+assign(Type *tp, Node *to, Node *from)
+{
+	int op;
+
+	switch (tp->size) {
+	case 1:
+		op = ASSTB;
+		break;
+	case 2:
+		op = ASSTH;
+		break;
+	case 4:
+		op = (tp->flags & FLOATF) ? ASSTS : ASSTW;
+		break;
+	case 8:
+		op = (tp->flags & FLOATF) ? ASSTD : ASSTL;
+		break;
+	default:
+		op = ASSTM;
+		break;
+	}
+	code(op, to, from, NULL);
+	return from;
+}
+
+static Node *
+copy(Type *tp, Node *to, Node *from)
+{
+	int op;
+
+	switch (tp->size) {
+	case 1:
+		op = ASCOPYB;
+		break;
+	case 2:
+		op = ASCOPYH;
+		break;
+	case 4:
+		op = (tp->flags & FLOATF) ? ASCOPYS : ASCOPYW;
+		break;
+	case 8:
+		op = (tp->flags & FLOATF) ? ASCOPYD : ASCOPYL;
+		break;
+	default:
+		/* TODO: Need to handle the general case */
+		abort();
+	}
+	code(op, to, from, NULL);
+	return from;
+}
+
+/* TODO: Do field() transformation in sethi */
+
+static Node *
+field(Node *np, Node *ret, int islhs)
+{
+	Node base, node, off, add, *addr;
+	TUINT offset = np->right->u.sym->u.off;
+
+	addr = rhs(np->left, &base);
+
+	if (offset != 0) {
+		node.op = OADD;
+		node.type = ptrtype;
+		node.left = addr;
+		node.right = constnode(&off, offset, &ptrtype);
+		addr = rhs(&node, &add);
+	}
+
+	if (islhs)
+		*ret = *addr;
+	else
+		load(&np->type, addr, ret);
+
+	return ret;
+}
+
+static Node *
+lhs(Node *np, Node *new)
+{
+	switch (np->op) {
+	case OMEM:
+	case OAUTO:
+		*new = *np;
+		return new;
+	case OPTR:
+		return rhs(np->left, new);
+	case OFIELD:
+		return field(np, new, 1);
+	default:
+		abort();
+	}
+}
+
+static void
+bool(Node *np, Symbol *true, Symbol *false)
+{
+	Node *l = np->left, *r = np->right;
+	Node ret, ifyes, ifno;
+	Symbol *label;
+
+	switch (np->op) {
+	case ONEG:
+		bool(l, false, true);
+		break;
+	case OAND:
+		label = newlabel();
+		bool(l, label, false);
+		setlabel(label);
+		bool(r, true, false);
+		break;
+	case OOR:
+		label = newlabel();
+		bool(l, true, label);
+		setlabel(label);
+		bool(r, true, false);
+		break;
+	default:
+		label2node(&ifyes, true);
+		label2node(&ifno, false);
+		code(ASBRANCH, rhs(np, &ret), &ifyes, &ifno);
+		break;
+	}
+}
+
+static Node *
+ternary(Node *np, Node *ret)
+{
+	Node ifyes, ifno, phi, *colon, aux1, aux2, aux3;
+
+	tmpnode(ret, &np->type);
+	label2node(&ifyes, NULL);
+	label2node(&ifno, NULL);
+	label2node(&phi, NULL);
+
+	colon = np->right;
+	code(ASBRANCH, rhs(np->left, &aux1), &ifyes, &ifno);
+
+	setlabel(ifyes.u.sym);
+	copy(&ret->type, ret, rhs(colon->left, &aux2));
+	code(ASJMP, NULL, &phi, NULL);
+
+	setlabel(ifno.u.sym);
+	copy(&ret->type, ret, rhs(colon->right, &aux3));
+	setlabel(phi.u.sym);
+
+	return ret;
+}
+
+static Node *
+function(void)
+{
+	Node aux;
+	Symbol *p;
+
+	/* allocate stack space for parameters */
+	for (p = locals; p && (p->type.flags & PARF) != 0; p = p->next)
+		code(ASALLOC, label2node(&aux, 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(&aux, 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(&aux, p), NULL, NULL);
+	}
+	return NULL;
+}
+
+static void
+swtch_if(Node *idx)
+{
+	Node aux1, aux2, *np;
+	Symbol *deflabel = NULL;
+
+	for (;;) {
+		np = delstmt();
+		setlabel(np->label);
+
+		switch (np->op) {
+		case OESWITCH:
+			if (!deflabel)
+				deflabel = np->u.sym;
+			aux1.op = OJMP;
+			aux1.label = NULL;
+			aux1.u.sym = deflabel;
+			cgen(&aux1);
+			return;
+		case OCASE:
+			aux1 = *np;
+			aux1.op = OBRANCH;
+			aux1.label = NULL;
+			aux1.left = &aux2;
+
+			aux2.op = OEQ;
+			aux2.type = idx->type;
+			aux2.left = np->left;
+			aux2.right = idx;
+
+			cgen(&aux1);
+			break;
+		case ODEFAULT:
+			deflabel = np->u.sym;
+			break;
+		default:
+			abort();
+		}
+	}
+}
+
+static Node *
+rhs(Node *np, Node *ret)
+{
+	Node aux1, aux2, *phi, *l = np->left, *r = np->right;
+	Type *tp;
+	int off, op;
+	char *tbl;
+	Symbol *true, *false;
+
+	tp = &np->type;
+
+	switch (np->op) {
+	case OBFUN:
+		return function();
+	case ONOP:
+	case OBLOOP:
+	case OELOOP:
+	case OEFUN:
+		return NULL;
+	case OTMP:
+	case OCONST:
+		*ret = *np;
+		return np;
+	case OMEM:
+	case OAUTO:
+		return load(tp, np, ret);
+	case ONEG:
+	case OAND:
+	case OOR:
+		true = newlabel();
+		false = newlabel();
+		phi = label2node(&aux1, NULL);
+		tmpnode(ret, &int32type);
+
+		bool(np, true, false);
+
+		setlabel(true);
+		code(ASCOPYW, ret, constnode(&aux2, 1, &int32type), NULL);
+		code(ASJMP, NULL, phi, NULL);
+
+		setlabel(false);
+		code(ASCOPYW, ret, constnode(&aux2, 0, &int32type), NULL);
+
+		setlabel(phi->u.sym);
+		return ret;
+        case OMOD:
+        case OSHR:
+		assert(tp->flags & INTF);
+        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 OSHL:
+        case OBAND:
+        case OBOR:
+        case OBXOR:
+		assert(tp->flags & INTF);
+        case OADD:
+        case OSUB:
+        case OMUL:
+        case OEQ:
+        case ONE:
+                off = 0;
+        binary:
+		if (l->complex >= r->complex) {
+			rhs(l, &aux1);
+			rhs(r, &aux2);
+		} else {
+			rhs(r, &aux2);
+			rhs(l, &aux1);
+		}
+                switch (tp->size) {
+                case 4:
+                        tbl = (tp->flags & FLOATF) ? opasms : opasmw;
+                        break;
+                case 8:
+                        tbl = (tp->flags & FLOATF) ? opasmd : opasml;
+                        break;
+                default:
+                        abort();
+                }
+                op = tbl[np->op] + off;
+		tmpnode(ret, tp);
+                code(op, ret, &aux1, &aux2);
+                return ret;
+	case OCALL:
+	case OCALLE:
+		if (l->op == OPTR)
+			l = rhs(l, &aux1);
+		return call(np, l, ret);
+	case OCAST:
+		return cast(tp, rhs(l, &aux1), ret);
+	case OASSIG:
+		/* TODO: Do this transformations in sethi */
+		switch (np->u.subop) {
+		case OINC:
+			op = OADD;
+			goto post_oper;
+		case ODEC:
+			op = OSUB;
+		post_oper:
+			aux1.op = op;
+			aux1.left = rhs(l, ret);
+			aux1.right = r;
+			aux1.type = np->type;
+			rhs(&aux1, &aux2);
+			lhs(l, &aux1);
+			assign(tp, &aux1, &aux2);
+			break;
+		default:
+			aux2.type = np->type;
+			aux2.op = np->u.subop;
+			aux2.right = np->right;
+			aux2.left = np->left;
+			r = rhs(&aux2, &aux1);
+			Node aux3;
+			if (l->op == OCAST) {
+				aux3.type = l->left->type;
+				aux3.op = OCAST;
+				aux3.left = r;
+				aux3.right = NULL;
+				r = &aux3;
+				l = l->left;
+			}
+		case 0:
+			/* TODO: see what is the most difficult */
+			lhs(l, &aux2);
+			rhs(r, ret);
+			return assign(tp, &aux2, ret);
+		}
+		return ret;
+	case OASK:
+		return ternary(np, ret);
+	case OCOMMA:
+		rhs(l, &aux1);
+		return rhs(r, ret);
+	case OPTR:
+		return load(tp, rhs(l, &aux1), ret);
+	case OADDR:
+		lhs(l, ret);
+		ret->type = *tp;
+		return ret;
+	case OFIELD:
+		return field(np, ret, 0);
+	case OBUILTIN:
+		switch (np->u.subop) {
+		case BVA_START:
+			l = rhs(l, &aux1);
+			code(ASVSTAR, NULL, l, NULL);
+			return NULL;
+		case BVA_END:
+			return NULL;
+		case BVA_ARG:
+			l = rhs(l, &aux1);
+			code(ASVARG, tmpnode(ret, tp), l, NULL);
+			return ret;
+		case BVA_COPY:
+			/* TODO */
+		default:
+			abort();
+		}
+	default:
+		abort();
+	}
+	abort();
+}
+
+Node *
+cgen(Node *np)
+{
+	Node aux, *p, *next;
+
+	setlabel(np->label);
+	switch (np->op) {
+	case OJMP:
+		label2node(&aux, np->u.sym);
+		code(ASJMP, NULL, &aux, NULL);
+		break;
+	case OBRANCH:
+		next = np->next;
+		if (!next->label)
+			next->label = newlabel();
+		bool(np->left, np->u.sym, next->label);
+		break;
+	case ORET:
+		p = (np->left) ? rhs(np->left, &aux) : NULL;
+		code(ASRET, NULL, p, NULL);
+		break;
+	case OBSWITCH:
+		p = rhs(np->left, &aux);
+		swtch_if(p);
+		break;
+	default:
+		rhs(np, &aux);
+		break;
+	}
+	return NULL;
+}
+
+/*
+ * 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 there, 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;
+	case OCPL:
+		assert(np->type.flags & INTF);
+		np->op = OBXOR;
+		rp = constnode(NULL, ~(TUINT) 0, &np->type);
+		goto binary;
+	case OSNEG:
+		np->op = OSUB;
+		rp = lp;
+		lp = constnode(NULL, 0, &np->type);
+		if ((np->type.flags & INTF) == 0)
+			lp->u.f = 0.0;
+	default:
+	binary:
+		lp = sethi(lp);
+		rp = sethi(rp);
+		break;
+	}
+	np->left = lp;
+	np->right = rp;
+
+	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;
+}
--- /dev/null
+++ b/cc2/target/qbe/code.c
@@ -1,0 +1,569 @@
+/* See LICENSE file for copyright and license details. */
+static char sccsid[] = "@(#) ./cc2/arch/qbe/code.c";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cstd.h>
+#include "arch.h"
+#include "../../../inc/scc.h"
+#include "../../cc2.h"
+
+#define ADDR_LEN (INTIDENTSIZ+64)
+
+static void binary(void), unary(void), store(void), jmp(void), ret(void),
+            branch(void), call(void), ecall(void), param(void),
+            alloc(void), form2local(void), ldir(void), vastart(void),
+            vaarg(void);
+
+static struct opdata {
+	void (*fun)(void);
+	char *txt;
+	char letter;
+} optbl [] = {
+	[ASLDSB]  =  {.fun = unary,  .txt = "loadsb", .letter = 'w'},
+	[ASLDUB]  =  {.fun = unary,  .txt = "loadub", .letter = 'w'},
+	[ASLDSH]  =  {.fun = unary,  .txt = "loadsh", .letter = 'w'},
+	[ASLDUH]  =  {.fun = unary,  .txt = "loaduh", .letter = 'w'},
+	[ASLDSW]  =  {.fun = unary,  .txt = "loadsw", .letter = 'w'},
+	[ASLDUW]  =  {.fun = unary,  .txt = "loaduw", .letter = 'w'},
+	[ASLDL]   =  {.fun = unary,  .txt = "loadl", .letter = 'l'},
+	[ASLDS]   =  {.fun = unary,  .txt = "loads", .letter = 's'},
+	[ASLDD]   =  {.fun = unary,  .txt = "loadd", .letter = 'd'},
+
+	[ASCOPYB] =  {.fun = unary,  .txt = "copy", .letter = 'b'},
+	[ASCOPYH] =  {.fun = unary,  .txt = "copy", .letter = 'h'},
+	[ASCOPYW] =  {.fun = unary,  .txt = "copy", .letter = 'w'},
+	[ASCOPYL] =  {.fun = unary,  .txt = "copy", .letter = 'l'},
+	[ASCOPYS] =  {.fun = unary,  .txt = "copy", .letter = 's'},
+	[ASCOPYD] =  {.fun = unary,  .txt = "copy", .letter = 'd'},
+
+	[ASSTB]   =  {.fun = store,  .txt = "store", .letter = 'b'},
+	[ASSTH]   =  {.fun = store,  .txt = "store", .letter = 'h'},
+	[ASSTW]   =  {.fun = store,  .txt = "store", .letter = 'w'},
+	[ASSTL]   =  {.fun = store,  .txt = "store", .letter = 'l'},
+	[ASSTM]   =  {.fun = ldir},
+	[ASSTS]   =  {.fun = store,  .txt = "store", .letter = 's'},
+	[ASSTD]   =  {.fun = store,  .txt = "store", .letter = 'd'},
+
+	[ASADDW]  =  {.fun = binary, .txt = "add", .letter = 'w'},
+	[ASSUBW]  =  {.fun = binary, .txt = "sub", .letter = 'w'},
+	[ASMULW]  =  {.fun = binary, .txt = "mul", .letter = 'w'},
+	[ASMODW]  =  {.fun = binary, .txt = "rem", .letter = 'w'},
+	[ASUMODW] =  {.fun = binary, .txt = "urem", .letter = 'w'},
+	[ASDIVW]  =  {.fun = binary, .txt = "div", .letter = 'w'},
+	[ASUDIVW] =  {.fun = binary, .txt = "udiv", .letter = 'w'},
+	[ASSHLW]  =  {.fun = binary, .txt = "shl", .letter = 'w'},
+	[ASSHRW]  =  {.fun = binary, .txt = "sar", .letter = 'w'},
+	[ASUSHRW] =  {.fun = binary, .txt = "shr", .letter = 'w'},
+	[ASLTW]   =  {.fun = binary, .txt = "csltw", .letter = 'w'},
+	[ASULTW]  =  {.fun = binary, .txt = "cultw", .letter = 'w'},
+	[ASGTW]   =  {.fun = binary, .txt = "csgtw", .letter = 'w'},
+	[ASUGTW]  =  {.fun = binary, .txt = "cugtw", .letter = 'w'},
+	[ASLEW]   =  {.fun = binary, .txt = "cslew", .letter = 'w'},
+	[ASULEW]  =  {.fun = binary, .txt = "culew", .letter = 'w'},
+	[ASGEW]   =  {.fun = binary, .txt = "csgew", .letter = 'w'},
+	[ASUGEW]  =  {.fun = binary, .txt = "cugew", .letter = 'w'},
+	[ASEQW]   =  {.fun = binary, .txt = "ceqw", .letter = 'w'},
+	[ASNEW]   =  {.fun = binary, .txt = "cnew", .letter = 'w'},
+	[ASBANDW] =  {.fun = binary, .txt = "and", .letter = 'w'},
+	[ASBORW]  =  {.fun = binary, .txt = "or", .letter = 'w'},
+	[ASBXORW] =  {.fun = binary, .txt = "xor", .letter = 'w'},
+
+	[ASADDL]  =  {.fun = binary, .txt = "add", .letter = 'l'},
+	[ASSUBL]  =  {.fun = binary, .txt = "sub", .letter = 'l'},
+	[ASMULL]  =  {.fun = binary, .txt = "mul", .letter = 'l'},
+	[ASMODL]  =  {.fun = binary, .txt = "rem", .letter = 'l'},
+	[ASUMODL] =  {.fun = binary, .txt = "urem", .letter = 'l'},
+	[ASDIVL]  =  {.fun = binary, .txt = "div", .letter = 'l'},
+	[ASUDIVL] =  {.fun = binary, .txt = "udiv", .letter = 'l'},
+	[ASSHLL]  =  {.fun = binary, .txt = "shl", .letter = 'l'},
+	[ASSHRL]  =  {.fun = binary, .txt = "sar", .letter = 'l'},
+	[ASUSHRL] =  {.fun = binary, .txt = "shr", .letter = 'l'},
+	[ASLTL]   =  {.fun = binary, .txt = "csltl", .letter = 'w'},
+	[ASULTL]  =  {.fun = binary, .txt = "cultl", .letter = 'w'},
+	[ASGTL]   =  {.fun = binary, .txt = "csgtl", .letter = 'w'},
+	[ASUGTL]  =  {.fun = binary, .txt = "cugtl", .letter = 'w'},
+	[ASLEL]   =  {.fun = binary, .txt = "cslel", .letter = 'w'},
+	[ASULEL]  =  {.fun = binary, .txt = "culel", .letter = 'w'},
+	[ASGEL]   =  {.fun = binary, .txt = "csgel", .letter = 'w'},
+	[ASUGEL]  =  {.fun = binary, .txt = "cugel", .letter = 'w'},
+	[ASEQL]   =  {.fun = binary, .txt = "ceql", .letter = 'w'},
+	[ASNEL]   =  {.fun = binary, .txt = "cnel", .letter = 'w'},
+	[ASBANDL] =  {.fun = binary, .txt = "and", .letter = 'l'},
+	[ASBORL]  =  {.fun = binary, .txt = "or", .letter = 'l'},
+	[ASBXORL] =  {.fun = binary, .txt = "xor", .letter = 'l'},
+
+	[ASADDS]  =  {.fun = binary, .txt = "add", .letter = 's'},
+	[ASSUBS]  =  {.fun = binary, .txt = "sub", .letter = 's'},
+	[ASMULS]  =  {.fun = binary, .txt = "mul", .letter = 's'},
+	[ASDIVS]  =  {.fun = binary, .txt = "div", .letter = 's'},
+	[ASLTS]   =  {.fun = binary, .txt = "clts", .letter = 'w'},
+	[ASGTS]   =  {.fun = binary, .txt = "cgts", .letter = 'w'},
+	[ASLES]   =  {.fun = binary, .txt = "cles", .letter = 'w'},
+	[ASGES]   =  {.fun = binary, .txt = "cges", .letter = 'w'},
+	[ASEQS]   =  {.fun = binary, .txt = "ceqs", .letter = 'w'},
+	[ASNES]   =  {.fun = binary, .txt = "cnes", .letter = 'w'},
+
+	[ASADDD]  =  {.fun = binary, .txt = "add", .letter = 'd'},
+	[ASSUBD]  =  {.fun = binary, .txt = "sub", .letter = 'd'},
+	[ASMULD]  =  {.fun = binary, .txt = "mul", .letter = 'd'},
+	[ASDIVD]  =  {.fun = binary, .txt = "div", .letter = 'd'},
+	[ASLTD]   =  {.fun = binary, .txt = "cltd", .letter = 'w'},
+	[ASGTD]   =  {.fun = binary, .txt = "cgtd", .letter = 'w'},
+	[ASLED]   =  {.fun = binary, .txt = "cled", .letter = 'w'},
+	[ASGED]   =  {.fun = binary, .txt = "cged", .letter = 'w'},
+	[ASEQD]   =  {.fun = binary, .txt = "ceqd", .letter = 'w'},
+	[ASNED]   =  {.fun = binary, .txt = "cned", .letter = 'w'},
+
+	[ASEXTBW] =  {.fun = unary, .txt = "extsb", .letter = 'w'},
+	[ASUEXTBW]=  {.fun = unary, .txt = "extub", .letter = 'w'},
+	[ASEXTBL] =  {.fun = unary, .txt = "extsb", .letter = 'l'},
+	[ASUEXTBL]=  {.fun = unary, .txt = "extub", .letter = 'l'},
+	[ASEXTHW] =  {.fun = unary, .txt = "extsh", .letter = 'w'},
+	[ASUEXTHW]=  {.fun = unary, .txt = "extuh", .letter = 'w'},
+	[ASEXTWL] =  {.fun = unary, .txt = "extsw", .letter = 'l'},
+	[ASUEXTWL]=  {.fun = unary, .txt = "extuw", .letter = 'l'},
+
+	[ASSTOL] = {.fun = unary, .txt = "stosi", .letter = 'l'},
+	[ASSTOW] = {.fun = unary, .txt = "stosi", .letter = 'w'},
+	[ASDTOL] = {.fun = unary, .txt = "dtosi", .letter = 'l'},
+	[ASDTOW] = {.fun = unary, .txt = "dtosi", .letter = 'w'},
+
+	[ASSWTOD] = {.fun = unary, .txt = "swtof", .letter = 'd'},
+	[ASSWTOS] = {.fun = unary, .txt = "swtof", .letter = 's'},
+	[ASSLTOD] = {.fun = unary, .txt = "sltof", .letter = 'd'},
+	[ASSLTOS] = {.fun = unary, .txt = "sltof", .letter = 's'},
+
+	[ASEXTS] = {.fun = unary, .txt = "exts", .letter = 'd'},
+	[ASTRUNCD] = {.fun = unary, .txt = "truncd", .letter = 's'},
+
+	[ASBRANCH] = {.fun = branch},
+	[ASJMP]  = {.fun = jmp},
+	[ASRET]  = {.fun = ret},
+	[ASCALL] = {.fun = call},
+	[ASCALLE] = {.fun = ecall, .txt = ")"},
+	[ASCALLEX] = {.fun = ecall, .txt = ", ...)"},
+	[ASPAR] = {.fun = param, .txt = "%s %s, "},
+	[ASPARE] = {.fun = param, .txt = "%s %s"},
+	[ASALLOC] = {.fun = alloc},
+	[ASFORM] = {.fun = form2local},
+
+	[ASVSTAR] = {.fun = vastart},
+	[ASVARG] = {.fun = vaarg},
+};
+
+static char buff[ADDR_LEN];
+/*
+ * : is for user-defined Aggregate Types
+ * $ is for globals (represented by a pointer)
+ * % is for function-scope temporaries
+ * @ is for block labels
+ */
+static char
+sigil(Symbol *sym)
+{
+	switch (sym->kind) {
+	case SEXTRN:
+	case SGLOB:
+	case SPRIV:
+	case SLOCAL:
+		return '$';
+	case SAUTO:
+	case STMP:
+		return '%';
+	case SLABEL:
+		return '@';
+	default:
+		abort();
+	}
+}
+
+static char *
+symname(Symbol *sym)
+{
+	char c = sigil(sym);
+
+	if (sym->name) {
+		switch (sym->kind) {
+		case SEXTRN:
+		case SGLOB:
+			sprintf(buff, "%c%s", c, sym->name);
+			return buff;
+		case SLOCAL:
+		case SPRIV:
+		case SAUTO:
+			sprintf(buff, "%c%s.%u", c, sym->name, sym->id);
+			return buff;
+		default:
+			abort();
+		}
+	}
+	sprintf(buff, "%c.%u", c, sym->numid);
+
+	return buff;
+}
+
+static void
+emitconst(Node *np)
+{
+	switch (np->type.size) {
+	case 1:
+		printf("%d", (int) np->u.i & 0xFF);
+		break;
+	case 2:
+		printf("%d", (int) np->u.i & 0xFFFF);
+		break;
+	case 4:
+		printf("%ld", (long) np->u.i & 0xFFFFFFFF);
+		break;
+        case 8:
+                printf("%lld", (long long) np->u.i);
+                break;
+	default:
+		abort();
+	}
+}
+
+static void
+emittree(Node *np)
+{
+	if (!np)
+		return;
+
+	switch (np->op) {
+	case OSTRING:
+		printf("\"%s\"", np->u.s);
+		free(np->u.s);
+		np->u.s = NULL;
+		break;
+	case OCONST:
+		emitconst(np);
+		break;
+	case OADDR:
+		emittree(np->left);
+		break;
+	case OMEM:
+		fputs(symname(np->u.sym), stdout);
+		break;
+	default:
+		emittree(np->left);
+		printf(" %c ", np->op);
+		emittree(np->right);
+		break;
+	}
+}
+
+static char *
+size2asm(Type *tp)
+{
+	if (tp->flags & STRF) {
+		return "b";
+	} else if (tp->flags & INTF) {
+		switch (tp->size) {
+		case 1:
+			return "b";
+		case 2:
+			return "h";
+		case 4:
+			return "w";
+		case 8:
+			return "l";
+		}
+	} else if (tp->flags & FLOATF) {
+		if (tp->size == 4)
+			return "s";
+		else if (tp->size == 8)
+			return "d";
+	}
+	abort();
+}
+
+void
+defglobal(Symbol *sym)
+{
+	if (sym->kind == SEXTRN)
+		return;
+	if (sym->kind == SGLOB)
+		fputs("export ", stdout);
+	printf("data %s = {\n", symname(sym));
+	if (sym->type.flags & INITF)
+		return;
+	printf("\tz\t%lu\n}\n", sym->type.size);
+}
+
+void
+defpar(Symbol *sym)
+{
+	sym->type.flags |= PARF;
+}
+
+void
+defvar(Symbol *sym)
+{
+	if (sym->kind == SREG)
+		sym->kind = SAUTO;
+}
+
+void
+data(Node *np)
+{
+	printf("\t%s\t", size2asm(&np->type));
+	emittree(np);
+	putchar(',');
+	putchar('\n');
+}
+
+static char *
+size2stack(Type *tp)
+{
+	if (tp->flags & INTF) {
+		switch (tp->size) {
+		case 1:
+		case 2:
+		case 4:
+			return "w";
+		case 8:
+			return "l";
+		}
+	} else if (tp->flags & FLOATF) {
+		if (tp->size == 4)
+			return "s";
+		else if (tp->size == 8)
+			return "d";
+	} else if (tp->size == 0) {
+		return "w";
+	}
+	abort();
+}
+
+void
+writeout(void)
+{
+	Symbol *p;
+	Type *tp;
+	char *sep, *name;
+	int haslabel = 0;
+
+	if (!curfun)
+		return;
+	if (curfun->kind == SGLOB)
+		fputs("export ", stdout);
+	printf("function %s %s(", size2stack(&curfun->rtype), symname(curfun));
+
+	/* declare formal parameters */
+	for (sep = "", p = locals; p; p = p->next, sep = ",") {
+		if ((p->type.flags & PARF) == 0)
+			break;
+		printf("%s%s %s.val", sep, size2stack(&p->type), symname(p));
+	}
+	printf("%s)\n{\n", (curfun->type.flags&ELLIPS) ? ", ..." : "");
+
+	/* emit assembler instructions */
+	for (pc = prog; pc; pc = pc->next) {
+		if (pc->label) {
+			haslabel = 1;
+			printf("%s\n", symname(pc->label));
+		}
+		if (!pc->op)
+			continue;
+		if (pc->flags&BBENTRY && !haslabel)
+			printf("%s\n", symname(newlabel()));
+		(*optbl[pc->op].fun)();
+		if (!pc->label)
+			haslabel = 0;
+	}
+
+	puts("}");
+}
+
+static char *
+addr2txt(Addr *a)
+{
+	switch (a->kind) {
+	case SCONST:
+		sprintf(buff, "%llu", (unsigned long long) a->u.i);
+		return buff;
+	case SAUTO:
+	case SLABEL:
+	case STMP:
+	case SGLOB:
+	case SEXTRN:
+	case SPRIV:
+	case SLOCAL:
+		return symname(a->u.sym);
+	default:
+		abort();
+	}
+}
+
+static void
+binary(void)
+{
+	struct opdata *p = &optbl[pc->op];
+	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%s =%c\t%s\t%s,%s\n", to, p->letter, p->txt, from1, from2);
+}
+
+static void
+ldir(void)
+{
+	struct opdata *p = &optbl[pc->op];
+	char to[ADDR_LEN], from[ADDR_LEN];
+	/* TODO: what type do we use for the size? */
+
+	/* TODO: it is pending */
+}
+
+static void
+store(void)
+{
+	struct opdata *p = &optbl[pc->op];
+	char to[ADDR_LEN], from[ADDR_LEN];
+
+	strcpy(to, addr2txt(&pc->to));
+	strcpy(from, addr2txt(&pc->from1));
+	printf("\t\t%s%c\t%s,%s\n", p->txt, p->letter, from, to);
+}
+
+static void
+unary(void)
+{
+	struct opdata *p = &optbl[pc->op];
+	char to[ADDR_LEN], from[ADDR_LEN];
+
+	strcpy(to, addr2txt(&pc->to));
+	strcpy(from, addr2txt(&pc->from1));
+	printf("\t%s =%c\t%s\t%s\n", to, p->letter, p->txt, from);
+}
+
+static void
+call(void)
+{
+	struct opdata *p = &optbl[pc->op];
+	char to[ADDR_LEN], from[ADDR_LEN];
+	Symbol *sym = pc->to.u.sym;
+
+	strcpy(to, addr2txt(&pc->to));
+	strcpy(from, addr2txt(&pc->from1));
+	printf("\t%s =%s\tcall\t%s(",
+	       to, size2stack(&sym->type), from);
+}
+
+static void
+param(void)
+{
+	Symbol *sym = pc->from2.u.sym;
+
+	printf(optbl[pc->op].txt,
+	       size2stack(&sym->type), addr2txt(&pc->from1));
+}
+
+static void
+ecall(void)
+{
+	struct opdata *p = &optbl[pc->op];
+
+	puts(p->txt);
+}
+
+static void
+ret(void)
+{
+	if (pc->from1.kind == SNONE)
+		puts("\t\tret");
+	else
+		printf("\t\tret\t%s\n", addr2txt(&pc->from1));
+}
+
+static void
+jmp(void)
+{
+	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);
+}
+
+static void
+vastart(void)
+{
+	printf("\t\tvastart %s\n", addr2txt(&pc->from1));
+}
+
+static void
+vaarg(void)
+{
+	Symbol *sym = pc->to.u.sym;
+	Type *tp = &sym->type;
+	char to[ADDR_LEN], from[ADDR_LEN];
+
+	strcpy(to, addr2txt(&pc->to));
+	strcpy(from, addr2txt(&pc->from1));
+	printf("\t\t%s =%s vaarg %s\n", to, size2asm(tp), from);
+}
+
+static void
+alloc(void)
+{
+	Symbol *sym = pc->to.u.sym;
+	Type *tp = &sym->type;
+	extern Type ptrtype;
+
+	printf("\t%s =%s\talloc%lu\t%lu\n",
+	       symname(sym), size2asm(&ptrtype), tp->align+3 & ~3, tp->size);
+}
+
+static void
+form2local(void)
+{
+	Symbol *sym = pc->to.u.sym;
+	Type *tp = &sym->type;
+	char *name = symname(sym);
+
+	printf("\t\tstore%s\t%s.val,%s\n", size2asm(tp), name, name);
+}
+
+void
+endinit(void)
+{
+	puts("}");
+}
+
+void
+getbblocks(void)
+{
+	Inst *i;
+
+	if (!prog)
+		return;
+
+	prog->flags |= BBENTRY;
+	for (pc = prog; pc; pc = pc->next) {
+		switch (pc->op) {
+		case ASBRANCH:
+			i = pc->from2.u.sym->u.inst;
+			i->flags |= BBENTRY;
+		case ASJMP:
+			i = pc->from1.u.sym->u.inst;
+			i->flags |= BBENTRY;
+		case ASRET:
+			if (pc->next)
+				pc->next->flags |= BBENTRY;
+			break;
+		}
+	}
+}
--- /dev/null
+++ b/cc2/target/qbe/optm.c
@@ -1,0 +1,58 @@
+/* See LICENSE file for copyright and license details. */
+static char sccsid[] = "@(#) ./cc2/arch/qbe/optm.c";
+
+#include <stddef.h>
+
+#include "../../../inc/scc.h"
+#include "../../cc2.h"
+
+Node *
+optm_dep(Node *np)
+{
+	int op = np->op;
+	Node *p, *dst, *next = np->next;
+	Symbol *sym, *osym;
+
+	switch (op) {
+	case OEFUN:
+		/*
+		 * 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
+		 */
+		op = (np->prev) ? np->prev->op : 0;
+		if (!op || op == ONOP || op == OBRANCH || (op != ORET && op != OJMP))
+			addstmt(newnode(ORET), KEEPCUR);
+		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;
+}
--- a/cc2/target/qbe_amd64-sysv/arch.h
+++ /dev/null
@@ -1,137 +1,0 @@
-/* See LICENSE file for copyright and license details. */
-
-enum asmop {
-	ASNOP = 0,
-	ASSTB,
-	ASSTH,
-	ASSTW,
-	ASSTL,
-	ASSTM,
-	ASSTS,
-	ASSTD,
-
-	ASLDSB,
-	ASLDUB,
-	ASLDSH,
-	ASLDUH,
-	ASLDSW,
-	ASLDUW,
-	ASLDL,
-	ASLDS,
-	ASLDD,
-
-	ASADDW,
-	ASSUBW,
-	ASMULW,
-	ASMODW,
-	ASUMODW,
-	ASDIVW,
-	ASUDIVW,
-	ASSHLW,
-	ASSHRW,
-	ASUSHRW,
-	ASLTW,
-	ASULTW,
-	ASGTW,
-	ASUGTW,
-	ASLEW,
-	ASULEW,
-	ASGEW,
-	ASUGEW,
-	ASEQW,
-	ASNEW,
-	ASBANDW,
-	ASBORW,
-	ASBXORW,
-
-	ASADDL,
-	ASSUBL,
-	ASMULL,
-	ASMODL,
-	ASUMODL,
-	ASDIVL,
-	ASUDIVL,
-	ASSHLL,
-	ASSHRL,
-	ASUSHRL,
-	ASLTL,
-	ASULTL,
-	ASGTL,
-	ASUGTL,
-	ASLEL,
-	ASULEL,
-	ASGEL,
-	ASUGEL,
-	ASEQL,
-	ASNEL,
-	ASBANDL,
-	ASBORL,
-	ASBXORL,
-
-	ASADDS,
-	ASSUBS,
-	ASMULS,
-	ASDIVS,
-	ASLTS,
-	ASGTS,
-	ASLES,
-	ASGES,
-	ASEQS,
-	ASNES,
-
-	ASADDD,
-	ASSUBD,
-	ASMULD,
-	ASDIVD,
-	ASLTD,
-	ASGTD,
-	ASLED,
-	ASGED,
-	ASEQD,
-	ASNED,
-
-	ASEXTBW,
-	ASUEXTBW,
-	ASEXTBL,
-	ASUEXTBL,
-	ASEXTHW,
-	ASUEXTHW,
-	ASEXTHL,
-	ASUEXTHL,
-	ASEXTWL,
-	ASUEXTWL,
-
-	ASSTOL,
-	ASSTOW,
-	ASDTOL,
-	ASDTOW,
-
-	ASSWTOD,
-	ASSWTOS,
-	ASSLTOD,
-	ASSLTOS,
-
-	ASEXTS,
-	ASTRUNCD,
-
-	ASJMP,
-	ASBRANCH,
-	ASRET,
-	ASCALL,
-	ASCALLE,
-	ASCALLEX,
-	ASPAR,
-	ASPARE,
-	ASALLOC,
-	ASFORM,
-
-	ASCOPYB,
-	ASCOPYH,
-	ASCOPYW,
-	ASCOPYL,
-	ASCOPYS,
-	ASCOPYD,
-
-	ASVSTAR,
-	ASVARG,
-};
--- a/cc2/target/qbe_amd64-sysv/cgen.c
+++ /dev/null
@@ -1,731 +1,0 @@
-/* See LICENSE file for copyright and license details. */
-static char sccsid[] = "@(#) ./cc2/arch/qbe/cgen.c";
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include <cstd.h>
-#include "arch.h"
-#include "../../../inc/scc.h"
-#include "../../cc2.h"
-
-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,
-};
-
-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,
-};
-
-static char opasms[] = {
-	[OADD] = ASADDS,
-	[OSUB] = ASSUBS,
-	[OMUL] = ASMULS,
-	[ODIV] = ASDIVS,
-	[OLT] = ASLTS,
-	[OGT] = ASGTS,
-	[OLE] = ASLES,
-	[OGE] = ASGES,
-	[OEQ] = ASEQS,
-	[ONE] = ASNES,
-};
-static char opasmd[] = {
-	[OADD] = ASADDD,
-	[OSUB] = ASSUBD,
-	[OMUL] = ASMULD,
-	[ODIV] = ASDIVD,
-	[OLT] = ASLTD,
-	[OGT] = ASGTD,
-	[OLE] = ASLED,
-	[OGE] = ASGED,
-	[OEQ] = ASEQD,
-	[ONE] = ASNED,
-};
-
-extern Type int32type, uint32type, ptrtype;
-
-static Node *
-tmpnode(Node *np, Type *tp)
-{
-	char flags;
-	Symbol *sym;
-
-	if (!np)
-		np = newnode(OTMP);
-	sym = getsym(TMPSYM);
-	sym->type = np->type = *tp;
-	flags = tp->flags & ~(PARF|INITF);
-	sym->type.flags = np->type.flags = flags;
-	sym->kind = STMP;
-	np->left = np->right = NULL;
-	np->u.sym = sym;
-	np->op = OTMP;
-	np->flags |= ISTMP;
-	return np;
-}
-
-static Node *
-load(Type *tp, Node *np, Node *new)
-{
-	int op;
-	int flags = tp->flags;
-
-	if (flags & (AGGRF|FUNF)) {
-		*new = *np;
-		return new;
-	}
-	switch (tp->size) {
-	case 1:
-		op = ASLDSB;
-		break;
-	case 2:
-		op = ASLDSH;
-		break;
-	case 4:
-		op = (flags & FLOATF) ? ASLDS : ASLDSW;
-		break;
-	case 8:
-		op = (flags & FLOATF) ? ASLDD : ASLDL;
-		break;
-	default:
-		abort();
-	}
-	/*
-	 * unsigned version of operations are always +1 the
-	 * signed version
-	 */
-	if ((flags & (INTF|SIGNF)) == INTF && tp->size < 8)
-		++op;
-
-	code(op, tmpnode(new, tp), np, NULL);
-
-	return new;
-}
-
-static Node *rhs(Node *np, Node *new);
-
-static Node *
-cast(Type *td, Node *ns, Node *nd)
-{
-	Type *ts;
-	Node aux1, aux2;
-	int op, d_isint, s_isint;
-
-	ts = &ns->type;
-	d_isint = (td->flags & INTF) != 0;
-	s_isint = (ts->flags & INTF) != 0;
-
-	if (d_isint && s_isint) {
-		if (td->size <= ts->size) {
-			*nd = *ns;
-			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 += (ts->flags & SIGNF) == 0;
-	} else if (d_isint) {
-		/* 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 (s_isint) {
-		/* conversion from int to float */
-		switch (ts->size) {
-		case 1:
-		case 2:
-			ts = (ts->flags&SIGNF) ? &int32type : &uint32type;
-			ns = cast(ts, ns, tmpnode(&aux2, ts));
-		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, td), ns, NULL);
-	return nd;
-}
-
-static Node *rhs(Node *np, Node *new);
-
-static Node *
-call(Node *np, Node *fun, Node *ret)
-{
-	int n, op;
-	Type *tp;
-	Node aux, **q, *p, *pars[NR_FUNPARAM];
-
-	for (n = 0, p = np->right; p; p = p->right)
-		pars[n++] = rhs(p->left, newnode(OTMP));
-
-	tp = &np->type;
-	code(ASCALL, tmpnode(ret, tp), fun, NULL);
-
-	for (q = pars; q < &pars[n]; ++q) {
-		op = (q == &pars[n-1]) ? ASPARE : ASPAR;
-		tmpnode(&aux, &(*q)->type);
-		code(op, NULL, *q, &aux);
-	}
-	code((np->op == OCALL) ? ASCALLE : ASCALLEX, NULL, NULL, NULL);
-
-	return ret;
-}
-
-static Node *
-assign(Type *tp, Node *to, Node *from)
-{
-	int op;
-
-	switch (tp->size) {
-	case 1:
-		op = ASSTB;
-		break;
-	case 2:
-		op = ASSTH;
-		break;
-	case 4:
-		op = (tp->flags & FLOATF) ? ASSTS : ASSTW;
-		break;
-	case 8:
-		op = (tp->flags & FLOATF) ? ASSTD : ASSTL;
-		break;
-	default:
-		op = ASSTM;
-		break;
-	}
-	code(op, to, from, NULL);
-	return from;
-}
-
-static Node *
-copy(Type *tp, Node *to, Node *from)
-{
-	int op;
-
-	switch (tp->size) {
-	case 1:
-		op = ASCOPYB;
-		break;
-	case 2:
-		op = ASCOPYH;
-		break;
-	case 4:
-		op = (tp->flags & FLOATF) ? ASCOPYS : ASCOPYW;
-		break;
-	case 8:
-		op = (tp->flags & FLOATF) ? ASCOPYD : ASCOPYL;
-		break;
-	default:
-		/* TODO: Need to handle the general case */
-		abort();
-	}
-	code(op, to, from, NULL);
-	return from;
-}
-
-/* TODO: Do field() transformation in sethi */
-
-static Node *
-field(Node *np, Node *ret, int islhs)
-{
-	Node base, node, off, add, *addr;
-	TUINT offset = np->right->u.sym->u.off;
-
-	addr = rhs(np->left, &base);
-
-	if (offset != 0) {
-		node.op = OADD;
-		node.type = ptrtype;
-		node.left = addr;
-		node.right = constnode(&off, offset, &ptrtype);
-		addr = rhs(&node, &add);
-	}
-
-	if (islhs)
-		*ret = *addr;
-	else
-		load(&np->type, addr, ret);
-
-	return ret;
-}
-
-static Node *
-lhs(Node *np, Node *new)
-{
-	switch (np->op) {
-	case OMEM:
-	case OAUTO:
-		*new = *np;
-		return new;
-	case OPTR:
-		return rhs(np->left, new);
-	case OFIELD:
-		return field(np, new, 1);
-	default:
-		abort();
-	}
-}
-
-static void
-bool(Node *np, Symbol *true, Symbol *false)
-{
-	Node *l = np->left, *r = np->right;
-	Node ret, ifyes, ifno;
-	Symbol *label;
-
-	switch (np->op) {
-	case ONEG:
-		bool(l, false, true);
-		break;
-	case OAND:
-		label = newlabel();
-		bool(l, label, false);
-		setlabel(label);
-		bool(r, true, false);
-		break;
-	case OOR:
-		label = newlabel();
-		bool(l, true, label);
-		setlabel(label);
-		bool(r, true, false);
-		break;
-	default:
-		label2node(&ifyes, true);
-		label2node(&ifno, false);
-		code(ASBRANCH, rhs(np, &ret), &ifyes, &ifno);
-		break;
-	}
-}
-
-static Node *
-ternary(Node *np, Node *ret)
-{
-	Node ifyes, ifno, phi, *colon, aux1, aux2, aux3;
-
-	tmpnode(ret, &np->type);
-	label2node(&ifyes, NULL);
-	label2node(&ifno, NULL);
-	label2node(&phi, NULL);
-
-	colon = np->right;
-	code(ASBRANCH, rhs(np->left, &aux1), &ifyes, &ifno);
-
-	setlabel(ifyes.u.sym);
-	copy(&ret->type, ret, rhs(colon->left, &aux2));
-	code(ASJMP, NULL, &phi, NULL);
-
-	setlabel(ifno.u.sym);
-	copy(&ret->type, ret, rhs(colon->right, &aux3));
-	setlabel(phi.u.sym);
-
-	return ret;
-}
-
-static Node *
-function(void)
-{
-	Node aux;
-	Symbol *p;
-
-	/* allocate stack space for parameters */
-	for (p = locals; p && (p->type.flags & PARF) != 0; p = p->next)
-		code(ASALLOC, label2node(&aux, 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(&aux, 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(&aux, p), NULL, NULL);
-	}
-	return NULL;
-}
-
-static void
-swtch_if(Node *idx)
-{
-	Node aux1, aux2, *np;
-	Symbol *deflabel = NULL;
-
-	for (;;) {
-		np = delstmt();
-		setlabel(np->label);
-
-		switch (np->op) {
-		case OESWITCH:
-			if (!deflabel)
-				deflabel = np->u.sym;
-			aux1.op = OJMP;
-			aux1.label = NULL;
-			aux1.u.sym = deflabel;
-			cgen(&aux1);
-			return;
-		case OCASE:
-			aux1 = *np;
-			aux1.op = OBRANCH;
-			aux1.label = NULL;
-			aux1.left = &aux2;
-
-			aux2.op = OEQ;
-			aux2.type = idx->type;
-			aux2.left = np->left;
-			aux2.right = idx;
-
-			cgen(&aux1);
-			break;
-		case ODEFAULT:
-			deflabel = np->u.sym;
-			break;
-		default:
-			abort();
-		}
-	}
-}
-
-static Node *
-rhs(Node *np, Node *ret)
-{
-	Node aux1, aux2, *phi, *l = np->left, *r = np->right;
-	Type *tp;
-	int off, op;
-	char *tbl;
-	Symbol *true, *false;
-
-	tp = &np->type;
-
-	switch (np->op) {
-	case OBFUN:
-		return function();
-	case ONOP:
-	case OBLOOP:
-	case OELOOP:
-	case OEFUN:
-		return NULL;
-	case OTMP:
-	case OCONST:
-		*ret = *np;
-		return np;
-	case OMEM:
-	case OAUTO:
-		return load(tp, np, ret);
-	case ONEG:
-	case OAND:
-	case OOR:
-		true = newlabel();
-		false = newlabel();
-		phi = label2node(&aux1, NULL);
-		tmpnode(ret, &int32type);
-
-		bool(np, true, false);
-
-		setlabel(true);
-		code(ASCOPYW, ret, constnode(&aux2, 1, &int32type), NULL);
-		code(ASJMP, NULL, phi, NULL);
-
-		setlabel(false);
-		code(ASCOPYW, ret, constnode(&aux2, 0, &int32type), NULL);
-
-		setlabel(phi->u.sym);
-		return ret;
-        case OMOD:
-        case OSHR:
-		assert(tp->flags & INTF);
-        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 OSHL:
-        case OBAND:
-        case OBOR:
-        case OBXOR:
-		assert(tp->flags & INTF);
-        case OADD:
-        case OSUB:
-        case OMUL:
-        case OEQ:
-        case ONE:
-                off = 0;
-        binary:
-		if (l->complex >= r->complex) {
-			rhs(l, &aux1);
-			rhs(r, &aux2);
-		} else {
-			rhs(r, &aux2);
-			rhs(l, &aux1);
-		}
-                switch (tp->size) {
-                case 4:
-                        tbl = (tp->flags & FLOATF) ? opasms : opasmw;
-                        break;
-                case 8:
-                        tbl = (tp->flags & FLOATF) ? opasmd : opasml;
-                        break;
-                default:
-                        abort();
-                }
-                op = tbl[np->op] + off;
-		tmpnode(ret, tp);
-                code(op, ret, &aux1, &aux2);
-                return ret;
-	case OCALL:
-	case OCALLE:
-		if (l->op == OPTR)
-			l = rhs(l, &aux1);
-		return call(np, l, ret);
-	case OCAST:
-		return cast(tp, rhs(l, &aux1), ret);
-	case OASSIG:
-		/* TODO: Do this transformations in sethi */
-		switch (np->u.subop) {
-		case OINC:
-			op = OADD;
-			goto post_oper;
-		case ODEC:
-			op = OSUB;
-		post_oper:
-			aux1.op = op;
-			aux1.left = rhs(l, ret);
-			aux1.right = r;
-			aux1.type = np->type;
-			rhs(&aux1, &aux2);
-			lhs(l, &aux1);
-			assign(tp, &aux1, &aux2);
-			break;
-		default:
-			aux2.type = np->type;
-			aux2.op = np->u.subop;
-			aux2.right = np->right;
-			aux2.left = np->left;
-			r = rhs(&aux2, &aux1);
-			Node aux3;
-			if (l->op == OCAST) {
-				aux3.type = l->left->type;
-				aux3.op = OCAST;
-				aux3.left = r;
-				aux3.right = NULL;
-				r = &aux3;
-				l = l->left;
-			}
-		case 0:
-			/* TODO: see what is the most difficult */
-			lhs(l, &aux2);
-			rhs(r, ret);
-			return assign(tp, &aux2, ret);
-		}
-		return ret;
-	case OASK:
-		return ternary(np, ret);
-	case OCOMMA:
-		rhs(l, &aux1);
-		return rhs(r, ret);
-	case OPTR:
-		return load(tp, rhs(l, &aux1), ret);
-	case OADDR:
-		lhs(l, ret);
-		ret->type = *tp;
-		return ret;
-	case OFIELD:
-		return field(np, ret, 0);
-	case OBUILTIN:
-		switch (np->u.subop) {
-		case BVA_START:
-			l = rhs(l, &aux1);
-			code(ASVSTAR, NULL, l, NULL);
-			return NULL;
-		case BVA_END:
-			return NULL;
-		case BVA_ARG:
-			l = rhs(l, &aux1);
-			code(ASVARG, tmpnode(ret, tp), l, NULL);
-			return ret;
-		case BVA_COPY:
-			/* TODO */
-		default:
-			abort();
-		}
-	default:
-		abort();
-	}
-	abort();
-}
-
-Node *
-cgen(Node *np)
-{
-	Node aux, *p, *next;
-
-	setlabel(np->label);
-	switch (np->op) {
-	case OJMP:
-		label2node(&aux, np->u.sym);
-		code(ASJMP, NULL, &aux, NULL);
-		break;
-	case OBRANCH:
-		next = np->next;
-		if (!next->label)
-			next->label = newlabel();
-		bool(np->left, np->u.sym, next->label);
-		break;
-	case ORET:
-		p = (np->left) ? rhs(np->left, &aux) : NULL;
-		code(ASRET, NULL, p, NULL);
-		break;
-	case OBSWITCH:
-		p = rhs(np->left, &aux);
-		swtch_if(p);
-		break;
-	default:
-		rhs(np, &aux);
-		break;
-	}
-	return NULL;
-}
-
-/*
- * 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 there, 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;
-	case OCPL:
-		assert(np->type.flags & INTF);
-		np->op = OBXOR;
-		rp = constnode(NULL, ~(TUINT) 0, &np->type);
-		goto binary;
-	case OSNEG:
-		np->op = OSUB;
-		rp = lp;
-		lp = constnode(NULL, 0, &np->type);
-		if ((np->type.flags & INTF) == 0)
-			lp->u.f = 0.0;
-	default:
-	binary:
-		lp = sethi(lp);
-		rp = sethi(rp);
-		break;
-	}
-	np->left = lp;
-	np->right = rp;
-
-	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;
-}
--- a/cc2/target/qbe_amd64-sysv/code.c
+++ /dev/null
@@ -1,569 +1,0 @@
-/* See LICENSE file for copyright and license details. */
-static char sccsid[] = "@(#) ./cc2/arch/qbe/code.c";
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cstd.h>
-#include "arch.h"
-#include "../../../inc/scc.h"
-#include "../../cc2.h"
-
-#define ADDR_LEN (INTIDENTSIZ+64)
-
-static void binary(void), unary(void), store(void), jmp(void), ret(void),
-            branch(void), call(void), ecall(void), param(void),
-            alloc(void), form2local(void), ldir(void), vastart(void),
-            vaarg(void);
-
-static struct opdata {
-	void (*fun)(void);
-	char *txt;
-	char letter;
-} optbl [] = {
-	[ASLDSB]  =  {.fun = unary,  .txt = "loadsb", .letter = 'w'},
-	[ASLDUB]  =  {.fun = unary,  .txt = "loadub", .letter = 'w'},
-	[ASLDSH]  =  {.fun = unary,  .txt = "loadsh", .letter = 'w'},
-	[ASLDUH]  =  {.fun = unary,  .txt = "loaduh", .letter = 'w'},
-	[ASLDSW]  =  {.fun = unary,  .txt = "loadsw", .letter = 'w'},
-	[ASLDUW]  =  {.fun = unary,  .txt = "loaduw", .letter = 'w'},
-	[ASLDL]   =  {.fun = unary,  .txt = "loadl", .letter = 'l'},
-	[ASLDS]   =  {.fun = unary,  .txt = "loads", .letter = 's'},
-	[ASLDD]   =  {.fun = unary,  .txt = "loadd", .letter = 'd'},
-
-	[ASCOPYB] =  {.fun = unary,  .txt = "copy", .letter = 'b'},
-	[ASCOPYH] =  {.fun = unary,  .txt = "copy", .letter = 'h'},
-	[ASCOPYW] =  {.fun = unary,  .txt = "copy", .letter = 'w'},
-	[ASCOPYL] =  {.fun = unary,  .txt = "copy", .letter = 'l'},
-	[ASCOPYS] =  {.fun = unary,  .txt = "copy", .letter = 's'},
-	[ASCOPYD] =  {.fun = unary,  .txt = "copy", .letter = 'd'},
-
-	[ASSTB]   =  {.fun = store,  .txt = "store", .letter = 'b'},
-	[ASSTH]   =  {.fun = store,  .txt = "store", .letter = 'h'},
-	[ASSTW]   =  {.fun = store,  .txt = "store", .letter = 'w'},
-	[ASSTL]   =  {.fun = store,  .txt = "store", .letter = 'l'},
-	[ASSTM]   =  {.fun = ldir},
-	[ASSTS]   =  {.fun = store,  .txt = "store", .letter = 's'},
-	[ASSTD]   =  {.fun = store,  .txt = "store", .letter = 'd'},
-
-	[ASADDW]  =  {.fun = binary, .txt = "add", .letter = 'w'},
-	[ASSUBW]  =  {.fun = binary, .txt = "sub", .letter = 'w'},
-	[ASMULW]  =  {.fun = binary, .txt = "mul", .letter = 'w'},
-	[ASMODW]  =  {.fun = binary, .txt = "rem", .letter = 'w'},
-	[ASUMODW] =  {.fun = binary, .txt = "urem", .letter = 'w'},
-	[ASDIVW]  =  {.fun = binary, .txt = "div", .letter = 'w'},
-	[ASUDIVW] =  {.fun = binary, .txt = "udiv", .letter = 'w'},
-	[ASSHLW]  =  {.fun = binary, .txt = "shl", .letter = 'w'},
-	[ASSHRW]  =  {.fun = binary, .txt = "sar", .letter = 'w'},
-	[ASUSHRW] =  {.fun = binary, .txt = "shr", .letter = 'w'},
-	[ASLTW]   =  {.fun = binary, .txt = "csltw", .letter = 'w'},
-	[ASULTW]  =  {.fun = binary, .txt = "cultw", .letter = 'w'},
-	[ASGTW]   =  {.fun = binary, .txt = "csgtw", .letter = 'w'},
-	[ASUGTW]  =  {.fun = binary, .txt = "cugtw", .letter = 'w'},
-	[ASLEW]   =  {.fun = binary, .txt = "cslew", .letter = 'w'},
-	[ASULEW]  =  {.fun = binary, .txt = "culew", .letter = 'w'},
-	[ASGEW]   =  {.fun = binary, .txt = "csgew", .letter = 'w'},
-	[ASUGEW]  =  {.fun = binary, .txt = "cugew", .letter = 'w'},
-	[ASEQW]   =  {.fun = binary, .txt = "ceqw", .letter = 'w'},
-	[ASNEW]   =  {.fun = binary, .txt = "cnew", .letter = 'w'},
-	[ASBANDW] =  {.fun = binary, .txt = "and", .letter = 'w'},
-	[ASBORW]  =  {.fun = binary, .txt = "or", .letter = 'w'},
-	[ASBXORW] =  {.fun = binary, .txt = "xor", .letter = 'w'},
-
-	[ASADDL]  =  {.fun = binary, .txt = "add", .letter = 'l'},
-	[ASSUBL]  =  {.fun = binary, .txt = "sub", .letter = 'l'},
-	[ASMULL]  =  {.fun = binary, .txt = "mul", .letter = 'l'},
-	[ASMODL]  =  {.fun = binary, .txt = "rem", .letter = 'l'},
-	[ASUMODL] =  {.fun = binary, .txt = "urem", .letter = 'l'},
-	[ASDIVL]  =  {.fun = binary, .txt = "div", .letter = 'l'},
-	[ASUDIVL] =  {.fun = binary, .txt = "udiv", .letter = 'l'},
-	[ASSHLL]  =  {.fun = binary, .txt = "shl", .letter = 'l'},
-	[ASSHRL]  =  {.fun = binary, .txt = "sar", .letter = 'l'},
-	[ASUSHRL] =  {.fun = binary, .txt = "shr", .letter = 'l'},
-	[ASLTL]   =  {.fun = binary, .txt = "csltl", .letter = 'w'},
-	[ASULTL]  =  {.fun = binary, .txt = "cultl", .letter = 'w'},
-	[ASGTL]   =  {.fun = binary, .txt = "csgtl", .letter = 'w'},
-	[ASUGTL]  =  {.fun = binary, .txt = "cugtl", .letter = 'w'},
-	[ASLEL]   =  {.fun = binary, .txt = "cslel", .letter = 'w'},
-	[ASULEL]  =  {.fun = binary, .txt = "culel", .letter = 'w'},
-	[ASGEL]   =  {.fun = binary, .txt = "csgel", .letter = 'w'},
-	[ASUGEL]  =  {.fun = binary, .txt = "cugel", .letter = 'w'},
-	[ASEQL]   =  {.fun = binary, .txt = "ceql", .letter = 'w'},
-	[ASNEL]   =  {.fun = binary, .txt = "cnel", .letter = 'w'},
-	[ASBANDL] =  {.fun = binary, .txt = "and", .letter = 'l'},
-	[ASBORL]  =  {.fun = binary, .txt = "or", .letter = 'l'},
-	[ASBXORL] =  {.fun = binary, .txt = "xor", .letter = 'l'},
-
-	[ASADDS]  =  {.fun = binary, .txt = "add", .letter = 's'},
-	[ASSUBS]  =  {.fun = binary, .txt = "sub", .letter = 's'},
-	[ASMULS]  =  {.fun = binary, .txt = "mul", .letter = 's'},
-	[ASDIVS]  =  {.fun = binary, .txt = "div", .letter = 's'},
-	[ASLTS]   =  {.fun = binary, .txt = "clts", .letter = 'w'},
-	[ASGTS]   =  {.fun = binary, .txt = "cgts", .letter = 'w'},
-	[ASLES]   =  {.fun = binary, .txt = "cles", .letter = 'w'},
-	[ASGES]   =  {.fun = binary, .txt = "cges", .letter = 'w'},
-	[ASEQS]   =  {.fun = binary, .txt = "ceqs", .letter = 'w'},
-	[ASNES]   =  {.fun = binary, .txt = "cnes", .letter = 'w'},
-
-	[ASADDD]  =  {.fun = binary, .txt = "add", .letter = 'd'},
-	[ASSUBD]  =  {.fun = binary, .txt = "sub", .letter = 'd'},
-	[ASMULD]  =  {.fun = binary, .txt = "mul", .letter = 'd'},
-	[ASDIVD]  =  {.fun = binary, .txt = "div", .letter = 'd'},
-	[ASLTD]   =  {.fun = binary, .txt = "cltd", .letter = 'w'},
-	[ASGTD]   =  {.fun = binary, .txt = "cgtd", .letter = 'w'},
-	[ASLED]   =  {.fun = binary, .txt = "cled", .letter = 'w'},
-	[ASGED]   =  {.fun = binary, .txt = "cged", .letter = 'w'},
-	[ASEQD]   =  {.fun = binary, .txt = "ceqd", .letter = 'w'},
-	[ASNED]   =  {.fun = binary, .txt = "cned", .letter = 'w'},
-
-	[ASEXTBW] =  {.fun = unary, .txt = "extsb", .letter = 'w'},
-	[ASUEXTBW]=  {.fun = unary, .txt = "extub", .letter = 'w'},
-	[ASEXTBL] =  {.fun = unary, .txt = "extsb", .letter = 'l'},
-	[ASUEXTBL]=  {.fun = unary, .txt = "extub", .letter = 'l'},
-	[ASEXTHW] =  {.fun = unary, .txt = "extsh", .letter = 'w'},
-	[ASUEXTHW]=  {.fun = unary, .txt = "extuh", .letter = 'w'},
-	[ASEXTWL] =  {.fun = unary, .txt = "extsw", .letter = 'l'},
-	[ASUEXTWL]=  {.fun = unary, .txt = "extuw", .letter = 'l'},
-
-	[ASSTOL] = {.fun = unary, .txt = "stosi", .letter = 'l'},
-	[ASSTOW] = {.fun = unary, .txt = "stosi", .letter = 'w'},
-	[ASDTOL] = {.fun = unary, .txt = "dtosi", .letter = 'l'},
-	[ASDTOW] = {.fun = unary, .txt = "dtosi", .letter = 'w'},
-
-	[ASSWTOD] = {.fun = unary, .txt = "swtof", .letter = 'd'},
-	[ASSWTOS] = {.fun = unary, .txt = "swtof", .letter = 's'},
-	[ASSLTOD] = {.fun = unary, .txt = "sltof", .letter = 'd'},
-	[ASSLTOS] = {.fun = unary, .txt = "sltof", .letter = 's'},
-
-	[ASEXTS] = {.fun = unary, .txt = "exts", .letter = 'd'},
-	[ASTRUNCD] = {.fun = unary, .txt = "truncd", .letter = 's'},
-
-	[ASBRANCH] = {.fun = branch},
-	[ASJMP]  = {.fun = jmp},
-	[ASRET]  = {.fun = ret},
-	[ASCALL] = {.fun = call},
-	[ASCALLE] = {.fun = ecall, .txt = ")"},
-	[ASCALLEX] = {.fun = ecall, .txt = ", ...)"},
-	[ASPAR] = {.fun = param, .txt = "%s %s, "},
-	[ASPARE] = {.fun = param, .txt = "%s %s"},
-	[ASALLOC] = {.fun = alloc},
-	[ASFORM] = {.fun = form2local},
-
-	[ASVSTAR] = {.fun = vastart},
-	[ASVARG] = {.fun = vaarg},
-};
-
-static char buff[ADDR_LEN];
-/*
- * : is for user-defined Aggregate Types
- * $ is for globals (represented by a pointer)
- * % is for function-scope temporaries
- * @ is for block labels
- */
-static char
-sigil(Symbol *sym)
-{
-	switch (sym->kind) {
-	case SEXTRN:
-	case SGLOB:
-	case SPRIV:
-	case SLOCAL:
-		return '$';
-	case SAUTO:
-	case STMP:
-		return '%';
-	case SLABEL:
-		return '@';
-	default:
-		abort();
-	}
-}
-
-static char *
-symname(Symbol *sym)
-{
-	char c = sigil(sym);
-
-	if (sym->name) {
-		switch (sym->kind) {
-		case SEXTRN:
-		case SGLOB:
-			sprintf(buff, "%c%s", c, sym->name);
-			return buff;
-		case SLOCAL:
-		case SPRIV:
-		case SAUTO:
-			sprintf(buff, "%c%s.%u", c, sym->name, sym->id);
-			return buff;
-		default:
-			abort();
-		}
-	}
-	sprintf(buff, "%c.%u", c, sym->numid);
-
-	return buff;
-}
-
-static void
-emitconst(Node *np)
-{
-	switch (np->type.size) {
-	case 1:
-		printf("%d", (int) np->u.i & 0xFF);
-		break;
-	case 2:
-		printf("%d", (int) np->u.i & 0xFFFF);
-		break;
-	case 4:
-		printf("%ld", (long) np->u.i & 0xFFFFFFFF);
-		break;
-        case 8:
-                printf("%lld", (long long) np->u.i);
-                break;
-	default:
-		abort();
-	}
-}
-
-static void
-emittree(Node *np)
-{
-	if (!np)
-		return;
-
-	switch (np->op) {
-	case OSTRING:
-		printf("\"%s\"", np->u.s);
-		free(np->u.s);
-		np->u.s = NULL;
-		break;
-	case OCONST:
-		emitconst(np);
-		break;
-	case OADDR:
-		emittree(np->left);
-		break;
-	case OMEM:
-		fputs(symname(np->u.sym), stdout);
-		break;
-	default:
-		emittree(np->left);
-		printf(" %c ", np->op);
-		emittree(np->right);
-		break;
-	}
-}
-
-static char *
-size2asm(Type *tp)
-{
-	if (tp->flags & STRF) {
-		return "b";
-	} else if (tp->flags & INTF) {
-		switch (tp->size) {
-		case 1:
-			return "b";
-		case 2:
-			return "h";
-		case 4:
-			return "w";
-		case 8:
-			return "l";
-		}
-	} else if (tp->flags & FLOATF) {
-		if (tp->size == 4)
-			return "s";
-		else if (tp->size == 8)
-			return "d";
-	}
-	abort();
-}
-
-void
-defglobal(Symbol *sym)
-{
-	if (sym->kind == SEXTRN)
-		return;
-	if (sym->kind == SGLOB)
-		fputs("export ", stdout);
-	printf("data %s = {\n", symname(sym));
-	if (sym->type.flags & INITF)
-		return;
-	printf("\tz\t%lu\n}\n", sym->type.size);
-}
-
-void
-defpar(Symbol *sym)
-{
-	sym->type.flags |= PARF;
-}
-
-void
-defvar(Symbol *sym)
-{
-	if (sym->kind == SREG)
-		sym->kind = SAUTO;
-}
-
-void
-data(Node *np)
-{
-	printf("\t%s\t", size2asm(&np->type));
-	emittree(np);
-	putchar(',');
-	putchar('\n');
-}
-
-static char *
-size2stack(Type *tp)
-{
-	if (tp->flags & INTF) {
-		switch (tp->size) {
-		case 1:
-		case 2:
-		case 4:
-			return "w";
-		case 8:
-			return "l";
-		}
-	} else if (tp->flags & FLOATF) {
-		if (tp->size == 4)
-			return "s";
-		else if (tp->size == 8)
-			return "d";
-	} else if (tp->size == 0) {
-		return "w";
-	}
-	abort();
-}
-
-void
-writeout(void)
-{
-	Symbol *p;
-	Type *tp;
-	char *sep, *name;
-	int haslabel = 0;
-
-	if (!curfun)
-		return;
-	if (curfun->kind == SGLOB)
-		fputs("export ", stdout);
-	printf("function %s %s(", size2stack(&curfun->rtype), symname(curfun));
-
-	/* declare formal parameters */
-	for (sep = "", p = locals; p; p = p->next, sep = ",") {
-		if ((p->type.flags & PARF) == 0)
-			break;
-		printf("%s%s %s.val", sep, size2stack(&p->type), symname(p));
-	}
-	printf("%s)\n{\n", (curfun->type.flags&ELLIPS) ? ", ..." : "");
-
-	/* emit assembler instructions */
-	for (pc = prog; pc; pc = pc->next) {
-		if (pc->label) {
-			haslabel = 1;
-			printf("%s\n", symname(pc->label));
-		}
-		if (!pc->op)
-			continue;
-		if (pc->flags&BBENTRY && !haslabel)
-			printf("%s\n", symname(newlabel()));
-		(*optbl[pc->op].fun)();
-		if (!pc->label)
-			haslabel = 0;
-	}
-
-	puts("}");
-}
-
-static char *
-addr2txt(Addr *a)
-{
-	switch (a->kind) {
-	case SCONST:
-		sprintf(buff, "%llu", (unsigned long long) a->u.i);
-		return buff;
-	case SAUTO:
-	case SLABEL:
-	case STMP:
-	case SGLOB:
-	case SEXTRN:
-	case SPRIV:
-	case SLOCAL:
-		return symname(a->u.sym);
-	default:
-		abort();
-	}
-}
-
-static void
-binary(void)
-{
-	struct opdata *p = &optbl[pc->op];
-	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%s =%c\t%s\t%s,%s\n", to, p->letter, p->txt, from1, from2);
-}
-
-static void
-ldir(void)
-{
-	struct opdata *p = &optbl[pc->op];
-	char to[ADDR_LEN], from[ADDR_LEN];
-	/* TODO: what type do we use for the size? */
-
-	/* TODO: it is pending */
-}
-
-static void
-store(void)
-{
-	struct opdata *p = &optbl[pc->op];
-	char to[ADDR_LEN], from[ADDR_LEN];
-
-	strcpy(to, addr2txt(&pc->to));
-	strcpy(from, addr2txt(&pc->from1));
-	printf("\t\t%s%c\t%s,%s\n", p->txt, p->letter, from, to);
-}
-
-static void
-unary(void)
-{
-	struct opdata *p = &optbl[pc->op];
-	char to[ADDR_LEN], from[ADDR_LEN];
-
-	strcpy(to, addr2txt(&pc->to));
-	strcpy(from, addr2txt(&pc->from1));
-	printf("\t%s =%c\t%s\t%s\n", to, p->letter, p->txt, from);
-}
-
-static void
-call(void)
-{
-	struct opdata *p = &optbl[pc->op];
-	char to[ADDR_LEN], from[ADDR_LEN];
-	Symbol *sym = pc->to.u.sym;
-
-	strcpy(to, addr2txt(&pc->to));
-	strcpy(from, addr2txt(&pc->from1));
-	printf("\t%s =%s\tcall\t%s(",
-	       to, size2stack(&sym->type), from);
-}
-
-static void
-param(void)
-{
-	Symbol *sym = pc->from2.u.sym;
-
-	printf(optbl[pc->op].txt,
-	       size2stack(&sym->type), addr2txt(&pc->from1));
-}
-
-static void
-ecall(void)
-{
-	struct opdata *p = &optbl[pc->op];
-
-	puts(p->txt);
-}
-
-static void
-ret(void)
-{
-	if (pc->from1.kind == SNONE)
-		puts("\t\tret");
-	else
-		printf("\t\tret\t%s\n", addr2txt(&pc->from1));
-}
-
-static void
-jmp(void)
-{
-	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);
-}
-
-static void
-vastart(void)
-{
-	printf("\t\tvastart %s\n", addr2txt(&pc->from1));
-}
-
-static void
-vaarg(void)
-{
-	Symbol *sym = pc->to.u.sym;
-	Type *tp = &sym->type;
-	char to[ADDR_LEN], from[ADDR_LEN];
-
-	strcpy(to, addr2txt(&pc->to));
-	strcpy(from, addr2txt(&pc->from1));
-	printf("\t\t%s =%s vaarg %s\n", to, size2asm(tp), from);
-}
-
-static void
-alloc(void)
-{
-	Symbol *sym = pc->to.u.sym;
-	Type *tp = &sym->type;
-	extern Type ptrtype;
-
-	printf("\t%s =%s\talloc%lu\t%lu\n",
-	       symname(sym), size2asm(&ptrtype), tp->align+3 & ~3, tp->size);
-}
-
-static void
-form2local(void)
-{
-	Symbol *sym = pc->to.u.sym;
-	Type *tp = &sym->type;
-	char *name = symname(sym);
-
-	printf("\t\tstore%s\t%s.val,%s\n", size2asm(tp), name, name);
-}
-
-void
-endinit(void)
-{
-	puts("}");
-}
-
-void
-getbblocks(void)
-{
-	Inst *i;
-
-	if (!prog)
-		return;
-
-	prog->flags |= BBENTRY;
-	for (pc = prog; pc; pc = pc->next) {
-		switch (pc->op) {
-		case ASBRANCH:
-			i = pc->from2.u.sym->u.inst;
-			i->flags |= BBENTRY;
-		case ASJMP:
-			i = pc->from1.u.sym->u.inst;
-			i->flags |= BBENTRY;
-		case ASRET:
-			if (pc->next)
-				pc->next->flags |= BBENTRY;
-			break;
-		}
-	}
-}
--- a/cc2/target/qbe_amd64-sysv/optm.c
+++ /dev/null
@@ -1,58 +1,0 @@
-/* See LICENSE file for copyright and license details. */
-static char sccsid[] = "@(#) ./cc2/arch/qbe/optm.c";
-
-#include <stddef.h>
-
-#include "../../../inc/scc.h"
-#include "../../cc2.h"
-
-Node *
-optm_dep(Node *np)
-{
-	int op = np->op;
-	Node *p, *dst, *next = np->next;
-	Symbol *sym, *osym;
-
-	switch (op) {
-	case OEFUN:
-		/*
-		 * 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
-		 */
-		op = (np->prev) ? np->prev->op : 0;
-		if (!op || op == ONOP || op == OBRANCH || (op != ORET && op != OJMP))
-			addstmt(newnode(ORET), KEEPCUR);
-		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;
-}
--- a/cc2/target/qbe_amd64-sysv/target.mk
+++ b/cc2/target/qbe_amd64-sysv/target.mk
@@ -1,6 +1,6 @@
 
 OBJ-qbe_amd64-sysv = $(OBJ)  \
-        target/qbe_amd64-sysv/cgen.o \
-        target/qbe_amd64-sysv/optm.o \
-        target/qbe_amd64-sysv/code.o \
-        target/qbe_amd64-sysv/types.o
+        target/qbe/cgen.o \
+        target/qbe/optm.o \
+        target/qbe/code.o \
+        target/arm64-sysv/types.o
--- a/cc2/target/qbe_amd64-sysv/types.c
+++ /dev/null
@@ -1,94 +1,0 @@
-/* See LICENSE file for copyright and license details. */
-static char sccsid[] = "@(#) ./cc2/arch/qbe/types.c";
-
-#include "../../../inc/scc.h"
-#include "../../cc2.h"
-
-
-Type int8type = {
-	.flags  = SIGNF | INTF,
-	.size   = 1,
-	.align  = 1
-};
-
-Type int16type = {
-	.flags  = SIGNF | INTF,
-	.size   = 2,
-	.align  = 2
-};
-
-Type int32type = {
-	.flags  = SIGNF | INTF,
-	.size   = 4,
-	.align  = 4
-};
-
-Type int64type = {
-	.flags  = SIGNF | INTF,
-	.size   = 8,
-	.align  = 8
-};
-
-Type uint8type = {
-	.flags  = INTF,
-	.size   = 1,
-	.align  = 1
-};
-
-Type uint16type = {
-	.flags  = INTF,
-	.size   = 2,
-	.align  = 2
-};
-
-Type uint32type = {
-	.flags  = INTF,
-	.size   = 4,
-	.align  = 4
-};
-
-Type uint64type = {
-	.flags  = INTF,
-	.size   = 8,
-	.align  = 2
-};
-
-Type ptrtype = {
-	.flags  = INTF,
-	.size   = 8,
-	.align  = 8
-};
-
-Type booltype = {
-	.flags  = INTF,
-	.size   = 1,
-	.align  = 1
-};
-
-Type float32type = {
-	.flags  = FLOATF,
-	.size   = 4,
-	.align  = 4
-};
-
-Type float64type = {
-	.flags  = FLOATF,
-	.size   = 8,
-	.align  = 8
-};
-
-Type float80type = {
-	.flags  = FLOATF,
-	.size   = 16,
-	.align  = 16
-};
-
-Type voidtype = {
-	.size = 0,
-	.align = 0
-};
-
-Type arg_type = {
-	.size = 24,
-	.align = 8
-};
--- /dev/null
+++ b/cc2/target/qbe_arm64-sysv/target.mk
@@ -1,0 +1,6 @@
+
+OBJ-qbe_amd64-sysv = $(OBJ)  \
+        target/qbe/cgen.o \
+        target/qbe/optm.o \
+        target/qbe/code.o \
+        target/arm64-sysv/types.o