ref: 51726ed12da4175bb9f73f8bf72e02fe5a816fd1
parent: 1344701bd8e23e73e5f94096485553b534ba4890
author: Roberto E. Vargas Caballero <[email protected]>
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
--- /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