ref: a63dd7c3e1fe8e41223a178f0b38a3354bd34d5e
dir: /cc2/arch/qbe/cgen.c/
/* 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 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 }; extern Type int32type; 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; } static Node * load(Node *np, Node *new) { int op; Type *tp; tp = &np->type; new->type = *tp; tmpnode(new); 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, np, NULL); return new; } static Node * assign(Node *to, Node *from) { Type *tp; int op; tp = &to->type; 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 *rhs(Node *np, Node *new); static Node * lhs(Node *np, Node *new) { switch (np->op) { case OMEM: case OAUTO: return np; case OPTR: return rhs(np->left, new); 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 OAND: label = newlabel(); bool(l, label, true); setlabel(label); bool(r, true, false); break; case OOR: label = newlabel(); bool(l, true, label); setlabel(label); bool(r, true, false); break; default: ifyes = label2node(true); ifno = label2node(false); rhs(l, &ret); code(ASBRANCH, &ret, ifyes, ifno); deltree(ifyes); deltree(ifno); break; } } 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; } 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 OEFUN: return NULL; case OCONST: case OMEM: case OAUTO: return load(np, ret); case OAND: case OOR: true = newlabel(); false = newlabel(); phi = label2node(newlabel()); ret->type = int32type; tmpnode(ret); bool(np, true, false); setlabel(true); assign(ret, constnode(1, &int32type)); code(ASJMP, NULL, phi, NULL); setlabel(false); assign(ret, constnode(0, &int32type)); setlabel(phi->u.sym); deltree(phi); return ret; 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: 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 & INTF) ? opasmw : opasms; break; case 8: tbl = (tp->flags & INTF) ? opasml : opasmd; break; default: abort(); } op = tbl[np->op] + off; ret = tmpnode(ret); code(op, ret, &aux1, &aux2); return ret; case OASSIG: lhs(l, &aux1); rhs(r, ret); return assign(&aux1, ret); default: abort(); } abort(); } Node * cgen(Node *np) { Node ret, *aux, *next, *phi, *ifyes, *ifno; setlabel(np->label); switch (np->op) { case OJMP: ifyes = label2node(np->u.sym); code(ASJMP, NULL, ifyes, NULL); deltree(ifyes); break; case OBRANCH: next = np->next; if (!next->label) next->label = newlabel(); ifyes = label2node(np->u.sym); ifno = label2node(next->label); rhs(np->left, &ret); code(ASBRANCH, &ret, ifyes, ifno); deltree(ifyes); deltree(ifno); break; case ORET: aux = (np->left) ? rhs(np->left, &ret) : NULL; code(ASRET, NULL, aux, NULL); break; default: rhs(np, &ret); 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: np->op = OAND; rp = constnode(~(TUINT) 0, &np->type); goto binary; case OSNEG: np->op = OSUB; rp = lp; lp = constnode(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; }