scc

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

code.c (14206B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #include <scc/cstd.h>
      6 #include <scc/scc.h>
      7 
      8 #include "arch.h"
      9 #include "../../cc2.h"
     10 
     11 #define ADDR_LEN (INTIDENTSIZ+64)
     12 
     13 static 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), ldir(void), vastart(void),
     16             vaarg(void);
     17 
     18 static 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'},
     32 
     33 	[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'},
     39 
     40 	[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 = ldir},
     45 	[ASSTS]   =  {.fun = store,  .txt = "store", .letter = 's'},
     46 	[ASSTD]   =  {.fun = store,  .txt = "store", .letter = 'd'},
     47 
     48 	[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'},
     71 
     72 	[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'},
     95 
     96 	[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'},
    106 
    107 	[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'},
    117 
    118 	[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 	[ASEXTWL] =  {.fun = unary, .txt = "extsw", .letter = 'l'},
    125 	[ASUEXTWL]=  {.fun = unary, .txt = "extuw", .letter = 'l'},
    126 
    127 	[ASSTOL] = {.fun = unary, .txt = "stosi", .letter = 'l'},
    128 	[ASSTOW] = {.fun = unary, .txt = "stosi", .letter = 'w'},
    129 	[ASDTOL] = {.fun = unary, .txt = "dtosi", .letter = 'l'},
    130 	[ASDTOW] = {.fun = unary, .txt = "dtosi", .letter = 'w'},
    131 
    132 	[ASSWTOD] = {.fun = unary, .txt = "swtof", .letter = 'd'},
    133 	[ASSWTOS] = {.fun = unary, .txt = "swtof", .letter = 's'},
    134 	[ASSLTOD] = {.fun = unary, .txt = "sltof", .letter = 'd'},
    135 	[ASSLTOS] = {.fun = unary, .txt = "sltof", .letter = 's'},
    136 
    137 	[ASEXTS] = {.fun = unary, .txt = "exts", .letter = 'd'},
    138 	[ASTRUNCD] = {.fun = unary, .txt = "truncd", .letter = 's'},
    139 
    140 	[ASBRANCH] = {.fun = branch},
    141 	[ASJMP]  = {.fun = jmp},
    142 	[ASRET]  = {.fun = ret},
    143 	[ASCALL] = {.fun = call},
    144 	[ASCALLE] = {.fun = ecall, .txt = ")"},
    145 	[ASCALLEX] = {.fun = ecall, .txt = ", ...)"},
    146 	[ASPAR] = {.fun = param, .txt = "%s %s, "},
    147 	[ASPARE] = {.fun = param, .txt = "%s %s"},
    148 	[ASALLOC] = {.fun = asalloc},
    149 	[ASFORM] = {.fun = form2local},
    150 
    151 	[ASVSTAR] = {.fun = vastart},
    152 	[ASVARG] = {.fun = vaarg},
    153 };
    154 
    155 static char buff[ADDR_LEN];
    156 /*
    157  * : is for user-defined Aggregate Types
    158  * $ is for globals (represented by a pointer)
    159  * % is for function-scope temporaries
    160  * @ is for block labels
    161  */
    162 static char
    163 sigil(Symbol *sym)
    164 {
    165 	switch (sym->kind) {
    166 	case SEXTRN:
    167 	case SGLOB:
    168 	case SPRIV:
    169 	case SLOCAL:
    170 		return '$';
    171 	case SAUTO:
    172 	case STMP:
    173 		return '%';
    174 	case SLABEL:
    175 		return '@';
    176 	default:
    177 		abort();
    178 	}
    179 }
    180 
    181 static char *
    182 symname(Symbol *sym)
    183 {
    184 	char c = sigil(sym);
    185 
    186 	if (sym->name) {
    187 		switch (sym->kind) {
    188 		case SEXTRN:
    189 		case SGLOB:
    190 			sprintf(buff, "%c%s", c, sym->name);
    191 			return buff;
    192 		case SLOCAL:
    193 		case SPRIV:
    194 		case SAUTO:
    195 			sprintf(buff, "%c%s.%u", c, sym->name, sym->id);
    196 			return buff;
    197 		default:
    198 			abort();
    199 		}
    200 	}
    201 	sprintf(buff, "%c.%u", c, sym->numid);
    202 
    203 	return buff;
    204 }
    205 
    206 static void
    207 emitconst(Node *np)
    208 {
    209 	switch (np->type.size) {
    210 	case 1:
    211 		printf("%d", (int) np->u.i & 0xFF);
    212 		break;
    213 	case 2:
    214 		printf("%d", (int) np->u.i & 0xFFFF);
    215 		break;
    216 	case 4:
    217 		printf("%ld", (long) np->u.i & 0xFFFFFFFF);
    218 		break;
    219         case 8:
    220                 printf("%lld", (long long) np->u.i);
    221                 break;
    222 	default:
    223 		abort();
    224 	}
    225 }
    226 
    227 static void
    228 emittree(Node *np)
    229 {
    230 	if (!np)
    231 		return;
    232 
    233 	switch (np->op) {
    234 	case OSTRING:
    235 		printf("\"%s\"", np->u.s);
    236 		free(np->u.s);
    237 		np->u.s = NULL;
    238 		break;
    239 	case OCONST:
    240 		emitconst(np);
    241 		break;
    242 	case OADDR:
    243 		emittree(np->left);
    244 		break;
    245 	case OMEM:
    246 		fputs(symname(np->u.sym), stdout);
    247 		break;
    248 	default:
    249 		emittree(np->left);
    250 		printf(" %c ", np->op);
    251 		emittree(np->right);
    252 		break;
    253 	}
    254 }
    255 
    256 static char *
    257 size2asm(Type *tp)
    258 {
    259 	if (tp->flags & STRF) {
    260 		return "b";
    261 	} else if (tp->flags & INTF) {
    262 		switch (tp->size) {
    263 		case 1:
    264 			return "b";
    265 		case 2:
    266 			return "h";
    267 		case 4:
    268 			return "w";
    269 		case 8:
    270 			return "l";
    271 		}
    272 	} else if (tp->flags & FLOATF) {
    273 		if (tp->size == 4)
    274 			return "s";
    275 		else if (tp->size == 8)
    276 			return "d";
    277 	}
    278 	abort();
    279 }
    280 
    281 void
    282 defglobal(Symbol *sym)
    283 {
    284 	if (sym->kind == SEXTRN)
    285 		return;
    286 	if (sym->kind == SGLOB)
    287 		fputs("export ", stdout);
    288 	printf("data %s = {\n", symname(sym));
    289 	if (sym->type.flags & INITF)
    290 		return;
    291 	printf("\tz\t%lu\n}\n", sym->type.size);
    292 }
    293 
    294 void
    295 defpar(Symbol *sym)
    296 {
    297 	sym->type.flags |= PARF;
    298 }
    299 
    300 void
    301 defvar(Symbol *sym)
    302 {
    303 	if (sym->kind == SREG)
    304 		sym->kind = SAUTO;
    305 }
    306 
    307 void
    308 data(Node *np)
    309 {
    310 	printf("\t%s\t", size2asm(&np->type));
    311 	emittree(np);
    312 	putchar(',');
    313 	putchar('\n');
    314 }
    315 
    316 static char *
    317 size2stack(Type *tp)
    318 {
    319 	if (tp->flags & INTF) {
    320 		switch (tp->size) {
    321 		case 1:
    322 		case 2:
    323 		case 4:
    324 			return "w";
    325 		case 8:
    326 			return "l";
    327 		}
    328 	} else if (tp->flags & FLOATF) {
    329 		if (tp->size == 4)
    330 			return "s";
    331 		else if (tp->size == 8)
    332 			return "d";
    333 	} else if (tp->size == 0) {
    334 		return "w";
    335 	}
    336 	abort();
    337 }
    338 
    339 void
    340 writeout(void)
    341 {
    342 	Symbol *p;
    343 	Type *tp;
    344 	char *sep, *name;
    345 	int haslabel = 0;
    346 
    347 	if (!curfun)
    348 		return;
    349 	if (curfun->kind == SGLOB)
    350 		fputs("export ", stdout);
    351 	printf("function %s %s(", size2stack(&curfun->rtype), symname(curfun));
    352 
    353 	/* declare formal parameters */
    354 	for (sep = "", p = locals; p; p = p->next, sep = ",") {
    355 		if ((p->type.flags & PARF) == 0)
    356 			break;
    357 		printf("%s%s %s.val", sep, size2stack(&p->type), symname(p));
    358 	}
    359 	printf("%s)\n{\n", (curfun->type.flags&ELLIPS) ? ", ..." : "");
    360 
    361 	/* emit assembler instructions */
    362 	for (pc = prog; pc; pc = pc->next) {
    363 		if (pc->label) {
    364 			haslabel = 1;
    365 			printf("%s\n", symname(pc->label));
    366 		}
    367 		if (!pc->op)
    368 			continue;
    369 		if (pc->flags&BBENTRY && !haslabel)
    370 			printf("%s\n", symname(newlabel()));
    371 		(*optbl[pc->op].fun)();
    372 		if (!pc->label)
    373 			haslabel = 0;
    374 	}
    375 
    376 	puts("}");
    377 }
    378 
    379 static char *
    380 addr2txt(Addr *a)
    381 {
    382 	switch (a->kind) {
    383 	case SCONST:
    384 		sprintf(buff, "%llu", (unsigned long long) a->u.i);
    385 		return buff;
    386 	case SAUTO:
    387 	case SLABEL:
    388 	case STMP:
    389 	case SGLOB:
    390 	case SEXTRN:
    391 	case SPRIV:
    392 	case SLOCAL:
    393 		return symname(a->u.sym);
    394 	default:
    395 		abort();
    396 	}
    397 }
    398 
    399 static void
    400 binary(void)
    401 {
    402 	struct opdata *p = &optbl[pc->op];
    403 	char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
    404 
    405 	strcpy(to, addr2txt(&pc->to));
    406 	strcpy(from1, addr2txt(&pc->from1));
    407 	strcpy(from2, addr2txt(&pc->from2));
    408 	printf("\t%s =%c\t%s\t%s,%s\n", to, p->letter, p->txt, from1, from2);
    409 }
    410 
    411 static void
    412 ldir(void)
    413 {
    414 	struct opdata *p = &optbl[pc->op];
    415 	char to[ADDR_LEN], from[ADDR_LEN];
    416 	/* TODO: what type do we use for the size? */
    417 
    418 	/* TODO: it is pending */
    419 }
    420 
    421 static void
    422 store(void)
    423 {
    424 	struct opdata *p = &optbl[pc->op];
    425 	char to[ADDR_LEN], from[ADDR_LEN];
    426 
    427 	strcpy(to, addr2txt(&pc->to));
    428 	strcpy(from, addr2txt(&pc->from1));
    429 	printf("\t\t%s%c\t%s,%s\n", p->txt, p->letter, from, to);
    430 }
    431 
    432 static void
    433 unary(void)
    434 {
    435 	struct opdata *p = &optbl[pc->op];
    436 	char to[ADDR_LEN], from[ADDR_LEN];
    437 
    438 	strcpy(to, addr2txt(&pc->to));
    439 	strcpy(from, addr2txt(&pc->from1));
    440 	printf("\t%s =%c\t%s\t%s\n", to, p->letter, p->txt, from);
    441 }
    442 
    443 static void
    444 call(void)
    445 {
    446 	struct opdata *p = &optbl[pc->op];
    447 	char to[ADDR_LEN], from[ADDR_LEN];
    448 	Symbol *sym = pc->to.u.sym;
    449 
    450 	strcpy(to, addr2txt(&pc->to));
    451 	strcpy(from, addr2txt(&pc->from1));
    452 	printf("\t%s =%s\tcall\t%s(",
    453 	       to, size2stack(&sym->type), from);
    454 }
    455 
    456 static void
    457 param(void)
    458 {
    459 	Symbol *sym = pc->from2.u.sym;
    460 
    461 	printf(optbl[pc->op].txt,
    462 	       size2stack(&sym->type), addr2txt(&pc->from1));
    463 }
    464 
    465 static void
    466 ecall(void)
    467 {
    468 	struct opdata *p = &optbl[pc->op];
    469 
    470 	puts(p->txt);
    471 }
    472 
    473 static void
    474 ret(void)
    475 {
    476 	if (pc->from1.kind == SNONE)
    477 		puts("\t\tret");
    478 	else
    479 		printf("\t\tret\t%s\n", addr2txt(&pc->from1));
    480 }
    481 
    482 static void
    483 jmp(void)
    484 {
    485 	printf("\t\tjmp\t%s\n", addr2txt(&pc->from1));
    486 }
    487 
    488 static void
    489 branch(void)
    490 {
    491 	char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
    492 
    493 	strcpy(to, addr2txt(&pc->to));
    494 	strcpy(from1, addr2txt(&pc->from1));
    495 	strcpy(from2, addr2txt(&pc->from2));
    496 	printf("\t\tjnz\t%s,%s,%s\n", to, from1, from2);
    497 }
    498 
    499 static void
    500 vastart(void)
    501 {
    502 	printf("\t\tvastart %s\n", addr2txt(&pc->from1));
    503 }
    504 
    505 static void
    506 vaarg(void)
    507 {
    508 	Symbol *sym = pc->to.u.sym;
    509 	Type *tp = &sym->type;
    510 	char to[ADDR_LEN], from[ADDR_LEN];
    511 
    512 	strcpy(to, addr2txt(&pc->to));
    513 	strcpy(from, addr2txt(&pc->from1));
    514 	printf("\t\t%s =%s vaarg %s\n", to, size2asm(tp), from);
    515 }
    516 
    517 static void
    518 asalloc(void)
    519 {
    520 	Symbol *sym = pc->to.u.sym;
    521 	Type *tp = &sym->type;
    522 	extern Type ptrtype;
    523 
    524 	printf("\t%s =%s\talloc%lu\t%lu\n",
    525 	       symname(sym), size2asm(&ptrtype), tp->align+3 & ~3, tp->size);
    526 }
    527 
    528 static void
    529 form2local(void)
    530 {
    531 	Symbol *sym = pc->to.u.sym;
    532 	Type *tp = &sym->type;
    533 	char *name = symname(sym);
    534 
    535 	printf("\t\tstore%s\t%s.val,%s\n", size2asm(tp), name, name);
    536 }
    537 
    538 void
    539 endinit(void)
    540 {
    541 	puts("}");
    542 }
    543 
    544 void
    545 getbblocks(void)
    546 {
    547 	Inst *i;
    548 
    549 	if (!prog)
    550 		return;
    551 
    552 	prog->flags |= BBENTRY;
    553 	for (pc = prog; pc; pc = pc->next) {
    554 		switch (pc->op) {
    555 		case ASBRANCH:
    556 			i = pc->from2.u.sym->u.inst;
    557 			i->flags |= BBENTRY;
    558 		case ASJMP:
    559 			i = pc->from1.u.sym->u.inst;
    560 			i->flags |= BBENTRY;
    561 		case ASRET:
    562 			if (pc->next)
    563 				pc->next->flags |= BBENTRY;
    564 			break;
    565 		}
    566 	}
    567 }