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