code.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
code.c (15519B)
---
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 %s %s(", size2stack(&curfun->rtype), symname(curfun));
415
416 /* declare formal parameters */
417 sep = "";
418 for (p = locals; p; p = p->next) {
419 if ((p->type.flags & PARF) == 0)
420 continue;
421 printf("%s%s %s%s",
422 sep, size2stack(&p->type),
423 symname(p),
424 (p->type.flags & AGGRF) ? "" : ".val");
425 sep = ",";
426 }
427 printf("%s)\n{\n", (curfun->type.flags&ELLIPS) ? ", ..." : "");
428
429 /* emit assembler instructions */
430 for (pc = prog; pc; pc = pc->next) {
431 if (pc->label) {
432 haslabel = 1;
433 printf("%s\n", symname(pc->label));
434 }
435 if (pc->op == ASLABEL)
436 continue;
437 if (pc->flags&BBENTRY && !haslabel)
438 printf("%s\n", symname(newlabel()));
439 (*optbl[pc->op].fun)();
440 if (!pc->label)
441 haslabel = 0;
442 }
443
444 puts("}");
445 }
446
447 static char *
448 addr2txt(Addr *a)
449 {
450 switch (a->kind) {
451 case SCONST:
452 sprintf(buff, "%llu", (unsigned long long) a->u.i);
453 return buff;
454 case SAUTO:
455 case SLABEL:
456 case STMP:
457 case SGLOB:
458 case SEXTRN:
459 case SPRIV:
460 case SLOCAL:
461 return symname(a->u.sym);
462 default:
463 abort();
464 }
465 }
466
467 static void
468 binary(void)
469 {
470 struct opdata *p = &optbl[pc->op];
471 char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
472
473 strcpy(to, addr2txt(&pc->to));
474 strcpy(from1, addr2txt(&pc->from1));
475 strcpy(from2, addr2txt(&pc->from2));
476 printf("\t%s =%c\t%s\t%s,%s\n", to, p->letter, p->txt, from1, from2);
477 }
478
479 static void
480 blit(void)
481 {
482 Type *tp = &pc->to.u.sym->type;
483 char to[ADDR_LEN], from[ADDR_LEN];
484
485 strcpy(to, addr2txt(&pc->to));
486 strcpy(from, addr2txt(&pc->from1));
487 printf("\t\tblit\t%s,%s,%lu\n", from, to, tp->size);
488 }
489
490 static void
491 store(void)
492 {
493 struct opdata *p = &optbl[pc->op];
494 char to[ADDR_LEN], from[ADDR_LEN];
495
496 strcpy(to, addr2txt(&pc->to));
497 strcpy(from, addr2txt(&pc->from1));
498 printf("\t\t%s%c\t%s,%s\n", p->txt, p->letter, from, to);
499 }
500
501 static void
502 unary(void)
503 {
504 struct opdata *p = &optbl[pc->op];
505 char to[ADDR_LEN], from[ADDR_LEN];
506
507 strcpy(to, addr2txt(&pc->to));
508 strcpy(from, addr2txt(&pc->from1));
509 printf("\t%s =%c\t%s\t%s\n", to, p->letter, p->txt, from);
510 }
511
512 static void
513 call(void)
514 {
515 char to[ADDR_LEN], from[ADDR_LEN];
516 Symbol *sym = pc->to.u.sym;
517
518 strcpy(to, addr2txt(&pc->to));
519 strcpy(from, addr2txt(&pc->from1));
520 printf("\t%s =%s\tcall\t%s(",
521 to, size2stack(&sym->type), from);
522 }
523
524 static void
525 param(void)
526 {
527 Symbol *sym = pc->from2.u.sym;
528
529 printf(optbl[pc->op].txt,
530 size2stack(&sym->type), addr2txt(&pc->from1));
531 }
532
533 static void
534 ecall(void)
535 {
536 struct opdata *p = &optbl[pc->op];
537
538 puts(p->txt);
539 }
540
541 static void
542 ret(void)
543 {
544 if (pc->from1.kind == SNONE)
545 puts("\t\tret");
546 else
547 printf("\t\tret\t%s\n", addr2txt(&pc->from1));
548 }
549
550 static void
551 jmp(void)
552 {
553 printf("\t\tjmp\t%s\n", addr2txt(&pc->from1));
554 }
555
556 static void
557 branch(void)
558 {
559 char to[ADDR_LEN], from1[ADDR_LEN], from2[ADDR_LEN];
560
561 strcpy(to, addr2txt(&pc->to));
562 strcpy(from1, addr2txt(&pc->from1));
563 strcpy(from2, addr2txt(&pc->from2));
564 printf("\t\tjnz\t%s,%s,%s\n", to, from1, from2);
565 }
566
567 static void
568 vastart(void)
569 {
570 printf("\t\tvastart %s\n", addr2txt(&pc->from1));
571 }
572
573 static void
574 vaarg(void)
575 {
576 Symbol *sym = pc->to.u.sym;
577 Type *tp = &sym->type;
578 char to[ADDR_LEN], from[ADDR_LEN];
579
580 strcpy(to, addr2txt(&pc->to));
581 strcpy(from, addr2txt(&pc->from1));
582 printf("\t\t%s =%s vaarg %s\n", to, size2asm(tp), from);
583 }
584
585 static void
586 asalloc(void)
587 {
588 Symbol *sym = pc->to.u.sym;
589 Type *tp = &sym->type;
590 extern Type ptrtype;
591
592 printf("\t%s =%s\talloc%d\t%lu\n",
593 symname(sym), size2asm(&ptrtype), tp->align+3 & ~3, tp->size);
594 }
595
596 static void
597 form2local(void)
598 {
599 Symbol *sym = pc->to.u.sym;
600 Type *tp = &sym->type;
601 char *name = symname(sym);
602
603 printf("\t\tstore%s\t%s.val,%s\n", size2asm(tp), name, name);
604 }
605
606 void
607 endinit(void)
608 {
609 puts("}");
610 }