cgen.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
---
cgen.c (12306B)
---
1 #include <assert.h>
2 #include <stdlib.h>
3
4 #include <scc/cstd.h>
5 #include <scc/scc.h>
6
7 #include "../cc2.h"
8 #include "arch.h"
9
10 #define I1BYTES 0
11 #define I2BYTES 1
12 #define I4BYTES 2
13 #define I8BYTES 3
14
15 static Node *cgen(Node *);
16
17 static unsigned char opasmw[][2] = {
18 [OADD] = {ASADDW, ASADDW},
19 [OSUB] = {ASSUBW, ASSUBW},
20 [OMUL] = {ASMULW, ASMULW},
21 [OMOD] = {ASMODW, ASUMODW},
22 [ODIV] = {ASDIVW, ASUDIVW},
23 [OSHL] = {ASSHLW, ASSHLW},
24 [OSHR] = {ASSHRW, ASUSHRW},
25 [OLT] = {ASLTW, ASULTW},
26 [OGT] = {ASGTW, ASUGTW},
27 [OLE] = {ASLEW, ASULEW},
28 [OGE] = {ASGEW, ASUGEW},
29 [OEQ] = {ASEQW, ASEQW},
30 [ONE] = {ASNEW, ASNEW},
31 [OBAND] = {ASBANDW, ASBANDW},
32 [OBOR] = {ASBORW, ASBORW},
33 [OBXOR] = {ASBXORW, ASBXORW},
34 [OSNEG] = {ASNEGW, ASNEGW},
35 };
36
37 static unsigned char opasml[][2] = {
38 [OADD] = {ASADDL, ASADDL},
39 [OSUB] = {ASSUBL, ASSUBL},
40 [OMUL] = {ASMULL, ASMULL},
41 [OMOD] = {ASMODL, ASUMODL},
42 [ODIV] = {ASDIVL, ASUDIVL},
43 [OSHL] = {ASSHLL, ASSHLL},
44 [OSHR] = {ASSHRL, ASUSHRL},
45 [OLT] = {ASLTL, ASULTL},
46 [OGT] = {ASGTL, ASUGTL},
47 [OLE] = {ASLEL, ASULEL},
48 [OGE] = {ASGEL, ASUGEL},
49 [OEQ] = {ASEQL, ASEQL},
50 [ONE] = {ASNEL, ASNEL},
51 [OBAND] = {ASBANDL, ASBANDL},
52 [OBOR] = {ASBORL, ASBORL},
53 [OBXOR] = {ASBXORL, ASBXORL},
54 [OSNEG] = {ASNEGL, ASNEGL},
55 };
56
57 static unsigned char opasms[][2] = {
58 [OADD] = {ASADDS, ASADDS},
59 [OSUB] = {ASSUBS, ASSUBS},
60 [OMUL] = {ASMULS, ASMULS},
61 [ODIV] = {ASDIVS, ASDIVS},
62 [OLT] = {ASLTS, ASLTS},
63 [OGT] = {ASGTS, ASGTS},
64 [OLE] = {ASLES, ASLES},
65 [OGE] = {ASGES, ASGES},
66 [OEQ] = {ASEQS, ASEQS},
67 [ONE] = {ASNES, ASNES},
68 [OSNEG] = {ASNEGS, ASNEGS},
69 };
70
71 static unsigned char opasmd[][2] = {
72 [OADD] = {ASADDD, ASADDD},
73 [OSUB] = {ASSUBD, ASSUBD},
74 [OMUL] = {ASMULD, ASMULD},
75 [ODIV] = {ASDIVD, ASDIVD},
76 [OLT] = {ASLTD, ASLTD},
77 [OGT] = {ASGTD, ASGTD},
78 [OLE] = {ASLED, ASLED},
79 [OGE] = {ASGED, ASGED},
80 [OEQ] = {ASEQD, ASEQD},
81 [ONE] = {ASNED, ASNED},
82 [OSNEG] = {ASNEGD, ASNEGD},
83 };
84
85 static unsigned char (*opbin[][2])[2] = {
86 {opasmw, opasml},
87 {opasms, opasmd},
88 };
89
90 static unsigned char i2i_conv[4][4][2] = {
91 [I1BYTES] = {
92 [I4BYTES] = {ASEXTBW, ASUEXTBW},
93 [I8BYTES] = {ASEXTBL, ASUEXTBL},
94 },
95 [I2BYTES] = {
96 [I4BYTES] = {ASEXTHW, ASUEXTHW},
97 [I8BYTES] = {ASEXTHL, ASUEXTHL},
98 },
99 [I4BYTES] = {
100 [I8BYTES] = {ASEXTWL, ASUEXTWL},
101 }
102 };
103
104 static unsigned char f2i_conv[4][4][2] = {
105 [I4BYTES] = {
106 [I4BYTES] = {ASSTOW, ASSTOUW},
107 [I8BYTES] = {ASSTOL, ASDTOUL},
108 },
109 [I8BYTES] = {
110 [I4BYTES] = {ASDTOW, ASDTOUW},
111 [I8BYTES] = {ASDTOL, ASDTOUL},
112 }
113 };
114
115 static unsigned char i2f_conv[4][4][2] = {
116 [I4BYTES] = {
117 [I4BYTES] = {ASSWTOS, ASUWTOS},
118 [I8BYTES] = {ASSWTOD, ASUWTOD},
119 },
120 [I8BYTES] = {
121 [I4BYTES] = {ASSLTOS, ASULTOS},
122 [I8BYTES] = {ASSLTOD, ASULTOD},
123 }
124 };
125
126 /*
127 * This is strongly influenced by
128 * http://plan9.bell-labs.com/sys/doc/compiler.ps (/sys/doc/compiler.ps)
129 * calculate addresability as follows
130 * AUTO => 11 value+fp
131 * REG => 11 reg
132 * STATIC => 11 (value)
133 * CONST => 11 $value
134 * These values of addressability are not used in the code generation.
135 * They are only used to calculate the Sethi-Ullman numbers. Since
136 * QBE is AMD64 targered we could do a better job there, and try to
137 * detect some of the complex addressing modes of these processors.
138 */
139 Node *
140 tsethi(Node *np)
141 {
142 int op;
143 Node *l, *r;
144
145 l = np->left;
146 r = np->right;
147
148 switch (np->op) {
149 case OAUTO:
150 case OREG:
151 case OMEM:
152 case OCONST:
153 np->address = 11;
154 break;
155 case OASSIG:
156 assert(l->op != OCAST);
157 goto binary;
158 case OCPL:
159 assert(np->type.flags & INTF);
160 np->op = OBXOR;
161 r = constnode(NULL, ~(TUINT) 0, &np->type);
162 goto binary;
163 case OEFUN:
164 /*
165 * In QBE we need at the end of a basic block
166 * a jump, so we have to ensure that the last
167 * statement of the function is a ret, a jmp
168 * or a branch.
169 */
170
171 op = np->prev->op;
172 if (op == ONOP || op == OBRANCH || (op != ORET && op != OJMP))
173 addstmt(node(ORET));
174 break;
175 default:
176 binary:
177 l = sethi(l);
178 r = sethi(r);
179 break;
180 }
181 np->left = l;
182 np->right = r;
183
184 return np;
185 }
186
187 static int
188 bytes2idx(int nbytes)
189 {
190 if (nbytes== 1)
191 return I1BYTES;
192 else if (nbytes == 2)
193 return I2BYTES;
194 else if (nbytes == 4)
195 return I4BYTES;
196 else if (nbytes == 8)
197 return I8BYTES;
198 else
199 abort();
200 }
201
202 static Node *
203 load(Type *tp, Node *np)
204 {
205 int op;
206 Node *new;
207 int flags = tp->flags;
208
209 if (flags & (AGGRF|FUNF|ARRF|PTRF))
210 return np;
211
212 switch (tp->size) {
213 case 1:
214 op = ASLDSB;
215 break;
216 case 2:
217 op = ASLDSH;
218 break;
219 case 4:
220 op = (flags & FLOATF) ? ASLDS : ASLDSW;
221 break;
222 case 8:
223 op = (flags & FLOATF) ? ASLDD : ASLDL;
224 break;
225 default:
226 abort();
227 }
228 /*
229 * unsigned version of operations are always +1 the
230 * signed version
231 */
232 if ((flags & (INTF|SIGNF)) == INTF && tp->size < 8)
233 ++op;
234
235 new = tmpnode(tp, NULL);
236 code(op, new, np, NULL);
237
238 return new;
239 }
240
241 static Node *rhs(Node *np);
242
243 static Node *
244 cast(Type *td, Node *np)
245 {
246 Type *ts;
247 Node *tmp;
248 int op, d_isint, s_isint, sidx, didx, sign;
249
250 ts = &np->type;
251 d_isint = (td->flags & INTF) != 0;
252 s_isint = (ts->flags & INTF) != 0;
253
254 sidx = bytes2idx(ts->size);
255 didx = bytes2idx(td->size);
256
257 sign = (ts->flags & SIGNF) == 0;
258
259 if (d_isint && s_isint) {
260 /* conversion from int to int */
261 if (didx < I4BYTES)
262 didx = bytes2idx(4);
263
264 if (didx <= sidx) {
265 np->type = *td;
266 return np;
267 }
268
269 op = i2i_conv[sidx][didx][sign];
270 } else if (d_isint) {
271 /* conversion from float to int */
272 if (didx < I4BYTES)
273 didx = bytes2idx(4);
274
275 op = f2i_conv[sidx][didx][sign];
276 } else if (s_isint) {
277 /* conversion from int to float */
278 if (sidx == I1BYTES || sidx == I2BYTES) {
279 ts = (ts->flags&SIGNF) ? &int32type : &uint32type;
280 np = cast(ts, np);
281 }
282 op = i2f_conv[sidx][didx][sign];
283 } else {
284 /* conversion from float to float */
285 op = (didx == I4BYTES) ? ASEXTS : ASTRUNCD;
286 }
287
288 assert(op != 0);
289 tmp = tmpnode(td, NULL);
290 code(op, tmp, np, NULL);
291
292 return tmp;
293 }
294
295 static Node *
296 call(Node *np, Node *fun)
297 {
298 int n, op;
299 Type *tp;
300 Node **q, *tmp, *p, *pars[NR_FUNPARAM];
301
302 for (n = 0, p = np->right; p; p = p->right)
303 pars[n++] = rhs(p->left);
304
305 tp = &np->type;
306 tmp = tmpnode(tp, NULL);
307 code(ASCALL, tmp, fun, NULL);
308
309 for (q = pars; q < &pars[n]; ++q) {
310 op = (q == &pars[n-1]) ? ASPARE : ASPAR;
311 code(op, NULL, *q, tmpnode(&(*q)->type, NULL));
312 }
313 code((np->op == OCALL) ? ASCALLE : ASCALLEX, NULL, NULL, NULL);
314
315 return tmp;
316 }
317
318 static Node *
319 copy(Type *tp, Node *to, Node *from)
320 {
321 int op;
322
323 switch (tp->size) {
324 case 0:
325 return from;
326 case 1:
327 op = ASCOPYB;
328 break;
329 case 2:
330 op = ASCOPYH;
331 break;
332 case 4:
333 op = (tp->flags & FLOATF) ? ASCOPYS : ASCOPYW;
334 break;
335 case 8:
336 op = (tp->flags & FLOATF) ? ASCOPYD : ASCOPYL;
337 break;
338 default:
339 abort();
340 }
341 code(op, to, from, NULL);
342 return from;
343 }
344
345 static Node *
346 field(Node *np, int islhs)
347 {
348 Node *tmp, *addr;
349 TUINT offset = np->right->u.sym->u.off;
350
351 addr = rhs(np->left);
352 tmp = node(OADD);
353 tmp->type = ptrtype;
354 tmp->left = addr;
355 tmp->right = constnode(NULL, offset, &ptrtype);
356 addr = rhs(tmp);
357
358 if (!islhs)
359 addr = load(&np->type, addr);
360 return addr;
361 }
362
363 static Node *
364 lhs(Node *np)
365 {
366 switch (np->op) {
367 case OREG:
368 case OMEM:
369 case OAUTO:
370 return np;
371 case OPTR:
372 return rhs(np->left);
373 case OFIELD:
374 return field(np, 1);
375 default:
376 abort();
377 }
378 }
379
380 static Node *
381 function(void)
382 {
383 Node aux;
384 Symbol *p;
385
386 /* allocate stack space for parameters */
387 for (p = locals; p; p = p->next) {
388 if ((p->type.flags & PARF) == 0)
389 continue;
390 if ((p->type.flags & AGGRF) != 0)
391 continue;
392 code(ASALLOC, label2node(&aux, p), NULL, NULL);
393 }
394
395 /* allocate stack space for local variables) */
396 for (p = locals; p; p = p->next) {
397 if ((p->type.flags & PARF) != 0)
398 continue;
399 if (p->kind != SAUTO || p->id == TMPSYM)
400 continue;
401 code(ASALLOC, label2node(&aux, p), NULL, NULL);
402 }
403
404 /* store formal parameters in parameters */
405 for (p = locals; p; p = p->next) {
406 if ((p->type.flags & PARF) == 0)
407 continue;
408 if ((p->type.flags & AGGRF) != 0)
409 continue;
410 if ((p->type.flags & (ARRF|AGGRF)) == 0)
411 code(ASFORM, label2node(&aux, p), NULL, NULL);
412 }
413 return NULL;
414 }
415
416 static int
417 assignop(Type *tp)
418 {
419 int flags = tp->flags;
420
421 if (flags & (AGGRF|FUNF|ARRF))
422 return ASSTM;
423
424 switch (tp->size) {
425 case 1:
426 return ASSTB;
427 case 2:
428 return ASSTH;
429 case 4:
430 return (tp->flags & FLOATF) ? ASSTS : ASSTW;
431 case 8:
432 return (tp->flags & FLOATF) ? ASSTD : ASSTL;
433 default:
434 abort();
435 }
436 }
437
438 static void
439 rhs_rhs(Node **lpp, Node **rpp)
440 {
441 Node *l = *lpp, *r = *rpp;
442
443 if (l->complex >= r->complex) {
444 l = rhs(l);
445 r = rhs(r);
446 } else {
447 r = rhs(r);
448 l = rhs(l);
449 }
450
451 *lpp = l, *rpp = r;
452 }
453
454 static void
455 lhs_rhs(Node **lpp, Node **rpp)
456 {
457 Node *l = *lpp, *r = *rpp;
458
459 if (l->complex >= r->complex) {
460 l = lhs(l);
461 r = rhs(r);
462 } else {
463 r = rhs(r);
464 l = lhs(l);
465 }
466
467 *lpp = l, *rpp = r;
468 }
469
470 static Node *
471 assign(Node *np)
472 {
473 Node *ret, aux;
474 Node *l = np->left, *r = np->right;
475 int op;
476
477 switch (np->u.subop) {
478 case OINC:
479 op = OADD;
480 goto post_oper;
481 case ODEC:
482 op = OSUB;
483 post_oper:
484 lhs_rhs(&l, &r);
485 ret = load(&l->type, l);
486 aux.op = op;
487 aux.left = ret;
488 aux.right = r;
489 aux.type = np->type;
490 r = rhs(sethi(&aux));
491 break;
492 default:
493 /* assign abbreviation */
494 assert(l->type.size == r->type.size);
495 if (r->type.size < 4) {
496 lhs_rhs(&l, &r);
497 aux.op = np->u.subop;
498 aux.left = load(&r->type, l);
499 aux.right = r;
500 aux.type = int32type;
501 aux.address = np->address;
502 ret = r = sethi(rhs(&aux));
503 break;
504 }
505
506 aux.op = np->u.subop;
507 aux.left = l;
508 aux.right = r;
509 aux.type = np->type;
510 aux.address = np->address;
511 r = sethi(&aux);
512 case 0:
513 if (l->op == OTMP) {
514 r = rhs(r);
515 copy(&np->type, l, r);
516 return r;
517 }
518
519 lhs_rhs(&l, &r);
520 ret = r;
521 break;
522 }
523
524 code(assignop(&np->type), l, r, NULL);
525 return ret;
526 }
527
528 static Node *
529 rhs(Node *np)
530 {
531 Node *tmp, aux1, aux2;
532 Node *phi, *l = np->left, *r = np->right;
533 Type *tp;
534 int sign, size, isfloat, op;
535 Symbol *true, *false;
536
537 tp = &np->type;
538
539 switch (np->op) {
540 case OTMP:
541 case OCONST:
542 return np;
543 case OMEM:
544 case OREG:
545 case OAUTO:
546 return load(tp, np);
547 case OMOD:
548 case OSHL:
549 case OBAND:
550 case OBOR:
551 case OBXOR:
552 case OSHR:
553 assert(tp->flags & INTF);
554 case ODIV:
555 case OLT:
556 case OGT:
557 case OLE:
558 case OGE:
559 case OADD:
560 case OSUB:
561 case OMUL:
562 case OEQ:
563 case ONE:
564 assert(tp->size == 4 || tp->size == 8);
565
566 sign = (tp->flags & SIGNF) == 0;
567 size = tp->size == 8;
568 isfloat = (tp->flags & FLOATF) != 0;
569 op = opbin[isfloat][size][np->op][sign];
570 rhs_rhs(&l, &r);
571 tmp = tmpnode(tp, NULL);
572 code(op, tmp, l, r);
573 return tmp;
574 case OCALL:
575 case OCALLE:
576 if (l->op == OPTR)
577 l = rhs(l);
578 return call(np, l);
579 case OCAST:
580 return cast(tp, rhs(l));
581 case OASSIG:
582 return assign(np);
583 case OSNEG:
584 sign = (tp->flags & SIGNF) == 0;
585 size = tp->size == 8;
586 isfloat = (tp->flags & FLOATF) != 0;
587 op = opbin[isfloat][size][np->op][sign];
588 tmp = tmpnode(tp, NULL);
589 code(op, tmp, rhs(l), NULL);
590 return tmp;
591 case OPTR:
592 return load(tp, rhs(l));
593 case OADDR:
594 l = lhs(l);
595 l->type = *tp;
596 l->type.flags |= PTRF;
597 return l;
598 case OFIELD:
599 return field(np, 0);
600 case OBUILTIN:
601 switch (np->u.subop) {
602 case BVA_START:
603 l = rhs(l);
604 code(ASVSTAR, NULL, l, NULL);
605 case BVA_END:
606 return NULL;
607 case BVA_ARG:
608 l = rhs(l);
609 tmp = tmpnode(tp, NULL);
610 code(ASVARG, tmp, l, NULL);
611 return tmp;
612 default:
613 abort();
614 }
615 default:
616 abort();
617 }
618 abort();
619 }
620
621 static Node *
622 cgen(Node *np)
623 {
624 Node true, false, *p, *next;
625
626 setlabel(np->label);
627 switch (np->op) {
628 case OBFUN:
629 return function();
630 case ONOP:
631 case OBLOOP:
632 case OELOOP:
633 case OEFUN:
634 break;
635 case OJMP:
636 label2node(&true, np->u.sym);
637 code(ASJMP, NULL, &true, NULL);
638 break;
639 case OBRANCH:
640 /*
641 * QBE does not accept labels at the end of a function
642 * (ONOP is used for labels) so we have to add a ret
643 * there, and in the case of branches we need a label
644 * for the next statement.
645 */
646 next = np->next;
647 if (!next->label)
648 labelstmt(next, NULL);
649
650 label2node(&true, np->u.sym);
651 label2node(&false, np->next->label);
652 code(ASBRANCH, rhs(np->left), &true, &false);
653 break;
654 case ORET:
655 p = (np->left) ? rhs(np->left) : NULL;
656 code(ASRET, NULL, p, NULL);
657 break;
658 default:
659 rhs(np);
660 break;
661 }
662 return NULL;
663 }
664
665 void
666 genasm(void)
667 {
668 apply(cgen);
669 }