Home | History | Annotate | Line # | Download | only in i86
      1 /*	Id: code.c,v 1.2 2014/11/11 07:43:07 ragge Exp 	*/
      2 /*	$NetBSD: code.c,v 1.1.1.1 2016/02/09 20:28:37 plunky Exp $	*/
      3 /*
      4  * Copyright (c) 2003 Anders Magnusson (ragge (at) ludd.luth.se).
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 
     31 # include "pass1.h"
     32 
     33 /*
     34  * Print out assembler segment name.
     35  */
     36 void
     37 setseg(int seg, char *name)
     38 {
     39 	switch (seg) {
     40 	case PROG: name = ".TEXT"; break;
     41 	case DATA:
     42 	case LDATA: name = ".DATA"; break;
     43 	case UDATA: break;
     44 	case STRNG:
     45 	case RDATA: name = ".DATA"; break;
     46 	case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
     47 	case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
     48 	case NMSEG:
     49 		printf("\t.section %s,\"a%c\",@progbits\n", name,
     50 		    cftnsp ? 'x' : 'w');
     51 		return;
     52 	}
     53 	printf("\t%s\n", name);
     54 }
     55 
     56 /*
     57  * Define everything needed to print out some data (or text).
     58  * This means segment, alignment, visibility, etc.
     59  */
     60 void
     61 defloc(struct symtab *sp)
     62 {
     63 	char *name;
     64 
     65 	if ((name = sp->soname) == NULL)
     66 		name = exname(sp->sname);
     67 	if (sp->sclass == EXTDEF) {
     68 		printf("	.globl %s\n", name);
     69 	}
     70 	if (sp->slevel == 0)
     71 		printf("%s:\n", name);
     72 	else
     73 		printf(LABFMT ":\n", sp->soffset);
     74 }
     75 
     76 int structrettemp;
     77 
     78 /*
     79  * code for the end of a function
     80  * deals with struct return here
     81  */
     82 void
     83 efcode(void)
     84 {
     85 	extern int gotnr;
     86 	NODE *p, *q;
     87 
     88 	gotnr = 0;	/* new number for next fun */
     89 	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
     90 		return;
     91 	/* Create struct assignment */
     92 	q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap);
     93 	q = buildtree(UMUL, q, NIL);
     94 	p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
     95 	p = buildtree(UMUL, p, NIL);
     96 	p = buildtree(ASSIGN, q, p);
     97 	ecomp(p);
     98 
     99 	/* put hidden arg in ax on return */
    100 	q = tempnode(structrettemp, INT, 0, 0);
    101 	p = block(REG, NIL, NIL, INT, 0, 0);
    102 	regno(p) = AX;
    103 	ecomp(buildtree(ASSIGN, p, q));
    104 }
    105 
    106 static TWORD longregs[] = { AXDX, DXCX };
    107 static TWORD regpregs[] = { AX, DX, CX };
    108 static TWORD charregs[] = { AL, DL, CL };
    109 
    110 /*
    111  * code for the beginning of a function; a is an array of
    112  * indices in symtab for the arguments; n is the number
    113  *
    114  * Classifying args on i386; not simple:
    115  * - Args may be on stack or in registers (regparm)
    116  * - There may be a hidden first arg, unless OpenBSD struct return.
    117  * - Regparm syntax is not well documented.
    118  * - There may be stdcall functions, where the called function pops stack
    119  * - ...probably more
    120  */
    121 void
    122 bfcode(struct symtab **sp, int cnt)
    123 {
    124 	extern int argstacksize;
    125 #ifdef GCC_COMPAT
    126 	struct attr *ap;
    127 #endif
    128 	struct symtab *sp2;
    129 	extern int gotnr;
    130 	NODE *n, *p;
    131 	int i, regparmarg;
    132 	int argbase, nrarg, sz;
    133 
    134 	argbase = ARGINIT;
    135 	nrarg = regparmarg = 0;
    136 
    137 #ifdef GCC_COMPAT
    138         if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL)
    139                 cftnsp->sflags |= SSTDCALL;
    140         if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM)))
    141                 regparmarg = ap->iarg(0);
    142 #endif
    143 
    144 	/* Function returns struct, create return arg node */
    145 	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
    146 		{
    147 			if (regparmarg) {
    148 				n = block(REG, 0, 0, INT, 0, 0);
    149 				regno(n) = regpregs[nrarg++];
    150 			} else {
    151 				n = block(OREG, 0, 0, INT, 0, 0);
    152 				n->n_lval = argbase/SZCHAR;
    153 				argbase += SZINT;
    154 				regno(n) = FPREG;
    155 			}
    156 			p = tempnode(0, INT, 0, 0);
    157 			structrettemp = regno(p);
    158 			p = buildtree(ASSIGN, p, n);
    159 			ecomp(p);
    160 		}
    161 	}
    162 
    163 	/*
    164 	 * Find where all params are so that they end up at the right place.
    165 	 * At the same time recalculate their arg offset on stack.
    166 	 * We also get the "pop size" for stdcall.
    167 	 */
    168 	for (i = 0; i < cnt; i++) {
    169 		sp2 = sp[i];
    170 		sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
    171 
    172 		SETOFF(sz, SZINT);
    173 
    174 		if (cisreg(sp2->stype) == 0 ||
    175 		    ((regparmarg - nrarg) * SZINT < sz)) {	/* not in reg */
    176 			sp2->soffset = argbase;
    177 			argbase += sz;
    178 			nrarg = regparmarg;	/* no more in reg either */
    179 		} else {					/* in reg */
    180 			sp2->soffset = nrarg;
    181 			nrarg += sz/SZINT;
    182 			sp2->sclass = REGISTER;
    183 		}
    184 	}
    185 
    186 	/*
    187 	 * Now (argbase - ARGINIT) is used space on stack.
    188 	 * Move (if necessary) the args to something new.
    189 	 */
    190 	for (i = 0; i < cnt; i++) {
    191 		int reg, j;
    192 
    193 		sp2 = sp[i];
    194 
    195 		if (ISSOU(sp2->stype) && sp2->sclass == REGISTER) {
    196 			/* must move to stack */
    197 			sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
    198 			SETOFF(sz, SZINT);
    199 			SETOFF(autooff, SZINT);
    200 			reg = sp2->soffset;
    201 			sp2->sclass = AUTO;
    202 			sp2->soffset = NOOFFSET;
    203 			oalloc(sp2, &autooff);
    204                         for (j = 0; j < sz/SZCHAR; j += 4) {
    205                                 p = block(OREG, 0, 0, INT, 0, 0);
    206                                 p->n_lval = sp2->soffset/SZCHAR + j;
    207                                 regno(p) = FPREG;
    208                                 n = block(REG, 0, 0, INT, 0, 0);
    209                                 regno(n) = regpregs[reg++];
    210                                 p = block(ASSIGN, p, n, INT, 0, 0);
    211                                 ecomp(p);
    212                         }
    213 		} else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) &&
    214 		    ((cqual(sp2->stype, sp2->squal) & VOL) == 0)) {
    215 			/* just put rest in temps */
    216 			if (sp2->sclass == REGISTER) {
    217 				n = block(REG, 0, 0, sp2->stype,
    218 				    sp2->sdf, sp2->sap);
    219 				if (ISLONGLONG(sp2->stype)|| sp2->stype == LONG || sp2->stype == ULONG)
    220 					regno(n) = longregs[sp2->soffset];
    221 				else if (DEUNSIGN(sp2->stype) == CHAR || sp2->stype == BOOL)
    222 					regno(n) = charregs[sp2->soffset];
    223 				else
    224 					regno(n) = regpregs[sp2->soffset];
    225 			} else {
    226                                 n = block(OREG, 0, 0, sp2->stype,
    227 				    sp2->sdf, sp2->sap);
    228                                 n->n_lval = sp2->soffset/SZCHAR;
    229                                 regno(n) = FPREG;
    230 			}
    231 			p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap);
    232 			sp2->soffset = regno(p);
    233 			sp2->sflags |= STNODE;
    234 			n = buildtree(ASSIGN, p, n);
    235 			ecomp(n);
    236 		}
    237 	}
    238 
    239         argstacksize = 0;
    240         if (cftnsp->sflags & SSTDCALL) {
    241 		argstacksize = (argbase - ARGINIT)/SZCHAR;
    242         }
    243 
    244 }
    245 
    246 
    247 /* called just before final exit */
    248 /* flag is 1 if errors, 0 if none */
    249 void
    250 ejobcode(int flag)
    251 {
    252 	printf("\t.asciz \"PCC: %s\"\n", VERSSTR);
    253 }
    254 
    255 void
    256 bjobcode(void)
    257 {
    258 	astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
    259 }
    260 
    261 /*
    262  * Convert FUNARG to assign in case of regparm.
    263  */
    264 static int regcvt, rparg;
    265 static void
    266 addreg(NODE *p)
    267 {
    268 	TWORD t;
    269 	NODE *q;
    270 	int sz, r;
    271 
    272 	sz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR;
    273 	sz = (sz + 3) >> 2;	/* sz in regs */
    274 	if ((regcvt+sz) > rparg) {
    275 		regcvt = rparg;
    276 		return;
    277 	}
    278 	if (sz > 2)
    279 		uerror("cannot put struct in 3 regs (yet)");
    280 
    281 	if (sz == 2)
    282 		r = regcvt == 0 ? AXDX : DXCX;
    283 	else
    284 		r = regcvt == 0 ? AX : regcvt == 1 ? DX : CX;
    285 
    286 	if (p->n_op == FUNARG) {
    287 		/* at most 2 regs */
    288 		if (p->n_type < INT) {
    289 			p->n_left = ccast(p->n_left, INT, 0, 0, 0);
    290 			p->n_type = INT;
    291 		}
    292 
    293 		p->n_op = ASSIGN;
    294 		p->n_right = p->n_left;
    295 	} else if (p->n_op == STARG) {
    296 		/* convert to ptr, put in reg */
    297 		q = p->n_left;
    298 		t = sz == 2 ? LONGLONG : INT;
    299 		q = cast(q, INCREF(t), 0);
    300 		q = buildtree(UMUL, q, NIL);
    301 		p->n_op = ASSIGN;
    302 		p->n_type = t;
    303 		p->n_right = q;
    304 	} else
    305 		cerror("addreg");
    306 	p->n_left = block(REG, 0, 0, p->n_type, 0, 0);
    307 	regno(p->n_left) = r;
    308 	regcvt += sz;
    309 }
    310 
    311 /*
    312  * Called with a function call with arguments as argument.
    313  * This is done early in buildtree() and only done once.
    314  * Returns p.
    315  */
    316 NODE *
    317 funcode(NODE *p)
    318 {
    319 	extern int gotnr;
    320 #ifdef GCC_COMPAT
    321 	struct attr *ap;
    322 #endif
    323 	NODE *r, *l;
    324 	TWORD t = DECREF(DECREF(p->n_left->n_type));
    325 	int stcall;
    326 
    327 	stcall = ISSOU(t);
    328 	/*
    329 	 * We may have to prepend:
    330 	 * - Hidden arg0 for struct return (in reg or on stack).
    331 	 * - ebx in case of PIC code.
    332 	 */
    333 
    334 	/* Fix function call arguments. On x86, just add funarg */
    335 	for (r = p->n_right; r->n_op == CM; r = r->n_left) {
    336 		if (r->n_right->n_op != STARG) {
    337 			r->n_right = intprom(r->n_right);
    338 			r->n_right = block(FUNARG, r->n_right, NIL,
    339 			    r->n_right->n_type, r->n_right->n_df,
    340 			    r->n_right->n_ap);
    341 		}
    342 	}
    343 	if (r->n_op != STARG) {
    344 		l = talloc();
    345 		*l = *r;
    346 		r->n_op = FUNARG;
    347 		r->n_left = l;
    348 		r->n_left = intprom(r->n_left);
    349 		r->n_type = r->n_left->n_type;
    350 	}
    351 	if (stcall) {
    352 		/* Prepend a placeholder for struct address. */
    353 		/* Use BP, can never show up under normal circumstances */
    354 		l = talloc();
    355 		*l = *r;
    356 		r->n_op = CM;
    357 		r->n_right = l;
    358 		r->n_type = INT;
    359 		l = block(REG, 0, 0, INCREF(VOID), 0, 0);
    360 		regno(l) = BP;
    361 		l = block(FUNARG, l, 0, INCREF(VOID), 0, 0);
    362 		r->n_left = l;
    363 	}
    364 
    365 #ifdef GCC_COMPAT
    366 	if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM)))
    367 		rparg = ap->iarg(0);
    368 	else
    369 #endif
    370 		rparg = 0;
    371 
    372 	regcvt = 0;
    373 	if (rparg)
    374 		listf(p->n_right, addreg);
    375 
    376 	return p;
    377 }
    378 
    379 /* fix up type of field p */
    380 void
    381 fldty(struct symtab *p)
    382 {
    383 }
    384 
    385 /*
    386  * XXX - fix genswitch.
    387  */
    388 int
    389 mygenswitch(int num, TWORD type, struct swents **p, int n)
    390 {
    391 	return 0;
    392 }
    393 
    394 NODE *
    395 builtin_return_address(const struct bitable *bt, NODE *a)
    396 {
    397 	int nframes;
    398 	NODE *f;
    399 
    400 	if (a->n_op != ICON)
    401 		goto bad;
    402 
    403 	nframes = (int)a->n_lval;
    404 
    405 	tfree(a);
    406 
    407 	f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
    408 	regno(f) = FPREG;
    409 
    410 	while (nframes--)
    411 		f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
    412 
    413 	f = block(PLUS, f, bcon(2), INCREF(PTR+VOID), 0, 0);
    414 	f = buildtree(UMUL, f, NIL);
    415 
    416 	return f;
    417 bad:
    418 	uerror("bad argument to __builtin_return_address");
    419 	return bcon(0);
    420 }
    421 
    422 NODE *
    423 builtin_frame_address(const struct bitable *bt, NODE *a)
    424 {
    425 	int nframes;
    426 	NODE *f;
    427 
    428 	if (a->n_op != ICON)
    429 		goto bad;
    430 
    431 	nframes = (int)a->n_lval;
    432 
    433 	tfree(a);
    434 
    435 	f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
    436 	regno(f) = FPREG;
    437 
    438 	while (nframes--)
    439 		f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
    440 
    441 	return f;
    442 bad:
    443 	uerror("bad argument to __builtin_frame_address");
    444 	return bcon(0);
    445 }
    446 
    447 /*
    448  * Return "canonical frame address".
    449  */
    450 NODE *
    451 builtin_cfa(const struct bitable *bt, NODE *a)
    452 {
    453 	uerror("missing builtin_cfa");
    454 	return bcon(0);
    455 }
    456 
    457