scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit c24d1d19be49987c696d8330bb66e50cc4435240
parent 82d4a96ab4740538492214657f82a75e43fa2014
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sun, 27 Aug 2017 19:05:17 +0200

[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

Diffstat:
cc1/target/arm64-sysv/arch.c | 0
cc2/target/arm64-sysv/types.c | 0
cc2/target/qbe/arch.h | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cc2/target/qbe/cgen.c | 731+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cc2/target/qbe/code.c | 569+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cc2/target/qbe/optm.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cc2/target/qbe_amd64-sysv/arch.h | 137-------------------------------------------------------------------------------
cc2/target/qbe_amd64-sysv/cgen.c | 731-------------------------------------------------------------------------------
cc2/target/qbe_amd64-sysv/code.c | 569-------------------------------------------------------------------------------
cc2/target/qbe_amd64-sysv/optm.c | 58----------------------------------------------------------
cc2/target/qbe_amd64-sysv/target.mk | 8++++----
cc2/target/qbe_amd64-sysv/types.c | 94-------------------------------------------------------------------------------
cc2/target/qbe_arm64-sysv/target.mk | 6++++++
13 files changed, 1505 insertions(+), 1593 deletions(-)

diff --git a/cc1/target/arm64-sysv/arch.c b/cc1/target/arm64-sysv/arch.c diff --git a/cc2/target/arm64-sysv/types.c b/cc2/target/arm64-sysv/types.c diff --git a/cc2/target/qbe/arch.h b/cc2/target/qbe/arch.h @@ -0,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, +}; diff --git a/cc2/target/qbe/cgen.c b/cc2/target/qbe/cgen.c @@ -0,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; +} diff --git a/cc2/target/qbe/code.c b/cc2/target/qbe/code.c @@ -0,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; + } + } +} diff --git a/cc2/target/qbe/optm.c b/cc2/target/qbe/optm.c @@ -0,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; +} diff --git a/cc2/target/qbe_amd64-sysv/arch.h b/cc2/target/qbe_amd64-sysv/arch.h @@ -1,137 +0,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, -}; diff --git a/cc2/target/qbe_amd64-sysv/cgen.c b/cc2/target/qbe_amd64-sysv/cgen.c @@ -1,731 +0,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; -} diff --git a/cc2/target/qbe_amd64-sysv/code.c b/cc2/target/qbe_amd64-sysv/code.c @@ -1,569 +0,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; - } - } -} diff --git a/cc2/target/qbe_amd64-sysv/optm.c b/cc2/target/qbe_amd64-sysv/optm.c @@ -1,58 +0,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; -} diff --git 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 diff --git a/cc2/target/qbe_amd64-sysv/types.c b/cc2/target/qbe_amd64-sysv/types.c @@ -1,94 +0,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 -}; diff --git a/cc2/target/qbe_arm64-sysv/target.mk b/cc2/target/qbe_arm64-sysv/target.mk @@ -0,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