scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

code.c (14260B)


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