1#include <assert.h>2#include <stdlib.h>34#include <scc/cstd.h>5#include <scc/scc.h>67#include "../cc2.h"8#include "arch.h"910#define I1BYTES 011#define I2BYTES 112#define I4BYTES 213#define I8BYTES 31415static Node *cgen(Node *);1617static unsigned char opasmw[][2] = {18 [OADD] = {ASADDW, ASADDW},19 [OSUB] = {ASSUBW, ASSUBW},20 [OMUL] = {ASMULW, ASMULW},21 [OMOD] = {ASMODW, ASUMODW},22 [ODIV] = {ASDIVW, ASUDIVW},23 [OSHL] = {ASSHLW, ASSHLW},24 [OSHR] = {ASSHRW, ASUSHRW},25 [OLT] = {ASLTW, ASULTW},26 [OGT] = {ASGTW, ASUGTW},27 [OLE] = {ASLEW, ASULEW},28 [OGE] = {ASGEW, ASUGEW},29 [OEQ] = {ASEQW, ASEQW},30 [ONE] = {ASNEW, ASNEW},31 [OBAND] = {ASBANDW, ASBANDW},32 [OBOR] = {ASBORW, ASBORW},33 [OBXOR] = {ASBXORW, ASBXORW},34 [OSNEG] = {ASNEGW, ASNEGW},35};3637static unsigned char opasml[][2] = {38 [OADD] = {ASADDL, ASADDL},39 [OSUB] = {ASSUBL, ASSUBL},40 [OMUL] = {ASMULL, ASMULL},41 [OMOD] = {ASMODL, ASUMODL},42 [ODIV] = {ASDIVL, ASUDIVL},43 [OSHL] = {ASSHLL, ASSHLL},44 [OSHR] = {ASSHRL, ASUSHRL},45 [OLT] = {ASLTL, ASULTL},46 [OGT] = {ASGTL, ASUGTL},47 [OLE] = {ASLEL, ASULEL},48 [OGE] = {ASGEL, ASUGEL},49 [OEQ] = {ASEQL, ASEQL},50 [ONE] = {ASNEL, ASNEL},51 [OBAND] = {ASBANDL, ASBANDL},52 [OBOR] = {ASBORL, ASBORL},53 [OBXOR] = {ASBXORL, ASBXORL},54 [OSNEG] = {ASNEGL, ASNEGL},55};5657static unsigned char opasms[][2] = {58 [OADD] = {ASADDS, ASADDS},59 [OSUB] = {ASSUBS, ASSUBS},60 [OMUL] = {ASMULS, ASMULS},61 [ODIV] = {ASDIVS, ASDIVS},62 [OLT] = {ASLTS, ASLTS},63 [OGT] = {ASGTS, ASGTS},64 [OLE] = {ASLES, ASLES},65 [OGE] = {ASGES, ASGES},66 [OEQ] = {ASEQS, ASEQS},67 [ONE] = {ASNES, ASNES},68 [OSNEG] = {ASNEGS, ASNEGS},69};7071static unsigned char opasmd[][2] = {72 [OADD] = {ASADDD, ASADDD},73 [OSUB] = {ASSUBD, ASSUBD},74 [OMUL] = {ASMULD, ASMULD},75 [ODIV] = {ASDIVD, ASDIVD},76 [OLT] = {ASLTD, ASLTD},77 [OGT] = {ASGTD, ASGTD},78 [OLE] = {ASLED, ASLED},79 [OGE] = {ASGED, ASGED},80 [OEQ] = {ASEQD, ASEQD},81 [ONE] = {ASNED, ASNED},82 [OSNEG] = {ASNEGD, ASNEGD},83};8485static unsigned char (*opbin[][2])[2] = {86 {opasmw, opasml},87 {opasms, opasmd},88};8990static unsigned char i2i_conv[4][4][2] = {91 [I1BYTES] = {92 [I4BYTES] = {ASEXTBW, ASUEXTBW},93 [I8BYTES] = {ASEXTBL, ASUEXTBL},94 },95 [I2BYTES] = {96 [I4BYTES] = {ASEXTHW, ASUEXTHW},97 [I8BYTES] = {ASEXTHL, ASUEXTHL},98 },99 [I4BYTES] = {100 [I8BYTES] = {ASEXTWL, ASUEXTWL},101 }102};103104static unsigned char f2i_conv[4][4][2] = {105 [I4BYTES] = {106 [I4BYTES] = {ASSTOW, ASSTOUW},107 [I8BYTES] = {ASSTOL, ASDTOUL},108 },109 [I8BYTES] = {110 [I4BYTES] = {ASDTOW, ASDTOUW},111 [I8BYTES] = {ASDTOL, ASDTOUL},112 }113};114115static unsigned char i2f_conv[4][4][2] = {116 [I4BYTES] = {117 [I4BYTES] = {ASSWTOS, ASUWTOS},118 [I8BYTES] = {ASSWTOD, ASUWTOD},119 },120 [I8BYTES] = {121 [I4BYTES] = {ASSLTOS, ASULTOS},122 [I8BYTES] = {ASSLTOD, ASULTOD},123 }124};125126/*127 * This is strongly influenced by128 * http://plan9.bell-labs.com/sys/doc/compiler.ps (/sys/doc/compiler.ps)129 * calculate addresability as follows130 * AUTO => 11 value+fp131 * REG => 11 reg132 * STATIC => 11 (value)133 * CONST => 11 $value134 * These values of addressability are not used in the code generation.135 * They are only used to calculate the Sethi-Ullman numbers. Since136 * QBE is AMD64 targered we could do a better job there, and try to137 * detect some of the complex addressing modes of these processors.138 */139Node *140tsethi(Node *np)141{142 int op;143 Node *l, *r;144145 l = np->left;146 r = np->right;147148 switch (np->op) {149 case OAUTO:150 case OREG:151 case OMEM:152 case OCONST:153 np->address = 11;154 break;155 case OASSIG:156 assert(l->op != OCAST);157 goto binary;158 case OCPL:159 assert(np->type.flags & INTF);160 np->op = OBXOR;161 r = constnode(NULL, ~0ULL, &np->type);162 goto binary;163 case OEFUN:164 /*165 * In QBE we need at the end of a basic block166 * a jump, so we have to ensure that the last167 * statement of the function is a ret, a jmp168 * or a branch.169 */170171 op = np->prev->op;172 if (op == ONOP || op == OBRANCH || (op != ORET && op != OJMP))173 addstmt(node(ORET));174 break;175 default:176 binary:177 l = sethi(l);178 r = sethi(r);179 break;180 }181 np->left = l;182 np->right = r;183184 return np;185}186187static int188bytes2idx(int nbytes)189{190 if (nbytes== 1)191 return I1BYTES;192 else if (nbytes == 2)193 return I2BYTES;194 else if (nbytes == 4)195 return I4BYTES;196 else if (nbytes == 8)197 return I8BYTES;198 else199 abort();200}201202static Node *203load(Type *tp, Node *np)204{205 int op;206 Node *new;207 int flags = tp->flags;208209 if (flags & (AGGRF|FUNF|ARRF|PTRF))210 return np;211212 switch (tp->size) {213 case 1:214 op = ASLDSB;215 break;216 case 2:217 op = ASLDSH;218 break;219 case 4:220 op = (flags & FLOATF) ? ASLDS : ASLDSW;221 break;222 case 8:223 op = (flags & FLOATF) ? ASLDD : ASLDL;224 break;225 default:226 abort();227 }228 /*229 * unsigned version of operations are always +1 the230 * signed version231 */232 if ((flags & (INTF|SIGNF)) == INTF && tp->size < 8)233 ++op;234235 new = tmpnode(tp, NULL);236 code(op, new, np, NULL);237238 return new;239}240241static Node *rhs(Node *np);242243static Node *244cast(Type *td, Node *np)245{246 Type *ts;247 Node *tmp;248 int op, d_isint, s_isint, sidx, didx, sign;249250 ts = &np->type;251 d_isint = (td->flags & INTF) != 0;252 s_isint = (ts->flags & INTF) != 0;253254 sidx = bytes2idx(ts->size);255 didx = bytes2idx(td->size);256257 sign = (ts->flags & SIGNF) == 0;258259 if (d_isint && s_isint) {260 /* conversion from int to int */261 if (didx < I4BYTES)262 didx = bytes2idx(4);263264 if (didx <= sidx) {265 np->type = *td;266 return np;267 }268269 op = i2i_conv[sidx][didx][sign];270 } else if (d_isint) {271 /* conversion from float to int */272 if (didx < I4BYTES)273 didx = bytes2idx(4);274275 op = f2i_conv[sidx][didx][sign];276 } else if (s_isint) {277 /* conversion from int to float */278 if (sidx == I1BYTES || sidx == I2BYTES) {279 ts = (ts->flags&SIGNF) ? &int32type : &uint32type;280 np = cast(ts, np);281 }282 op = i2f_conv[sidx][didx][sign];283 } else {284 /* conversion from float to float */285 op = (didx == I4BYTES) ? ASTRUNCD : ASEXTS;286 }287288 assert(op != 0);289 tmp = tmpnode(td, NULL);290 code(op, tmp, np, NULL);291292 return tmp;293}294295static Node *296call(Node *np, Node *fun)297{298 int n, op;299 Type *tp;300 Node **q, *tmp, *p, *pars[NR_FUNPARAM];301302 for (n = 0, p = np->right; p; p = p->right)303 pars[n++] = rhs(p->left);304305 tp = &np->type;306 tmp = tmpnode(tp, NULL);307 code(ASCALL, tmp, fun, NULL);308309 for (q = pars; q < &pars[n]; ++q) {310 op = (q == &pars[n-1]) ? ASPARE : ASPAR;311 code(op, NULL, *q, tmpnode(&(*q)->type, NULL));312 }313 code((np->op == OCALL) ? ASCALLE : ASCALLEX, NULL, NULL, NULL);314315 return tmp;316}317318static Node *319copy(Type *tp, Node *to, Node *from)320{321 int op;322323 switch (tp->size) {324 case 0:325 return from;326 case 1:327 op = ASCOPYB;328 break;329 case 2:330 op = ASCOPYH;331 break;332 case 4:333 op = (tp->flags & FLOATF) ? ASCOPYS : ASCOPYW;334 break;335 case 8:336 op = (tp->flags & FLOATF) ? ASCOPYD : ASCOPYL;337 break;338 default:339 abort();340 }341 code(op, to, from, NULL);342 return from;343}344345static Node *346field(Node *np, int islhs)347{348 Node *tmp, *addr;349 unsigned long long offset = np->right->u.sym->u.off;350351 addr = rhs(np->left);352 tmp = node(OADD);353 tmp->type = ptrtype;354 tmp->left = addr;355 tmp->right = constnode(NULL, offset, &ptrtype);356 addr = rhs(tmp);357358 if (!islhs)359 addr = load(&np->type, addr);360 return addr;361}362363static Node *364lhs(Node *np)365{366 switch (np->op) {367 case OREG:368 case OMEM:369 case OAUTO:370 return np;371 case OPTR:372 return rhs(np->left);373 case OFIELD:374 return field(np, 1);375 default:376 abort();377 }378}379380static Node *381function(void)382{383 Node aux;384 Symbol *p;385386 /* allocate stack space for parameters */387 for (p = locals; p; p = p->next) {388 if ((p->type.flags & PARF) == 0)389 continue;390 if ((p->type.flags & AGGRF) != 0)391 continue;392 code(ASALLOC, label2node(&aux, p), NULL, NULL);393 }394395 /* allocate stack space for local variables) */396 for (p = locals; p; p = p->next) {397 if ((p->type.flags & PARF) != 0)398 continue;399 if (p->kind != SAUTO || p->id == TMPSYM)400 continue;401 code(ASALLOC, label2node(&aux, p), NULL, NULL);402 }403404 /* store formal parameters in parameters */405 for (p = locals; p; p = p->next) {406 if ((p->type.flags & PARF) == 0)407 continue;408 if ((p->type.flags & AGGRF) != 0)409 continue;410 if ((p->type.flags & (ARRF|AGGRF)) == 0)411 code(ASFORM, label2node(&aux, p), NULL, NULL);412 }413 return NULL;414}415416static int417assignop(Type *tp)418{419 int flags = tp->flags;420421 if (flags & (AGGRF|FUNF|ARRF))422 return ASSTM;423424 switch (tp->size) {425 case 1:426 return ASSTB;427 case 2:428 return ASSTH;429 case 4:430 return (tp->flags & FLOATF) ? ASSTS : ASSTW;431 case 8:432 return (tp->flags & FLOATF) ? ASSTD : ASSTL;433 default:434 abort();435 }436}437438static void439rhs_rhs(Node **lpp, Node **rpp)440{441 Node *l = *lpp, *r = *rpp;442443 if (l->complex >= r->complex) {444 l = rhs(l);445 r = rhs(r);446 } else {447 r = rhs(r);448 l = rhs(l);449 }450451 *lpp = l, *rpp = r;452}453454static void455lhs_rhs(Node **lpp, Node **rpp)456{457 Node *l = *lpp, *r = *rpp;458459 if (l->complex >= r->complex) {460 l = lhs(l);461 r = rhs(r);462 } else {463 r = rhs(r);464 l = lhs(l);465 }466467 *lpp = l, *rpp = r;468}469470static Node *471assign(Node *np)472{473 Node *ret, aux;474 Node *l = np->left, *r = np->right;475 int op;476477 switch (np->u.subop) {478 case OINC:479 op = OADD;480 goto post_oper;481 case ODEC:482 op = OSUB;483 post_oper:484 lhs_rhs(&l, &r);485 ret = load(&r->type, l);486 aux.op = op;487 aux.left = ret;488 aux.right = r;489 aux.type = np->type;490 r = rhs(sethi(&aux));491 break;492 default:493 /* assign abbreviation */494 assert(l->type.size == r->type.size);495 if (r->type.size < 4) {496 lhs_rhs(&l, &r);497 aux.op = np->u.subop;498 aux.left = load(&r->type, l);499 aux.right = r;500 aux.type = int32type;501 aux.address = np->address;502 ret = r = sethi(rhs(&aux));503 break;504 }505506 aux.op = np->u.subop;507 aux.left = l;508 aux.right = r;509 aux.type = np->type;510 aux.address = np->address;511 r = sethi(&aux);512 case 0:513 if (l->op == OTMP) {514 r = rhs(r);515 copy(&np->type, l, r);516 return r;517 }518519 lhs_rhs(&l, &r);520 ret = r;521 break;522 }523524 code(assignop(&np->type), l, r, tmpnode(&np->type, NULL));525 return ret;526}527528static Node *529rhs(Node *np)530{531 Node *tmp, aux1, aux2;532 Node *phi, *l = np->left, *r = np->right;533 Type *tp;534 int cmp, sign, size, isfloat, op;535536 tp = &np->type;537538 switch (np->op) {539 case OTMP:540 case OCONST:541 return np;542 case OMEM:543 case OREG:544 case OAUTO:545 return load(tp, np);546 case OLT:547 case OGT:548 case OLE:549 case OGE:550 case OEQ:551 case ONE:552 cmp = 1;553 goto binary;554 case OMOD:555 case OSHL:556 case OBAND:557 case OBOR:558 case OBXOR:559 case OSHR:560 assert(tp->flags & INTF);561 case ODIV:562 case OADD:563 case OSUB:564 case OMUL:565 cmp = 0;566 binary:567 assert(tp->size == 4 || tp->size == 8);568569 sign = (tp->flags & SIGNF) == 0;570 size = tp->size == 8;571 isfloat = (tp->flags & FLOATF) != 0;572 op = opbin[isfloat][size][np->op][sign];573 rhs_rhs(&l, &r);574 if (cmp)575 tp = &int32type;576 tmp = tmpnode(tp, NULL);577 code(op, tmp, l, r);578 return tmp;579 case OCALL:580 case OCALLE:581 if (l->op == OPTR)582 l = rhs(l);583 return call(np, l);584 case OCAST:585 return cast(tp, rhs(l));586 case OASSIG:587 return assign(np);588 case OSNEG:589 sign = (tp->flags & SIGNF) == 0;590 size = tp->size == 8;591 isfloat = (tp->flags & FLOATF) != 0;592 op = opbin[isfloat][size][np->op][sign];593 tmp = tmpnode(tp, NULL);594 code(op, tmp, rhs(l), NULL);595 return tmp;596 case OPTR:597 return load(tp, rhs(l));598 case OADDR:599 l = lhs(l);600 l->type = *tp;601 l->type.flags |= PTRF;602 return l;603 case OFIELD:604 return field(np, 0);605 case OBUILTIN:606 switch (np->u.subop) {607 case BVA_START:608 l = rhs(l);609 code(ASVSTAR, NULL, l, NULL);610 case BVA_END:611 return NULL;612 case BVA_ARG:613 l = rhs(l);614 tmp = tmpnode(tp, NULL);615 code(ASVARG, tmp, l, NULL);616 return tmp;617 default:618 abort();619 }620 default:621 abort();622 }623 abort();624}625626static Node *627cgen(Node *np)628{629 Node ntrue, nfalse, *p, *next;630631 setlabel(np->label);632 switch (np->op) {633 case OBFUN:634 return function();635 case ONOP:636 case OBLOOP:637 case OELOOP:638 case OEFUN:639 break;640 case OJMP:641 label2node(&ntrue, np->u.sym);642 code(ASJMP, NULL, &ntrue, NULL);643 break;644 case OBRANCH:645 /*646 * QBE does not accept labels at the end of a function647 * (ONOP is used for labels) so we have to add a ret648 * there, and in the case of branches we need a label649 * for the next statement.650 */651 next = np->next;652 if (!next->label)653 labelstmt(next, NULL);654655 label2node(&ntrue, np->u.sym);656 label2node(&nfalse, np->next->label);657 code(ASBRANCH, rhs(np->left), &ntrue, &nfalse);658 break;659 case ORET:660 p = (np->left) ? rhs(np->left) : NULL;661 code(ASRET, NULL, p, NULL);662 break;663 default:664 rhs(np);665 break;666 }667 return NULL;668}669670void671genasm(void)672{673 apply(cgen);674}