scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

cgen.c (13429B)


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