code.c - scc - simple c99 compiler
HTML git clone git://git.simple-cc.org/scc
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
code.c (15616B)
---
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 "../cc2.h"
9 #include "arch.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), blit(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 = blit},
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 [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'},
128
129 [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'},
137
138 [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'},
146
147 [ASEXTS] = {.fun = unary, .txt = "exts", .letter = 'd'},
148 [ASTRUNCD] = {.fun = unary, .txt = "truncd", .letter = 's'},
149
150 [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'},
154
155 [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},
165
166 [ASVSTAR] = {.fun = vastart},
167 [ASVARG] = {.fun = vaarg},
168 };
169
170 static char buff[ADDR_LEN];
171 /*
172 * : is for user-defined Aggregate Types
173 * $ is for globals (represented by a pointer)
174 * % is for function-scope temporaries
175 * @ is for block labels
176 */
177 static char
178 sigil(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 }
195
196 static char *
197 symname(Symbol *sym)
198 {
199 char c = sigil(sym);
200
201 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);
217
218 return buff;
219 }
220
221 static void
222 emitconst(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 }
241
242 static void
243 emittree(Node *np)
244 {
245 if (!np)
246 return;
247
248 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 }
270
271 static char *
272 size2asm(Type *tp)
273 {
274 static char spec[ADDR_LEN];
275
276 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 }
295
296 abort();
297 }
298
299 void
300 defglobal(Symbol *sym)
301 {
302 Type *tp = &sym->type;
303
304 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);
310
311 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 }
317
318 void
319 defpar(Symbol *sym)
320 {
321 if (sym->kind == SREG)
322 sym->kind = SAUTO;
323 sym->type.flags |= PARF;
324 }
325
326 void
327 defvar(Symbol *sym)
328 {
329 if (sym->kind == SREG)
330 sym->kind = SAUTO;
331 }
332
333 void
334 data(Node *np)
335 {
336 printf("\t%s\t", size2asm(&np->type));
337 emittree(np);
338 putchar(',');
339 putchar('\n');
340 }
341
342 static char *
343 size2stack(Type *tp)
344 {
345 static char spec[ADDR_LEN];
346
347 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 }
369
370 void
371 deftype(Type *tp)
372 {
373 printf("type :.%u = align %d { %lu }\n",
374 tp->id, tp->align, tp->size);
375 }
376
377 static void
378 getbblocks(void)
379 {
380 Inst *i;
381
382 if (!prog)
383 return;
384
385 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 }
401
402 void
403 writeout(void)
404 {
405 Symbol *p;
406 Type *tp;
407 char *sep;
408 int haslabel = 0;
409
410 getbblocks();
411
412 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));
418
419 /* 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);
433
434 /* 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 }
448
449 puts("}");
450 }
451
452 static char *
453 addr2txt(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 }
471
472 static void
473 binary(void)
474 {
475 struct opdata *p = &optbl[pc->op];
476 char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
477
478 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 }
483
484 static void
485 blit(void)
486 {
487 Type *tp = &pc->from2.u.sym->type;
488 char to[ADDR_LEN], from[ADDR_LEN];
489
490 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 }
494
495 static void
496 store(void)
497 {
498 struct opdata *p = &optbl[pc->op];
499 char to[ADDR_LEN], from[ADDR_LEN];
500
501 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 }
505
506 static void
507 unary(void)
508 {
509 struct opdata *p = &optbl[pc->op];
510 char to[ADDR_LEN], from[ADDR_LEN];
511
512 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 }
516
517 static void
518 call(void)
519 {
520 char to[ADDR_LEN], from[ADDR_LEN];
521 Symbol *sym = pc->to.u.sym;
522
523 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 }
529
530 static void
531 param(void)
532 {
533 Symbol *sym = pc->from2.u.sym;
534
535 printf(optbl[pc->op].txt,
536 size2stack(&sym->type), addr2txt(&pc->from1));
537 }
538
539 static void
540 ecall(void)
541 {
542 struct opdata *p = &optbl[pc->op];
543
544 puts(p->txt);
545 }
546
547 static void
548 ret(void)
549 {
550 if (pc->from1.kind == SNONE)
551 puts("\t\tret");
552 else
553 printf("\t\tret\t%s\n", addr2txt(&pc->from1));
554 }
555
556 static void
557 jmp(void)
558 {
559 printf("\t\tjmp\t%s\n", addr2txt(&pc->from1));
560 }
561
562 static void
563 branch(void)
564 {
565 char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
566
567 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 }
572
573 static void
574 vastart(void)
575 {
576 printf("\t\tvastart %s\n", addr2txt(&pc->from1));
577 }
578
579 static void
580 vaarg(void)
581 {
582 Symbol *sym = pc->to.u.sym;
583 Type *tp = &sym->type;
584 char to[ADDR_LEN], from[ADDR_LEN];
585
586 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 }
590
591 static void
592 asalloc(void)
593 {
594 Symbol *sym = pc->to.u.sym;
595 Type *tp = &sym->type;
596 extern Type ptrtype;
597
598 printf("\t%s =%s\talloc%d\t%lu\n",
599 symname(sym), size2asm(&ptrtype), tp->align+3 & ~3, tp->size);
600 }
601
602 static void
603 form2local(void)
604 {
605 Symbol *sym = pc->to.u.sym;
606 Type *tp = &sym->type;
607 char *name = symname(sym);
608
609 printf("\t\tstore%s\t%s.val,%s\n", size2asm(tp), name, name);
610 }
611
612 void
613 endinit(void)
614 {
615 puts("}");
616 }