scc

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

code.c (14264B)


      1 static char sccsid[] = "@(#) ./cc2/arch/qbe/code.c";
      2 
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 
      7 #include <cstd.h>
      8 #include "arch.h"
      9 #include "../../../inc/scc.h"
     10 #include "../../cc2.h"
     11 
     12 #define ADDR_LEN (INTIDENTSIZ+64)
     13 
     14 static void binary(void), unary(void), store(void), jmp(void), ret(void),
     15             branch(void), call(void), ecall(void), param(void),
     16             asalloc(void), form2local(void), ldir(void), vastart(void),
     17             vaarg(void);
     18 
     19 static struct opdata {
     20 	void (*fun)(void);
     21 	char *txt;
     22 	char letter;
     23 } optbl [] = {
     24 	[ASLDSB]  =  {.fun = unary,  .txt = "loadsb", .letter = 'w'},
     25 	[ASLDUB]  =  {.fun = unary,  .txt = "loadub", .letter = 'w'},
     26 	[ASLDSH]  =  {.fun = unary,  .txt = "loadsh", .letter = 'w'},
     27 	[ASLDUH]  =  {.fun = unary,  .txt = "loaduh", .letter = 'w'},
     28 	[ASLDSW]  =  {.fun = unary,  .txt = "loadsw", .letter = 'w'},
     29 	[ASLDUW]  =  {.fun = unary,  .txt = "loaduw", .letter = 'w'},
     30 	[ASLDL]   =  {.fun = unary,  .txt = "loadl", .letter = 'l'},
     31 	[ASLDS]   =  {.fun = unary,  .txt = "loads", .letter = 's'},
     32 	[ASLDD]   =  {.fun = unary,  .txt = "loadd", .letter = 'd'},
     33 
     34 	[ASCOPYB] =  {.fun = unary,  .txt = "copy", .letter = 'b'},
     35 	[ASCOPYH] =  {.fun = unary,  .txt = "copy", .letter = 'h'},
     36 	[ASCOPYW] =  {.fun = unary,  .txt = "copy", .letter = 'w'},
     37 	[ASCOPYL] =  {.fun = unary,  .txt = "copy", .letter = 'l'},
     38 	[ASCOPYS] =  {.fun = unary,  .txt = "copy", .letter = 's'},
     39 	[ASCOPYD] =  {.fun = unary,  .txt = "copy", .letter = 'd'},
     40 
     41 	[ASSTB]   =  {.fun = store,  .txt = "store", .letter = 'b'},
     42 	[ASSTH]   =  {.fun = store,  .txt = "store", .letter = 'h'},
     43 	[ASSTW]   =  {.fun = store,  .txt = "store", .letter = 'w'},
     44 	[ASSTL]   =  {.fun = store,  .txt = "store", .letter = 'l'},
     45 	[ASSTM]   =  {.fun = ldir},
     46 	[ASSTS]   =  {.fun = store,  .txt = "store", .letter = 's'},
     47 	[ASSTD]   =  {.fun = store,  .txt = "store", .letter = 'd'},
     48 
     49 	[ASADDW]  =  {.fun = binary, .txt = "add", .letter = 'w'},
     50 	[ASSUBW]  =  {.fun = binary, .txt = "sub", .letter = 'w'},
     51 	[ASMULW]  =  {.fun = binary, .txt = "mul", .letter = 'w'},
     52 	[ASMODW]  =  {.fun = binary, .txt = "rem", .letter = 'w'},
     53 	[ASUMODW] =  {.fun = binary, .txt = "urem", .letter = 'w'},
     54 	[ASDIVW]  =  {.fun = binary, .txt = "div", .letter = 'w'},
     55 	[ASUDIVW] =  {.fun = binary, .txt = "udiv", .letter = 'w'},
     56 	[ASSHLW]  =  {.fun = binary, .txt = "shl", .letter = 'w'},
     57 	[ASSHRW]  =  {.fun = binary, .txt = "sar", .letter = 'w'},
     58 	[ASUSHRW] =  {.fun = binary, .txt = "shr", .letter = 'w'},
     59 	[ASLTW]   =  {.fun = binary, .txt = "csltw", .letter = 'w'},
     60 	[ASULTW]  =  {.fun = binary, .txt = "cultw", .letter = 'w'},
     61 	[ASGTW]   =  {.fun = binary, .txt = "csgtw", .letter = 'w'},
     62 	[ASUGTW]  =  {.fun = binary, .txt = "cugtw", .letter = 'w'},
     63 	[ASLEW]   =  {.fun = binary, .txt = "cslew", .letter = 'w'},
     64 	[ASULEW]  =  {.fun = binary, .txt = "culew", .letter = 'w'},
     65 	[ASGEW]   =  {.fun = binary, .txt = "csgew", .letter = 'w'},
     66 	[ASUGEW]  =  {.fun = binary, .txt = "cugew", .letter = 'w'},
     67 	[ASEQW]   =  {.fun = binary, .txt = "ceqw", .letter = 'w'},
     68 	[ASNEW]   =  {.fun = binary, .txt = "cnew", .letter = 'w'},
     69 	[ASBANDW] =  {.fun = binary, .txt = "and", .letter = 'w'},
     70 	[ASBORW]  =  {.fun = binary, .txt = "or", .letter = 'w'},
     71 	[ASBXORW] =  {.fun = binary, .txt = "xor", .letter = 'w'},
     72 
     73 	[ASADDL]  =  {.fun = binary, .txt = "add", .letter = 'l'},
     74 	[ASSUBL]  =  {.fun = binary, .txt = "sub", .letter = 'l'},
     75 	[ASMULL]  =  {.fun = binary, .txt = "mul", .letter = 'l'},
     76 	[ASMODL]  =  {.fun = binary, .txt = "rem", .letter = 'l'},
     77 	[ASUMODL] =  {.fun = binary, .txt = "urem", .letter = 'l'},
     78 	[ASDIVL]  =  {.fun = binary, .txt = "div", .letter = 'l'},
     79 	[ASUDIVL] =  {.fun = binary, .txt = "udiv", .letter = 'l'},
     80 	[ASSHLL]  =  {.fun = binary, .txt = "shl", .letter = 'l'},
     81 	[ASSHRL]  =  {.fun = binary, .txt = "sar", .letter = 'l'},
     82 	[ASUSHRL] =  {.fun = binary, .txt = "shr", .letter = 'l'},
     83 	[ASLTL]   =  {.fun = binary, .txt = "csltl", .letter = 'w'},
     84 	[ASULTL]  =  {.fun = binary, .txt = "cultl", .letter = 'w'},
     85 	[ASGTL]   =  {.fun = binary, .txt = "csgtl", .letter = 'w'},
     86 	[ASUGTL]  =  {.fun = binary, .txt = "cugtl", .letter = 'w'},
     87 	[ASLEL]   =  {.fun = binary, .txt = "cslel", .letter = 'w'},
     88 	[ASULEL]  =  {.fun = binary, .txt = "culel", .letter = 'w'},
     89 	[ASGEL]   =  {.fun = binary, .txt = "csgel", .letter = 'w'},
     90 	[ASUGEL]  =  {.fun = binary, .txt = "cugel", .letter = 'w'},
     91 	[ASEQL]   =  {.fun = binary, .txt = "ceql", .letter = 'w'},
     92 	[ASNEL]   =  {.fun = binary, .txt = "cnel", .letter = 'w'},
     93 	[ASBANDL] =  {.fun = binary, .txt = "and", .letter = 'l'},
     94 	[ASBORL]  =  {.fun = binary, .txt = "or", .letter = 'l'},
     95 	[ASBXORL] =  {.fun = binary, .txt = "xor", .letter = 'l'},
     96 
     97 	[ASADDS]  =  {.fun = binary, .txt = "add", .letter = 's'},
     98 	[ASSUBS]  =  {.fun = binary, .txt = "sub", .letter = 's'},
     99 	[ASMULS]  =  {.fun = binary, .txt = "mul", .letter = 's'},
    100 	[ASDIVS]  =  {.fun = binary, .txt = "div", .letter = 's'},
    101 	[ASLTS]   =  {.fun = binary, .txt = "clts", .letter = 'w'},
    102 	[ASGTS]   =  {.fun = binary, .txt = "cgts", .letter = 'w'},
    103 	[ASLES]   =  {.fun = binary, .txt = "cles", .letter = 'w'},
    104 	[ASGES]   =  {.fun = binary, .txt = "cges", .letter = 'w'},
    105 	[ASEQS]   =  {.fun = binary, .txt = "ceqs", .letter = 'w'},
    106 	[ASNES]   =  {.fun = binary, .txt = "cnes", .letter = 'w'},
    107 
    108 	[ASADDD]  =  {.fun = binary, .txt = "add", .letter = 'd'},
    109 	[ASSUBD]  =  {.fun = binary, .txt = "sub", .letter = 'd'},
    110 	[ASMULD]  =  {.fun = binary, .txt = "mul", .letter = 'd'},
    111 	[ASDIVD]  =  {.fun = binary, .txt = "div", .letter = 'd'},
    112 	[ASLTD]   =  {.fun = binary, .txt = "cltd", .letter = 'w'},
    113 	[ASGTD]   =  {.fun = binary, .txt = "cgtd", .letter = 'w'},
    114 	[ASLED]   =  {.fun = binary, .txt = "cled", .letter = 'w'},
    115 	[ASGED]   =  {.fun = binary, .txt = "cged", .letter = 'w'},
    116 	[ASEQD]   =  {.fun = binary, .txt = "ceqd", .letter = 'w'},
    117 	[ASNED]   =  {.fun = binary, .txt = "cned", .letter = 'w'},
    118 
    119 	[ASEXTBW] =  {.fun = unary, .txt = "extsb", .letter = 'w'},
    120 	[ASUEXTBW]=  {.fun = unary, .txt = "extub", .letter = 'w'},
    121 	[ASEXTBL] =  {.fun = unary, .txt = "extsb", .letter = 'l'},
    122 	[ASUEXTBL]=  {.fun = unary, .txt = "extub", .letter = 'l'},
    123 	[ASEXTHW] =  {.fun = unary, .txt = "extsh", .letter = 'w'},
    124 	[ASUEXTHW]=  {.fun = unary, .txt = "extuh", .letter = 'w'},
    125 	[ASEXTWL] =  {.fun = unary, .txt = "extsw", .letter = 'l'},
    126 	[ASUEXTWL]=  {.fun = unary, .txt = "extuw", .letter = 'l'},
    127 
    128 	[ASSTOL] = {.fun = unary, .txt = "stosi", .letter = 'l'},
    129 	[ASSTOW] = {.fun = unary, .txt = "stosi", .letter = 'w'},
    130 	[ASDTOL] = {.fun = unary, .txt = "dtosi", .letter = 'l'},
    131 	[ASDTOW] = {.fun = unary, .txt = "dtosi", .letter = 'w'},
    132 
    133 	[ASSWTOD] = {.fun = unary, .txt = "swtof", .letter = 'd'},
    134 	[ASSWTOS] = {.fun = unary, .txt = "swtof", .letter = 's'},
    135 	[ASSLTOD] = {.fun = unary, .txt = "sltof", .letter = 'd'},
    136 	[ASSLTOS] = {.fun = unary, .txt = "sltof", .letter = 's'},
    137 
    138 	[ASEXTS] = {.fun = unary, .txt = "exts", .letter = 'd'},
    139 	[ASTRUNCD] = {.fun = unary, .txt = "truncd", .letter = 's'},
    140 
    141 	[ASBRANCH] = {.fun = branch},
    142 	[ASJMP]  = {.fun = jmp},
    143 	[ASRET]  = {.fun = ret},
    144 	[ASCALL] = {.fun = call},
    145 	[ASCALLE] = {.fun = ecall, .txt = ")"},
    146 	[ASCALLEX] = {.fun = ecall, .txt = ", ...)"},
    147 	[ASPAR] = {.fun = param, .txt = "%s %s, "},
    148 	[ASPARE] = {.fun = param, .txt = "%s %s"},
    149 	[ASALLOC] = {.fun = asalloc},
    150 	[ASFORM] = {.fun = form2local},
    151 
    152 	[ASVSTAR] = {.fun = vastart},
    153 	[ASVARG] = {.fun = vaarg},
    154 };
    155 
    156 static char buff[ADDR_LEN];
    157 /*
    158  * : is for user-defined Aggregate Types
    159  * $ is for globals (represented by a pointer)
    160  * % is for function-scope temporaries
    161  * @ is for block labels
    162  */
    163 static char
    164 sigil(Symbol *sym)
    165 {
    166 	switch (sym->kind) {
    167 	case SEXTRN:
    168 	case SGLOB:
    169 	case SPRIV:
    170 	case SLOCAL:
    171 		return '$';
    172 	case SAUTO:
    173 	case STMP:
    174 		return '%';
    175 	case SLABEL:
    176 		return '@';
    177 	default:
    178 		abort();
    179 	}
    180 }
    181 
    182 static char *
    183 symname(Symbol *sym)
    184 {
    185 	char c = sigil(sym);
    186 
    187 	if (sym->name) {
    188 		switch (sym->kind) {
    189 		case SEXTRN:
    190 		case SGLOB:
    191 			sprintf(buff, "%c%s", c, sym->name);
    192 			return buff;
    193 		case SLOCAL:
    194 		case SPRIV:
    195 		case SAUTO:
    196 			sprintf(buff, "%c%s.%u", c, sym->name, sym->id);
    197 			return buff;
    198 		default:
    199 			abort();
    200 		}
    201 	}
    202 	sprintf(buff, "%c.%u", c, sym->numid);
    203 
    204 	return buff;
    205 }
    206 
    207 static void
    208 emitconst(Node *np)
    209 {
    210 	switch (np->type.size) {
    211 	case 1:
    212 		printf("%d", (int) np->u.i & 0xFF);
    213 		break;
    214 	case 2:
    215 		printf("%d", (int) np->u.i & 0xFFFF);
    216 		break;
    217 	case 4:
    218 		printf("%ld", (long) np->u.i & 0xFFFFFFFF);
    219 		break;
    220         case 8:
    221                 printf("%lld", (long long) np->u.i);
    222                 break;
    223 	default:
    224 		abort();
    225 	}
    226 }
    227 
    228 static void
    229 emittree(Node *np)
    230 {
    231 	if (!np)
    232 		return;
    233 
    234 	switch (np->op) {
    235 	case OSTRING:
    236 		printf("\"%s\"", np->u.s);
    237 		free(np->u.s);
    238 		np->u.s = NULL;
    239 		break;
    240 	case OCONST:
    241 		emitconst(np);
    242 		break;
    243 	case OADDR:
    244 		emittree(np->left);
    245 		break;
    246 	case OMEM:
    247 		fputs(symname(np->u.sym), stdout);
    248 		break;
    249 	default:
    250 		emittree(np->left);
    251 		printf(" %c ", np->op);
    252 		emittree(np->right);
    253 		break;
    254 	}
    255 }
    256 
    257 static char *
    258 size2asm(Type *tp)
    259 {
    260 	if (tp->flags & STRF) {
    261 		return "b";
    262 	} else if (tp->flags & INTF) {
    263 		switch (tp->size) {
    264 		case 1:
    265 			return "b";
    266 		case 2:
    267 			return "h";
    268 		case 4:
    269 			return "w";
    270 		case 8:
    271 			return "l";
    272 		}
    273 	} else if (tp->flags & FLOATF) {
    274 		if (tp->size == 4)
    275 			return "s";
    276 		else if (tp->size == 8)
    277 			return "d";
    278 	}
    279 	abort();
    280 }
    281 
    282 void
    283 defglobal(Symbol *sym)
    284 {
    285 	if (sym->kind == SEXTRN)
    286 		return;
    287 	if (sym->kind == SGLOB)
    288 		fputs("export ", stdout);
    289 	printf("data %s = {\n", symname(sym));
    290 	if (sym->type.flags & INITF)
    291 		return;
    292 	printf("\tz\t%lu\n}\n", sym->type.size);
    293 }
    294 
    295 void
    296 defpar(Symbol *sym)
    297 {
    298 	sym->type.flags |= PARF;
    299 }
    300 
    301 void
    302 defvar(Symbol *sym)
    303 {
    304 	if (sym->kind == SREG)
    305 		sym->kind = SAUTO;
    306 }
    307 
    308 void
    309 data(Node *np)
    310 {
    311 	printf("\t%s\t", size2asm(&np->type));
    312 	emittree(np);
    313 	putchar(',');
    314 	putchar('\n');
    315 }
    316 
    317 static char *
    318 size2stack(Type *tp)
    319 {
    320 	if (tp->flags & INTF) {
    321 		switch (tp->size) {
    322 		case 1:
    323 		case 2:
    324 		case 4:
    325 			return "w";
    326 		case 8:
    327 			return "l";
    328 		}
    329 	} else if (tp->flags & FLOATF) {
    330 		if (tp->size == 4)
    331 			return "s";
    332 		else if (tp->size == 8)
    333 			return "d";
    334 	} else if (tp->size == 0) {
    335 		return "w";
    336 	}
    337 	abort();
    338 }
    339 
    340 void
    341 writeout(void)
    342 {
    343 	Symbol *p;
    344 	Type *tp;
    345 	char *sep, *name;
    346 	int haslabel = 0;
    347 
    348 	if (!curfun)
    349 		return;
    350 	if (curfun->kind == SGLOB)
    351 		fputs("export ", stdout);
    352 	printf("function %s %s(", size2stack(&curfun->rtype), symname(curfun));
    353 
    354 	/* declare formal parameters */
    355 	for (sep = "", p = locals; p; p = p->next, sep = ",") {
    356 		if ((p->type.flags & PARF) == 0)
    357 			break;
    358 		printf("%s%s %s.val", sep, size2stack(&p->type), symname(p));
    359 	}
    360 	printf("%s)\n{\n", (curfun->type.flags&ELLIPS) ? ", ..." : "");
    361 
    362 	/* emit assembler instructions */
    363 	for (pc = prog; pc; pc = pc->next) {
    364 		if (pc->label) {
    365 			haslabel = 1;
    366 			printf("%s\n", symname(pc->label));
    367 		}
    368 		if (!pc->op)
    369 			continue;
    370 		if (pc->flags&BBENTRY && !haslabel)
    371 			printf("%s\n", symname(newlabel()));
    372 		(*optbl[pc->op].fun)();
    373 		if (!pc->label)
    374 			haslabel = 0;
    375 	}
    376 
    377 	puts("}");
    378 }
    379 
    380 static char *
    381 addr2txt(Addr *a)
    382 {
    383 	switch (a->kind) {
    384 	case SCONST:
    385 		sprintf(buff, "%llu", (unsigned long long) a->u.i);
    386 		return buff;
    387 	case SAUTO:
    388 	case SLABEL:
    389 	case STMP:
    390 	case SGLOB:
    391 	case SEXTRN:
    392 	case SPRIV:
    393 	case SLOCAL:
    394 		return symname(a->u.sym);
    395 	default:
    396 		abort();
    397 	}
    398 }
    399 
    400 static void
    401 binary(void)
    402 {
    403 	struct opdata *p = &optbl[pc->op];
    404 	char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
    405 
    406 	strcpy(to, addr2txt(&pc->to));
    407 	strcpy(from1, addr2txt(&pc->from1));
    408 	strcpy(from2, addr2txt(&pc->from2));
    409 	printf("\t%s =%c\t%s\t%s,%s\n", to, p->letter, p->txt, from1, from2);
    410 }
    411 
    412 static void
    413 ldir(void)
    414 {
    415 	struct opdata *p = &optbl[pc->op];
    416 	char to[ADDR_LEN], from[ADDR_LEN];
    417 	/* TODO: what type do we use for the size? */
    418 
    419 	/* TODO: it is pending */
    420 }
    421 
    422 static void
    423 store(void)
    424 {
    425 	struct opdata *p = &optbl[pc->op];
    426 	char to[ADDR_LEN], from[ADDR_LEN];
    427 
    428 	strcpy(to, addr2txt(&pc->to));
    429 	strcpy(from, addr2txt(&pc->from1));
    430 	printf("\t\t%s%c\t%s,%s\n", p->txt, p->letter, from, to);
    431 }
    432 
    433 static void
    434 unary(void)
    435 {
    436 	struct opdata *p = &optbl[pc->op];
    437 	char to[ADDR_LEN], from[ADDR_LEN];
    438 
    439 	strcpy(to, addr2txt(&pc->to));
    440 	strcpy(from, addr2txt(&pc->from1));
    441 	printf("\t%s =%c\t%s\t%s\n", to, p->letter, p->txt, from);
    442 }
    443 
    444 static void
    445 call(void)
    446 {
    447 	struct opdata *p = &optbl[pc->op];
    448 	char to[ADDR_LEN], from[ADDR_LEN];
    449 	Symbol *sym = pc->to.u.sym;
    450 
    451 	strcpy(to, addr2txt(&pc->to));
    452 	strcpy(from, addr2txt(&pc->from1));
    453 	printf("\t%s =%s\tcall\t%s(",
    454 	       to, size2stack(&sym->type), from);
    455 }
    456 
    457 static void
    458 param(void)
    459 {
    460 	Symbol *sym = pc->from2.u.sym;
    461 
    462 	printf(optbl[pc->op].txt,
    463 	       size2stack(&sym->type), addr2txt(&pc->from1));
    464 }
    465 
    466 static void
    467 ecall(void)
    468 {
    469 	struct opdata *p = &optbl[pc->op];
    470 
    471 	puts(p->txt);
    472 }
    473 
    474 static void
    475 ret(void)
    476 {
    477 	if (pc->from1.kind == SNONE)
    478 		puts("\t\tret");
    479 	else
    480 		printf("\t\tret\t%s\n", addr2txt(&pc->from1));
    481 }
    482 
    483 static void
    484 jmp(void)
    485 {
    486 	printf("\t\tjmp\t%s\n", addr2txt(&pc->from1));
    487 }
    488 
    489 static void
    490 branch(void)
    491 {
    492 	char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
    493 
    494 	strcpy(to, addr2txt(&pc->to));
    495 	strcpy(from1, addr2txt(&pc->from1));
    496 	strcpy(from2, addr2txt(&pc->from2));
    497 	printf("\t\tjnz\t%s,%s,%s\n", to, from1, from2);
    498 }
    499 
    500 static void
    501 vastart(void)
    502 {
    503 	printf("\t\tvastart %s\n", addr2txt(&pc->from1));
    504 }
    505 
    506 static void
    507 vaarg(void)
    508 {
    509 	Symbol *sym = pc->to.u.sym;
    510 	Type *tp = &sym->type;
    511 	char to[ADDR_LEN], from[ADDR_LEN];
    512 
    513 	strcpy(to, addr2txt(&pc->to));
    514 	strcpy(from, addr2txt(&pc->from1));
    515 	printf("\t\t%s =%s vaarg %s\n", to, size2asm(tp), from);
    516 }
    517 
    518 static void
    519 asalloc(void)
    520 {
    521 	Symbol *sym = pc->to.u.sym;
    522 	Type *tp = &sym->type;
    523 	extern Type ptrtype;
    524 
    525 	printf("\t%s =%s\talloc%lu\t%lu\n",
    526 	       symname(sym), size2asm(&ptrtype), tp->align+3 & ~3, tp->size);
    527 }
    528 
    529 static void
    530 form2local(void)
    531 {
    532 	Symbol *sym = pc->to.u.sym;
    533 	Type *tp = &sym->type;
    534 	char *name = symname(sym);
    535 
    536 	printf("\t\tstore%s\t%s.val,%s\n", size2asm(tp), name, name);
    537 }
    538 
    539 void
    540 endinit(void)
    541 {
    542 	puts("}");
    543 }
    544 
    545 void
    546 getbblocks(void)
    547 {
    548 	Inst *i;
    549 
    550 	if (!prog)
    551 		return;
    552 
    553 	prog->flags |= BBENTRY;
    554 	for (pc = prog; pc; pc = pc->next) {
    555 		switch (pc->op) {
    556 		case ASBRANCH:
    557 			i = pc->from2.u.sym->u.inst;
    558 			i->flags |= BBENTRY;
    559 		case ASJMP:
    560 			i = pc->from1.u.sym->u.inst;
    561 			i->flags |= BBENTRY;
    562 		case ASRET:
    563 			if (pc->next)
    564 				pc->next->flags |= BBENTRY;
    565 			break;
    566 		}
    567 	}
    568 }