1#include <stdio.h>2#include <stdlib.h>3#include <string.h>45#include <scc/cstd.h>6#include <scc/scc.h>78#include "../cc2.h"9#include "arch.h"1011#define ADDR_LEN (INTIDENTSIZ+64)1213static void binary(void), unary(void), store(void), jmp(void), ret(void),14 branch(void), call(void), ecall(void), param(void),15 asalloc(void), form2local(void), blit(void), vastart(void),16 vaarg(void);1718static struct opdata {19 void (*fun)(void);20 char *txt;21 char letter;22} optbl [] = {23 [ASLDSB] = {.fun = unary, .txt = "loadsb", .letter = 'w'},24 [ASLDUB] = {.fun = unary, .txt = "loadub", .letter = 'w'},25 [ASLDSH] = {.fun = unary, .txt = "loadsh", .letter = 'w'},26 [ASLDUH] = {.fun = unary, .txt = "loaduh", .letter = 'w'},27 [ASLDSW] = {.fun = unary, .txt = "loadsw", .letter = 'w'},28 [ASLDUW] = {.fun = unary, .txt = "loaduw", .letter = 'w'},29 [ASLDL] = {.fun = unary, .txt = "loadl", .letter = 'l'},30 [ASLDS] = {.fun = unary, .txt = "loads", .letter = 's'},31 [ASLDD] = {.fun = unary, .txt = "loadd", .letter = 'd'},3233 [ASCOPYB] = {.fun = unary, .txt = "copy", .letter = 'b'},34 [ASCOPYH] = {.fun = unary, .txt = "copy", .letter = 'h'},35 [ASCOPYW] = {.fun = unary, .txt = "copy", .letter = 'w'},36 [ASCOPYL] = {.fun = unary, .txt = "copy", .letter = 'l'},37 [ASCOPYS] = {.fun = unary, .txt = "copy", .letter = 's'},38 [ASCOPYD] = {.fun = unary, .txt = "copy", .letter = 'd'},3940 [ASSTB] = {.fun = store, .txt = "store", .letter = 'b'},41 [ASSTH] = {.fun = store, .txt = "store", .letter = 'h'},42 [ASSTW] = {.fun = store, .txt = "store", .letter = 'w'},43 [ASSTL] = {.fun = store, .txt = "store", .letter = 'l'},44 [ASSTM] = {.fun = blit},45 [ASSTS] = {.fun = store, .txt = "store", .letter = 's'},46 [ASSTD] = {.fun = store, .txt = "store", .letter = 'd'},4748 [ASADDW] = {.fun = binary, .txt = "add", .letter = 'w'},49 [ASSUBW] = {.fun = binary, .txt = "sub", .letter = 'w'},50 [ASMULW] = {.fun = binary, .txt = "mul", .letter = 'w'},51 [ASMODW] = {.fun = binary, .txt = "rem", .letter = 'w'},52 [ASUMODW] = {.fun = binary, .txt = "urem", .letter = 'w'},53 [ASDIVW] = {.fun = binary, .txt = "div", .letter = 'w'},54 [ASUDIVW] = {.fun = binary, .txt = "udiv", .letter = 'w'},55 [ASSHLW] = {.fun = binary, .txt = "shl", .letter = 'w'},56 [ASSHRW] = {.fun = binary, .txt = "sar", .letter = 'w'},57 [ASUSHRW] = {.fun = binary, .txt = "shr", .letter = 'w'},58 [ASLTW] = {.fun = binary, .txt = "csltw", .letter = 'w'},59 [ASULTW] = {.fun = binary, .txt = "cultw", .letter = 'w'},60 [ASGTW] = {.fun = binary, .txt = "csgtw", .letter = 'w'},61 [ASUGTW] = {.fun = binary, .txt = "cugtw", .letter = 'w'},62 [ASLEW] = {.fun = binary, .txt = "cslew", .letter = 'w'},63 [ASULEW] = {.fun = binary, .txt = "culew", .letter = 'w'},64 [ASGEW] = {.fun = binary, .txt = "csgew", .letter = 'w'},65 [ASUGEW] = {.fun = binary, .txt = "cugew", .letter = 'w'},66 [ASEQW] = {.fun = binary, .txt = "ceqw", .letter = 'w'},67 [ASNEW] = {.fun = binary, .txt = "cnew", .letter = 'w'},68 [ASBANDW] = {.fun = binary, .txt = "and", .letter = 'w'},69 [ASBORW] = {.fun = binary, .txt = "or", .letter = 'w'},70 [ASBXORW] = {.fun = binary, .txt = "xor", .letter = 'w'},7172 [ASADDL] = {.fun = binary, .txt = "add", .letter = 'l'},73 [ASSUBL] = {.fun = binary, .txt = "sub", .letter = 'l'},74 [ASMULL] = {.fun = binary, .txt = "mul", .letter = 'l'},75 [ASMODL] = {.fun = binary, .txt = "rem", .letter = 'l'},76 [ASUMODL] = {.fun = binary, .txt = "urem", .letter = 'l'},77 [ASDIVL] = {.fun = binary, .txt = "div", .letter = 'l'},78 [ASUDIVL] = {.fun = binary, .txt = "udiv", .letter = 'l'},79 [ASSHLL] = {.fun = binary, .txt = "shl", .letter = 'l'},80 [ASSHRL] = {.fun = binary, .txt = "sar", .letter = 'l'},81 [ASUSHRL] = {.fun = binary, .txt = "shr", .letter = 'l'},82 [ASLTL] = {.fun = binary, .txt = "csltl", .letter = 'w'},83 [ASULTL] = {.fun = binary, .txt = "cultl", .letter = 'w'},84 [ASGTL] = {.fun = binary, .txt = "csgtl", .letter = 'w'},85 [ASUGTL] = {.fun = binary, .txt = "cugtl", .letter = 'w'},86 [ASLEL] = {.fun = binary, .txt = "cslel", .letter = 'w'},87 [ASULEL] = {.fun = binary, .txt = "culel", .letter = 'w'},88 [ASGEL] = {.fun = binary, .txt = "csgel", .letter = 'w'},89 [ASUGEL] = {.fun = binary, .txt = "cugel", .letter = 'w'},90 [ASEQL] = {.fun = binary, .txt = "ceql", .letter = 'w'},91 [ASNEL] = {.fun = binary, .txt = "cnel", .letter = 'w'},92 [ASBANDL] = {.fun = binary, .txt = "and", .letter = 'l'},93 [ASBORL] = {.fun = binary, .txt = "or", .letter = 'l'},94 [ASBXORL] = {.fun = binary, .txt = "xor", .letter = 'l'},9596 [ASADDS] = {.fun = binary, .txt = "add", .letter = 's'},97 [ASSUBS] = {.fun = binary, .txt = "sub", .letter = 's'},98 [ASMULS] = {.fun = binary, .txt = "mul", .letter = 's'},99 [ASDIVS] = {.fun = binary, .txt = "div", .letter = 's'},100 [ASLTS] = {.fun = binary, .txt = "clts", .letter = 'w'},101 [ASGTS] = {.fun = binary, .txt = "cgts", .letter = 'w'},102 [ASLES] = {.fun = binary, .txt = "cles", .letter = 'w'},103 [ASGES] = {.fun = binary, .txt = "cges", .letter = 'w'},104 [ASEQS] = {.fun = binary, .txt = "ceqs", .letter = 'w'},105 [ASNES] = {.fun = binary, .txt = "cnes", .letter = 'w'},106107 [ASADDD] = {.fun = binary, .txt = "add", .letter = 'd'},108 [ASSUBD] = {.fun = binary, .txt = "sub", .letter = 'd'},109 [ASMULD] = {.fun = binary, .txt = "mul", .letter = 'd'},110 [ASDIVD] = {.fun = binary, .txt = "div", .letter = 'd'},111 [ASLTD] = {.fun = binary, .txt = "cltd", .letter = 'w'},112 [ASGTD] = {.fun = binary, .txt = "cgtd", .letter = 'w'},113 [ASLED] = {.fun = binary, .txt = "cled", .letter = 'w'},114 [ASGED] = {.fun = binary, .txt = "cged", .letter = 'w'},115 [ASEQD] = {.fun = binary, .txt = "ceqd", .letter = 'w'},116 [ASNED] = {.fun = binary, .txt = "cned", .letter = 'w'},117118 [ASEXTBW] = {.fun = unary, .txt = "extsb", .letter = 'w'},119 [ASUEXTBW]= {.fun = unary, .txt = "extub", .letter = 'w'},120 [ASEXTBL] = {.fun = unary, .txt = "extsb", .letter = 'l'},121 [ASUEXTBL]= {.fun = unary, .txt = "extub", .letter = 'l'},122 [ASEXTHW] = {.fun = unary, .txt = "extsh", .letter = 'w'},123 [ASUEXTHW]= {.fun = unary, .txt = "extuh", .letter = 'w'},124 [ASEXTHL] = {.fun = unary, .txt = "extsh", .letter = 'l'},125 [ASUEXTHL]= {.fun = unary, .txt = "extuh", .letter = 'l'},126 [ASEXTWL] = {.fun = unary, .txt = "extsw", .letter = 'l'},127 [ASUEXTWL]= {.fun = unary, .txt = "extuw", .letter = 'l'},128129 [ASSTOL] = {.fun = unary, .txt = "stosi", .letter = 'l'},130 [ASSTOUL] = {.fun = unary, .txt = "stoui", .letter = 'l'},131 [ASSTOW] = {.fun = unary, .txt = "stosi", .letter = 'w'},132 [ASSTOUW] = {.fun = unary, .txt = "stoui", .letter = 'w'},133 [ASDTOL] = {.fun = unary, .txt = "dtosi", .letter = 'l'},134 [ASDTOUL] = {.fun = unary, .txt = "dtoui", .letter = 'l'},135 [ASDTOW] = {.fun = unary, .txt = "dtosi", .letter = 'w'},136 [ASDTOUW] = {.fun = unary, .txt = "dtoui", .letter = 'w'},137138 [ASSWTOD] = {.fun = unary, .txt = "swtof", .letter = 'd'},139 [ASUWTOD] = {.fun = unary, .txt = "uwtof", .letter = 'd'},140 [ASSWTOS] = {.fun = unary, .txt = "swtof", .letter = 's'},141 [ASUWTOS] = {.fun = unary, .txt = "uwtof", .letter = 's'},142 [ASSLTOD] = {.fun = unary, .txt = "sltof", .letter = 'd'},143 [ASULTOD] = {.fun = unary, .txt = "ultof", .letter = 'd'},144 [ASSLTOS] = {.fun = unary, .txt = "sltof", .letter = 's'},145 [ASULTOS] = {.fun = unary, .txt = "ultof", .letter = 's'},146147 [ASEXTS] = {.fun = unary, .txt = "exts", .letter = 'd'},148 [ASTRUNCD] = {.fun = unary, .txt = "truncd", .letter = 's'},149150 [ASNEGL] = {.fun = unary, .txt = "neg", .letter ='l'},151 [ASNEGW] = {.fun = unary, .txt = "neg", .letter ='w'},152 [ASNEGS] = {.fun = unary, .txt = "neg", .letter ='s'},153 [ASNEGD] = {.fun = unary, .txt = "neg", .letter ='d'},154155 [ASBRANCH] = {.fun = branch},156 [ASJMP] = {.fun = jmp},157 [ASRET] = {.fun = ret},158 [ASCALL] = {.fun = call},159 [ASCALLE] = {.fun = ecall, .txt = ")"},160 [ASCALLEX] = {.fun = ecall, .txt = ", ...)"},161 [ASPAR] = {.fun = param, .txt = "%s %s, "},162 [ASPARE] = {.fun = param, .txt = "%s %s"},163 [ASALLOC] = {.fun = asalloc},164 [ASFORM] = {.fun = form2local},165166 [ASVSTAR] = {.fun = vastart},167 [ASVARG] = {.fun = vaarg},168};169170static char buff[ADDR_LEN];171/*172 * : is for user-defined Aggregate Types173 * $ is for globals (represented by a pointer)174 * % is for function-scope temporaries175 * @ is for block labels176 */177static char178sigil(Symbol *sym)179{180 switch (sym->kind) {181 case SEXTRN:182 case SGLOB:183 case SPRIV:184 case SLOCAL:185 return '$';186 case SAUTO:187 case STMP:188 return '%';189 case SLABEL:190 return '@';191 default:192 abort();193 }194}195196static char *197symname(Symbol *sym)198{199 char c = sigil(sym);200201 if (sym->name) {202 switch (sym->kind) {203 case SEXTRN:204 case SGLOB:205 sprintf(buff, "%c%s", c, sym->name);206 return buff;207 case SLOCAL:208 case SPRIV:209 case SAUTO:210 sprintf(buff, "%c%s.L%u", c, sym->name, sym->id);211 return buff;212 default:213 abort();214 }215 }216 sprintf(buff, "%c.L%u", c, sym->numid);217218 return buff;219}220221static void222emitconst(Node *np)223{224 switch (np->type.size) {225 case 1:226 printf("%d", (int) np->u.i & 0xFF);227 break;228 case 2:229 printf("%d", (int) np->u.i & 0xFFFF);230 break;231 case 4:232 printf("%ld", (long) np->u.i & 0xFFFFFFFF);233 break;234 case 8:235 printf("%lld", (long long) np->u.i);236 break;237 default:238 abort();239 }240}241242static void243emittree(Node *np)244{245 if (!np)246 return;247248 switch (np->op) {249 case OSTRING:250 pprint(np->u.s);251 free(np->u.s);252 np->u.s = NULL;253 break;254 case OCONST:255 emitconst(np);256 break;257 case OADDR:258 emittree(np->left);259 break;260 case OMEM:261 fputs(symname(np->u.sym), stdout);262 break;263 default:264 emittree(np->left);265 printf(" %c ", np->op);266 emittree(np->right);267 break;268 }269}270271static char *272size2asm(Type *tp)273{274 static char spec[ADDR_LEN];275276 if (tp->flags & STRF) {277 return "b";278 } else if (tp->flags & INTF) {279 switch (tp->size) {280 case 1:281 return "b";282 case 2:283 return "h";284 case 4:285 return "w";286 case 8:287 return "l";288 }289 } else if (tp->flags & FLOATF) {290 if (tp->size == 4)291 return "s";292 else if (tp->size == 8)293 return "d";294 }295296 abort();297}298299void300defglobal(Symbol *sym)301{302 Type *tp = &sym->type;303304 if (sym->kind == SEXTRN)305 return;306 if (sym->kind == SGLOB)307 fputs("export ", stdout);308 if ((tp->flags & INITF) == 0)309 fputs("common ", stdout);310311 printf("data %s = align %d {\n",312 symname(sym),313 tp->align);314 if ((tp->flags & INITF) == 0)315 printf("\tz\t%lu\n}\n", tp->size);316}317318void319defpar(Symbol *sym)320{321 if (sym->kind == SREG)322 sym->kind = SAUTO;323 sym->type.flags |= PARF;324}325326void327defvar(Symbol *sym)328{329 if (sym->kind == SREG)330 sym->kind = SAUTO;331}332333void334data(Node *np)335{336 printf("\t%s\t", size2asm(&np->type));337 emittree(np);338 putchar(',');339 putchar('\n');340}341342static char *343size2stack(Type *tp)344{345 static char spec[ADDR_LEN];346347 if (tp->flags & INTF) {348 switch (tp->size) {349 case 1:350 case 2:351 case 4:352 return "w";353 case 8:354 return "l";355 }356 } else if (tp->flags & FLOATF) {357 if (tp->size == 4)358 return "s";359 else if (tp->size == 8)360 return "d";361 } else if (tp->flags & (ARRF|AGGRF)) {362 sprintf(spec, ":.%u", tp->id);363 return spec;364 } else if (tp->size == 0) {365 return "w";366 }367 abort();368}369370void371deftype(Type *tp)372{373 printf("type :.%u = align %d { %lu }\n",374 tp->id, tp->align, tp->size);375}376377static void378getbblocks(void)379{380 Inst *i;381382 if (!prog)383 return;384385 prog->flags |= BBENTRY;386 for (pc = prog; pc; pc = pc->next) {387 switch (pc->op) {388 case ASBRANCH:389 i = pc->from2.u.sym->u.inst;390 i->flags |= BBENTRY;391 case ASJMP:392 i = pc->from1.u.sym->u.inst;393 i->flags |= BBENTRY;394 case ASRET:395 if (pc->next)396 pc->next->flags |= BBENTRY;397 break;398 }399 }400}401402void403writeout(void)404{405 Symbol *p;406 Type *tp;407 char *sep;408 int haslabel = 0;409410 getbblocks();411412 if (curfun->kind == SGLOB)413 fputs("export ", stdout);414 printf("function ");415 if (curfun->rtype.size > 0)416 printf("%s ", size2stack(&curfun->rtype));417 printf("%s(", symname(curfun));418419 /* declare formal parameters */420 sep = "";421 for (p = locals; p; p = p->next) {422 if ((p->type.flags & PARF) == 0)423 continue;424 printf("%s%s %s%s",425 sep, size2stack(&p->type),426 symname(p),427 (p->type.flags & AGGRF) ? "" : ".val");428 sep = ",";429 }430 printf("%s)\n{\n@%s.body\n",431 (curfun->type.flags&ELLIPS) ? ", ..." : "",432 curfun->name);433434 /* emit assembler instructions */435 for (pc = prog; pc; pc = pc->next) {436 if (pc->label) {437 haslabel = 1;438 printf("%s\n", symname(pc->label));439 }440 if (pc->op == ASLABEL)441 continue;442 if (pc->flags&BBENTRY && !haslabel)443 printf("%s\n", symname(newlabel()));444 (*optbl[pc->op].fun)();445 if (!pc->label)446 haslabel = 0;447 }448449 puts("}");450}451452static char *453addr2txt(Addr *a)454{455 switch (a->kind) {456 case SCONST:457 sprintf(buff, "%llu", (unsigned long long) a->u.i);458 return buff;459 case SAUTO:460 case SLABEL:461 case STMP:462 case SGLOB:463 case SEXTRN:464 case SPRIV:465 case SLOCAL:466 return symname(a->u.sym);467 default:468 abort();469 }470}471472static void473binary(void)474{475 struct opdata *p = &optbl[pc->op];476 char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];477478 strcpy(to, addr2txt(&pc->to));479 strcpy(from1, addr2txt(&pc->from1));480 strcpy(from2, addr2txt(&pc->from2));481 printf("\t%s =%c\t%s\t%s,%s\n", to, p->letter, p->txt, from1, from2);482}483484static void485blit(void)486{487 Type *tp = &pc->from2.u.sym->type;488 char to[ADDR_LEN], from[ADDR_LEN];489490 strcpy(to, addr2txt(&pc->to));491 strcpy(from, addr2txt(&pc->from1));492 printf("\t\tblit\t%s,%s,%lu\n", from, to, tp->size);493}494495static void496store(void)497{498 struct opdata *p = &optbl[pc->op];499 char to[ADDR_LEN], from[ADDR_LEN];500501 strcpy(to, addr2txt(&pc->to));502 strcpy(from, addr2txt(&pc->from1));503 printf("\t\t%s%c\t%s,%s\n", p->txt, p->letter, from, to);504}505506static void507unary(void)508{509 struct opdata *p = &optbl[pc->op];510 char to[ADDR_LEN], from[ADDR_LEN];511512 strcpy(to, addr2txt(&pc->to));513 strcpy(from, addr2txt(&pc->from1));514 printf("\t%s =%c\t%s\t%s\n", to, p->letter, p->txt, from);515}516517static void518call(void)519{520 char to[ADDR_LEN], from[ADDR_LEN];521 Symbol *sym = pc->to.u.sym;522523 strcpy(to, addr2txt(&pc->to));524 strcpy(from, addr2txt(&pc->from1));525 if (sym->type.size > 0)526 printf("\t%s =%s", to, size2stack(&sym->type));527 printf("\tcall\t%s(", from);528}529530static void531param(void)532{533 Symbol *sym = pc->from2.u.sym;534535 printf(optbl[pc->op].txt,536 size2stack(&sym->type), addr2txt(&pc->from1));537}538539static void540ecall(void)541{542 struct opdata *p = &optbl[pc->op];543544 puts(p->txt);545}546547static void548ret(void)549{550 if (pc->from1.kind == SNONE)551 puts("\t\tret");552 else553 printf("\t\tret\t%s\n", addr2txt(&pc->from1));554}555556static void557jmp(void)558{559 printf("\t\tjmp\t%s\n", addr2txt(&pc->from1));560}561562static void563branch(void)564{565 char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];566567 strcpy(to, addr2txt(&pc->to));568 strcpy(from1, addr2txt(&pc->from1));569 strcpy(from2, addr2txt(&pc->from2));570 printf("\t\tjnz\t%s,%s,%s\n", to, from1, from2);571}572573static void574vastart(void)575{576 printf("\t\tvastart %s\n", addr2txt(&pc->from1));577}578579static void580vaarg(void)581{582 Symbol *sym = pc->to.u.sym;583 Type *tp = &sym->type;584 char to[ADDR_LEN], from[ADDR_LEN];585586 strcpy(to, addr2txt(&pc->to));587 strcpy(from, addr2txt(&pc->from1));588 printf("\t\t%s =%s vaarg %s\n", to, size2asm(tp), from);589}590591static void592asalloc(void)593{594 Symbol *sym = pc->to.u.sym;595 Type *tp = &sym->type;596 extern Type ptrtype;597598 printf("\t%s =%s\talloc%d\t%lu\n",599 symname(sym), size2asm(&ptrtype), tp->align+3 & ~3, tp->size);600}601602static void603form2local(void)604{605 Symbol *sym = pc->to.u.sym;606 Type *tp = &sym->type;607 char *name = symname(sym);608609 printf("\t\tstore%s\t%s.val,%s\n", size2asm(tp), name, name);610}611612void613endinit(void)614{615 puts("}");616}