Home | History | Annotate | Line # | Download | only in amd64
      1 /*	Id: code.c,v 1.85 2015/12/13 09:00:04 ragge Exp 	*/
      2 /*	$NetBSD: code.c,v 1.3 2016/02/09 20:37:32 plunky Exp $	*/
      3 /*
      4  * Copyright (c) 2008 Michael Shalayeff
      5  * Copyright (c) 2003 Anders Magnusson (ragge (at) ludd.luth.se).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of the author may not be used to endorse or promote products
     17  *    derived from this software without specific prior written permission
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 
     32 # include "pass1.h"
     33 
     34 #ifndef LANG_CXX
     35 #undef NIL
     36 #define	NIL NULL
     37 #define	NODE P1ND
     38 #define	nfree p1nfree
     39 #define	ccopy p1tcopy
     40 #define	tfree p1tfree
     41 #endif
     42 
     43 static int nsse, ngpr, nrsp, rsaoff;
     44 static int thissse, thisgpr, thisrsp;
     45 enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87,
     46 	STRREG, STRMEM, STRSSE, STRIF, STRFI, STRX87 };
     47 static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 };
     48 /*
     49  * The Register Save Area looks something like this.
     50  * It is put first on stack with fixed offsets.
     51  * struct {
     52  *	long regs[6];
     53  *	double xmm[8][2]; // 16 byte in width
     54  * };
     55  */
     56 #define	RSASZ		(6*SZLONG+8*2*SZDOUBLE)
     57 #define	RSALONGOFF(x)	(RSASZ-(x)*SZLONG)
     58 #define	RSADBLOFF(x)	((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
     59 /* va_list */
     60 #define	VAARGSZ		(SZINT*2+SZPOINT(CHAR)*2)
     61 #define	VAGPOFF(x)	(x)
     62 #define	VAFPOFF(x)	(x-SZINT)
     63 #define	VAOFA(x)	(x-SZINT-SZINT)
     64 #define	VARSA(x)	(x-SZINT-SZINT-SZPOINT(0))
     65 
     66 static int stroffset;
     67 
     68 static int varneeds;
     69 #define	NEED_1FPREF	 001
     70 #define	NEED_2FPREF	 002
     71 #define	NEED_1REGREF	 004
     72 #define	NEED_2REGREF	 010
     73 #define	NEED_MEMREF	 020
     74 #define	NEED_STRFI	 040
     75 #define	NEED_STRIF	0100
     76 
     77 static int argtyp(TWORD t, union dimfun *df, struct attr *ap);
     78 static NODE *movtomem(NODE *p, int off, int reg);
     79 static NODE *movtoreg(NODE *p, int rno);
     80 void varattrib(char *name, struct attr *sap);
     81 
     82 /*
     83  * Print out assembler segment name.
     84  */
     85 #ifdef MACHOABI
     86 void
     87 setseg(int seg, char *name)
     88 {
     89 	switch (seg) {
     90 	case PROG: name = ".text"; break;
     91 	case DATA:
     92 	case LDATA: name = ".data"; break;
     93 	case RDATA: name = ".const"; break;
     94 	case STRNG: name = ".cstring"; break;
     95 	case UDATA: break;
     96 	case CTORS: name = ".mod_init_func"; break;
     97 	case DTORS: name = ".mod_term_func"; break;
     98 	default:
     99 		cerror("unknown seg %d", seg);
    100 	}
    101 	printf("\t%s\n", name);
    102 }
    103 
    104 #else
    105 void
    106 setseg(int seg, char *name)
    107 {
    108 	switch (seg) {
    109 	case PROG: name = ".text"; break;
    110 	case DATA:
    111 	case LDATA: name = ".data"; break;
    112 	case STRNG:
    113 	case RDATA: name = ".section .rodata"; break;
    114 	case UDATA: break;
    115 	case PICLDATA:
    116 	case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
    117 	case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
    118 	case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
    119 	case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
    120 	case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
    121 	case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
    122 	case NMSEG:
    123 		printf("\t.section %s,\"a%c\",@progbits\n", name,
    124 		    cftnsp ? 'x' : 'w');
    125 		return;
    126 	}
    127 	printf("\t%s\n", name);
    128 }
    129 #endif
    130 
    131 /*
    132  * Define everything needed to print out some data (or text).
    133  * This means segment, alignment, visibility, etc.
    134  */
    135 void
    136 defloc(struct symtab *sp)
    137 {
    138 	char *name;
    139 
    140 	name = getexname(sp);
    141 
    142 	if (sp->sclass == EXTDEF) {
    143 		printf("\t.globl %s\n", name);
    144 #ifndef MACHOABI
    145 		if (ISFTN(sp->stype)) {
    146 			printf("\t.type %s,@function\n", name);
    147 		} else {
    148 			printf("\t.type %s,@object\n", name);
    149 			printf("\t.size %s,%d\n", name,
    150 			    (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
    151 		}
    152 #endif
    153 	}
    154 	if (sp->slevel == 0)
    155 		printf("%s:\n", name);
    156 	else
    157 		printf(LABFMT ":\n", sp->soffset);
    158 }
    159 
    160 /*
    161  * code for the end of a function
    162  * deals with struct return here
    163  * The return value is in (or pointed to by) RETREG.
    164  */
    165 void
    166 efcode(void)
    167 {
    168 	struct symtab *sp;
    169 	extern int gotnr;
    170 	TWORD t;
    171 	NODE *p, *r, *l;
    172 	int typ;
    173 
    174 	gotnr = 0;	/* new number for next fun */
    175 	sp = cftnsp;
    176 	t = DECREF(sp->stype);
    177 	if (t != STRTY && t != UNIONTY)
    178 		return;
    179 
    180 	/* XXX should have one routine for this */
    181 	ngpr = nsse = 0;
    182 	typ = argtyp(t, sp->sdf, sp->sap);
    183 	if (typ == STRMEM) {
    184 		r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap);
    185 		regno(r) = RAX;
    186 		r = buildtree(UMUL, r, NIL);
    187 		l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap);
    188 		l = buildtree(UMUL, l, NIL);
    189 		ecomp(buildtree(ASSIGN, l, r));
    190 		l = block(REG, NIL, NIL, LONG, 0, 0);
    191 		regno(l) = RAX;
    192 		r = tempnode(stroffset, LONG, 0, 0);
    193 		ecomp(buildtree(ASSIGN, l, r));
    194 	} else if (typ == STRX87) {
    195 		p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0);
    196 		regno(p) = RAX;
    197 		p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
    198 		ecomp(movtoreg(p, 041));
    199 		p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0);
    200 		regno(p) = RAX;
    201 		p = buildtree(UMUL, p, NIL);
    202 		ecomp(movtoreg(p, 040));
    203 	} else {
    204 		TWORD t1, t2;
    205 		int r1, r2;
    206 		if (typ == STRSSE || typ == STRFI)
    207 			r1 = XMM0, t1 = DOUBLE;
    208 		else
    209 			r1 = RAX, t1 = LONG;
    210 		if (typ == STRSSE)
    211 			r2 = XMM1, t2 = DOUBLE;
    212 		else if (typ == STRFI)
    213 			r2 = RAX, t2 = LONG;
    214 		else if (typ == STRIF)
    215 			r2 = XMM0, t2 = DOUBLE;
    216 		else /* if (typ == STRREG) */
    217 			r2 = RDX, t2 = LONG;
    218 
    219 		if (tsize(t, sp->sdf, sp->sap) > SZLONG) {
    220 			p = block(REG, NIL, NIL, INCREF(t2), 0, 0);
    221 			regno(p) = RAX;
    222 			p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
    223 			ecomp(movtoreg(p, r2));
    224 		}
    225 		p = block(REG, NIL, NIL, INCREF(t1), 0, 0);
    226 		regno(p) = RAX;
    227 		p = buildtree(UMUL, p, NIL);
    228 		ecomp(movtoreg(p, r1));
    229 	}
    230 }
    231 
    232 /*
    233  * code for the beginning of a function; a is an array of
    234  * indices in symtab for the arguments; n is the number
    235  */
    236 void
    237 bfcode(struct symtab **s, int cnt)
    238 {
    239 	union arglist *al;
    240 	struct symtab *sp;
    241 	NODE *p, *r;
    242 	TWORD t;
    243 	int i, rno, typ, ssz;
    244 
    245 	/* recalculate the arg offset and create TEMP moves */
    246 	/* Always do this for reg, even if not optimizing, to free arg regs */
    247 	nsse = ngpr = 0;
    248 	nrsp = ARGINIT;
    249 	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
    250 		sp = cftnsp;
    251 		if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) {
    252 			r = block(REG, NIL, NIL, LONG, 0, 0);
    253 			regno(r) = argregsi[ngpr++];
    254 			p = tempnode(0, r->n_type, r->n_df, r->n_ap);
    255 			stroffset = regno(p);
    256 			ecomp(buildtree(ASSIGN, p, r));
    257 		}
    258 	}
    259 
    260 	for (i = 0; i < cnt; i++) {
    261 		sp = s[i];
    262 
    263 		if (sp == NULL)
    264 			continue; /* XXX when happens this? */
    265 
    266 		ssz = tsize(sp->stype, sp->sdf, sp->sap);
    267 		switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) {
    268 		case INTEGER:
    269 		case SSE:
    270 			if (typ == SSE)
    271 				rno = XMM0 + nsse++;
    272 			else
    273 				rno = argregsi[ngpr++];
    274 			r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap);
    275 			regno(r) = rno;
    276 			p = tempnode(0, sp->stype, sp->sdf, sp->sap);
    277 			sp->soffset = regno(p);
    278 			sp->sflags |= STNODE;
    279 			ecomp(buildtree(ASSIGN, p, r));
    280 			break;
    281 
    282 		case SSEMEM:
    283 			sp->soffset = nrsp;
    284 			nrsp += SZDOUBLE;
    285 			if (xtemps) {
    286 				p = tempnode(0, sp->stype, sp->sdf, sp->sap);
    287 				p = buildtree(ASSIGN, p, nametree(sp));
    288 				sp->soffset = regno(p->n_left);
    289 				sp->sflags |= STNODE;
    290 				ecomp(p);
    291 			}
    292 			break;
    293 
    294 		case INTMEM:
    295 			sp->soffset = nrsp;
    296 			nrsp += SZLONG;
    297 			if (xtemps) {
    298 				p = tempnode(0, sp->stype, sp->sdf, sp->sap);
    299 				p = buildtree(ASSIGN, p, nametree(sp));
    300 				sp->soffset = regno(p->n_left);
    301 				sp->sflags |= STNODE;
    302 				ecomp(p);
    303 			}
    304 			break;
    305 
    306 		case STRX87:
    307 		case STRMEM: /* Struct in memory */
    308 			sp->soffset = nrsp;
    309 			nrsp += ssz;
    310 			break;
    311 
    312 		case X87: /* long double args */
    313 			sp->soffset = nrsp;
    314 			nrsp += SZLDOUBLE;
    315 			break;
    316 
    317 		case STRFI:
    318 		case STRIF:
    319 		case STRSSE:
    320 		case STRREG: /* Struct in register */
    321 			autooff += (2*SZLONG);
    322 
    323 			if (typ == STRSSE || typ == STRFI) {
    324 				rno = XMM0 + nsse++;
    325 				t = DOUBLE;
    326 			} else {
    327 				rno = argregsi[ngpr++];
    328 				t = LONG;
    329 			}
    330 			r = block(REG, NIL, NIL, t, 0, 0);
    331 			regno(r) = rno;
    332 			ecomp(movtomem(r, -autooff, FPREG));
    333 
    334 			if (ssz > SZLONG) {
    335 				if (typ == STRSSE || typ == STRIF) {
    336 					rno = XMM0 + nsse++;
    337 					t = DOUBLE;
    338 				} else {
    339 					rno = argregsi[ngpr++];
    340 					t = LONG;
    341 				}
    342 				r = block(REG, NIL, NIL, t, 0, 0);
    343 				regno(r) = rno;
    344 				ecomp(movtomem(r, -autooff+SZLONG, FPREG));
    345 			}
    346 			sp->soffset = -autooff;
    347 			break;
    348 
    349 		default:
    350 			cerror("bfcode: %d", typ);
    351 		}
    352 	}
    353 
    354 	/* Check if there are varargs */
    355 	if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
    356 		return; /* no prototype */
    357 	al = cftnsp->sdf->dfun;
    358 
    359 	for (; al->type != TELLIPSIS; al++) {
    360 		t = al->type;
    361 		if (t == TNULL)
    362 			return;
    363 		if (ISSOU(BTYPE(t)))
    364 			al++;
    365 		for (i = 0; t > BTMASK; t = DECREF(t))
    366 			if (ISARY(t) || ISFTN(t))
    367 				i++;
    368 		if (i)
    369 			al++;
    370 	}
    371 
    372 	/* fix stack offset */
    373 	SETOFF(autooff, ALMAX);
    374 
    375 	/* Save reg arguments in the reg save area */
    376 	p = NIL;
    377 	for (i = ngpr; i < 6; i++) {
    378 		r = block(REG, NIL, NIL, LONG, 0, 0);
    379 		regno(r) = argregsi[i];
    380 		r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG);
    381 		p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
    382 	}
    383 	for (i = nsse; i < 8; i++) {
    384 		r = block(REG, NIL, NIL, DOUBLE, 0, 0);
    385 		regno(r) = i + XMM0;
    386 		r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG);
    387 		p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
    388 	}
    389 	autooff += RSASZ;
    390 	rsaoff = autooff;
    391 	thissse = nsse;
    392 	thisgpr = ngpr;
    393 	thisrsp = nrsp;
    394 
    395 	ecomp(p);
    396 }
    397 
    398 
    399 /* called just before final exit */
    400 /* flag is 1 if errors, 0 if none */
    401 void
    402 ejobcode(int flag)
    403 {
    404 	if (flag)
    405 		return;
    406 
    407 #ifdef MACHOABI
    408 #define PT(x)
    409 #else
    410 #define	PT(x) printf(".type __pcc_" x ",@function\n")
    411 #endif
    412 
    413 #define	P(x) printf(x "\n")
    414 	/* printout varargs routines if used */
    415 	if (varneeds & NEED_STRFI) {	/* struct with one float and then int */
    416 		P(".text\n.align 4");
    417 		PT("strif");
    418 		P("__pcc_strif:");
    419 		P("cmpl $176,4(%%rdi)\njae .Ladd16");
    420 		P("cmpl $48,(%%rdi)\njae .Ladd16\n");
    421 		P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
    422 		P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
    423 		P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
    424 		P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
    425 		P("leaq 24(%%rdi),%%rax\nret");
    426 	}
    427 	if (varneeds & NEED_STRIF) {	/* struct with one int and one float */
    428 		P(".text\n.align 4");
    429 		PT("strif");
    430 		P("__pcc_strif:");
    431 		P("cmpl $176,4(%%rdi)\njae .Ladd16");
    432 		P("cmpl $48,(%%rdi)\njae .Ladd16\n");
    433 		P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
    434 		P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
    435 		P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
    436 		P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
    437 		P("leaq 24(%%rdi),%%rax\nret");
    438 	}
    439 	if (varneeds & NEED_2FPREF) {	/* struct with two float regs */
    440 		P(".text\n.align 4");
    441 		PT("2fpref");
    442 		P("__pcc_2fpref:");
    443 		P("cmpl $160,4(%%rdi)\njae .Ladd16");
    444 		P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
    445 		P("addl $32,4(%%rdi)");
    446 		P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
    447 		P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
    448 		P("leaq 24(%%rdi),%%rax\nret");
    449 	}
    450 	if (varneeds & NEED_1FPREF) {
    451 		printf(".text\n.align 4\n");
    452 		PT("1fpref");
    453 		printf("__pcc_1fpref:\n");
    454 		printf("cmpl $176,4(%%rdi)\njae .Ladd8\n");
    455 		printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
    456 		printf("addl $16,4(%%rdi)\nret\n");
    457 	}
    458 	if (varneeds & NEED_1REGREF) {
    459 		printf(".text\n.align 4\n");
    460 		PT("1regref");
    461 		printf("__pcc_1regref:\n");
    462 		printf("cmpl $48,(%%rdi)\njae .Ladd8\n");
    463 		printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
    464 		printf("addl $8,(%%rdi)\nret\n");
    465 	}
    466 	if (varneeds & NEED_2REGREF) {
    467 		printf(".text\n.align 4\n");
    468 		PT("2regref");
    469 		printf("__pcc_2regref:\n");
    470 		printf("cmpl $40,(%%rdi)\njae .Ladd16\n");
    471 		printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
    472 		printf("addl $16,(%%rdi)\nret\n");
    473 	}
    474 	if (varneeds & NEED_MEMREF) {
    475 		printf(".text\n.align 4\n");
    476 		PT("memref");
    477 		printf("__pcc_memref:\n");
    478 		printf("movq 8(%%rdi),%%rax\n");
    479 		printf("addq %%rsi,8(%%rdi)\nret\n");
    480 	}
    481 
    482 	if (varneeds & (NEED_1FPREF|NEED_1REGREF)) {
    483 		P(".Ladd8:");
    484 		P("movq 8(%%rdi),%%rax");
    485 		P("addq $8,8(%%rdi)");
    486 		P("ret");
    487 	}
    488 	if (varneeds & (NEED_2FPREF|NEED_2REGREF|NEED_STRFI|NEED_STRIF)) {
    489 		P(".Ladd16:");
    490 		P("movq 8(%%rdi),%%rax");
    491 		P("addq $16,8(%%rdi)");
    492 		P("ret");
    493 	}
    494 
    495 #ifdef MACHOABI
    496 	printf("\t.ident \"PCC: %s\"\n", VERSSTR);
    497 #else
    498 	printf("\t.ident \"PCC: %s\"\n\t.end\n", VERSSTR);
    499 #endif
    500 }
    501 
    502 /*
    503  * Varargs stuff:
    504  * The ABI says that va_list should be declared as this typedef.
    505  * We handcraft it here and then just reference it.
    506  *
    507  * typedef struct {
    508  *	unsigned int gp_offset;
    509  *	unsigned int fp_offset;
    510  *	void *overflow_arg_area;
    511  *	void *reg_save_area;
    512  * } __builtin_va_list[1];
    513  *
    514  * ...actually, we allocate two of them and use the second one as
    515  * bounce buffers for floating point structs...
    516  *
    517  * There are a number of asm routines printed out if varargs are used:
    518  *	long __pcc_gpnext(va)	- get a gpreg value
    519  *	long __pcc_fpnext(va)	- get a fpreg value
    520  *	void *__pcc_1regref(va)	- get reference to a onereg struct
    521  *	void *__pcc_2regref(va)	- get reference to a tworeg struct
    522  *	void *__pcc_memref(va,sz)	- get reference to a large struct
    523  */
    524 
    525 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
    526 static char *_1fpref, *_2fpref, *_1regref, *_2regref, *memref;
    527 static char *strif, *strfi;
    528 
    529 void
    530 bjobcode(void)
    531 {
    532 	struct symtab *sp;
    533 	struct rstack *rp;
    534 	NODE *p, *q;
    535 	char *c;
    536 
    537 #if defined(__GNUC__) || defined(__PCC__)
    538 	/* Be sure that the compiler uses full x87 */
    539 	/* XXX cross-compiling will fail here */
    540 	int fcw = 0;
    541 	__asm("fstcw (%0)" : : "r"(&fcw));
    542 	fcw |= 0x33f;
    543 	__asm("fldcw (%0)" : : "r"(&fcw));
    544 #endif
    545 
    546 	/* amd64 names for some asm constant printouts */
    547 	astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
    548 	astypnames[LONG] = astypnames[ULONG] = "\t.quad";
    549 
    550 	gp_offset = addname("gp_offset");
    551 	fp_offset = addname("fp_offset");
    552 	overflow_arg_area = addname("overflow_arg_area");
    553 	reg_save_area = addname("reg_save_area");
    554 
    555 	rp = bstruct(NULL, STNAME, NULL);
    556 	p = block(NAME, NIL, NIL, UNSIGNED, 0, 0);
    557 	soumemb(p, gp_offset, 0);
    558 	soumemb(p, fp_offset, 0);
    559 	p->n_type = VOID+PTR;
    560 	p->n_ap = NULL;
    561 	soumemb(p, overflow_arg_area, 0);
    562 	soumemb(p, reg_save_area, 0);
    563 	nfree(p);
    564 	q = dclstruct(rp);
    565 	c = addname("__builtin_va_list");
    566 	p = block(LB, bdty(NAME, c), bcon(2), INT, 0, 0);
    567 	p = tymerge(q, p);
    568 	p->n_sp = lookup(c, 0);
    569 	defid(p, TYPEDEF);
    570 	nfree(q);
    571 	nfree(p);
    572 
    573 	/* for the static varargs functions */
    574 #define	MKN(vn, rn) \
    575 	{ vn = addname(rn); sp = lookup(vn, SNORMAL); \
    576 	  sp->sclass = USTATIC; sp->stype = FTN|VOID|(PTR<<TSHIFT); }
    577 
    578 	MKN(strfi, "__pcc_strfi");
    579 	MKN(strif, "__pcc_strif");
    580 	MKN(_1fpref, "__pcc_1fpref");
    581 	MKN(_2fpref, "__pcc_2fpref");
    582 	MKN(_1regref, "__pcc_1regref");
    583 	MKN(_2regref, "__pcc_2regref");
    584 	MKN(memref, "__pcc_memref");
    585 }
    586 
    587 static NODE *
    588 mkstkref(int off, TWORD typ)
    589 {
    590 	NODE *p;
    591 
    592 	p = block(REG, NIL, NIL, PTR|typ, 0, 0);
    593 	regno(p) = FPREG;
    594 	return buildtree(PLUS, p, bcon(off/SZCHAR));
    595 }
    596 
    597 NODE *
    598 amd64_builtin_stdarg_start(const struct bitable *bt, NODE *a)
    599 {
    600 	NODE *p, *r;
    601 
    602 	/* use the values from the function header */
    603 	p = a->n_left;
    604 	r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area),
    605 	    mkstkref(-rsaoff, VOID));
    606 	r = buildtree(COMOP, r,
    607 	    buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area),
    608 	    mkstkref(thisrsp, VOID)));
    609 	r = buildtree(COMOP, r,
    610 	    buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset),
    611 	    bcon(thisgpr*(SZLONG/SZCHAR))));
    612 	r = buildtree(COMOP, r,
    613 	    buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset),
    614 	    bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
    615 
    616 	tfree(a);
    617 	return r;
    618 }
    619 
    620 static NODE *
    621 mkvacall(char *fun, NODE *a, int typ)
    622 {
    623 	NODE *r, *f = block(NAME, NIL, NIL, INT, 0, 0);
    624 	NODE *ap = a->n_left;
    625 	NODE *dp = a->n_right;
    626 	int sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
    627 
    628 	f->n_sp = lookup(fun, SNORMAL);
    629 	varneeds |= typ;
    630 	f->n_type = f->n_sp->stype;
    631 	f = clocal(f);
    632 	SETOFF(sz, ALLONG);
    633 	r = buildtree(CALL, f,
    634 	    buildtree(CM, ccopy(ap), bcon(sz/SZCHAR)));
    635 	r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
    636 	r = buildtree(UMUL, r, NIL);
    637 	return r;
    638 }
    639 
    640 NODE *
    641 amd64_builtin_va_arg(const struct bitable *bt, NODE *a)
    642 {
    643 	NODE *r, *dp;
    644 	int typ, sz;
    645 
    646 	dp = a->n_right;
    647 
    648 	nsse = ngpr = 0;
    649 	sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
    650 	switch (typ = argtyp(dp->n_type, dp->n_df, dp->n_ap)) {
    651 	case INTEGER:
    652 		r = mkvacall(_1regref, a, NEED_1REGREF);
    653 		break;
    654 
    655 	case SSE:
    656 		r = mkvacall(_1fpref, a, NEED_1FPREF);
    657 		break;
    658 
    659 	default:
    660 		cerror("va_arg: bad type %d", typ);
    661 
    662 	case X87:
    663 	case STRX87:
    664 	case STRMEM: /* stored in memory */
    665 		r = mkvacall(memref, a, NEED_MEMREF);
    666 		break;
    667 
    668 	case STRREG: /* struct in general regs */
    669 		if (sz <= SZLONG)
    670 			r = mkvacall(_1regref, a, NEED_1REGREF);
    671 		else
    672 			r = mkvacall(_2regref, a, NEED_2REGREF);
    673 		break;
    674 
    675 	case STRSSE:
    676 		if (sz <= SZLONG)
    677 			r = mkvacall(_1fpref, a, NEED_1FPREF);
    678 		else
    679 			r = mkvacall(_2fpref, a, NEED_2FPREF);
    680 		break;
    681 
    682 	case STRIF:
    683 		r = mkvacall(strif, a, NEED_STRIF);
    684 		break;
    685 
    686 	case STRFI:
    687 		r = mkvacall(strfi, a, NEED_STRFI);
    688 		break;
    689 	}
    690 
    691 	tfree(a);
    692 	return r;
    693 }
    694 
    695 NODE *
    696 amd64_builtin_va_end(const struct bitable *bt, NODE *a)
    697 {
    698 	tfree(a);
    699 	return bcon(0); /* nothing */
    700 }
    701 
    702 NODE *
    703 amd64_builtin_va_copy(const struct bitable *bt, NODE *a)
    704 {
    705 	NODE *f;
    706 
    707 	f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL),
    708 	    buildtree(UMUL, a->n_right, NIL));
    709 	nfree(a);
    710 	return f;
    711 }
    712 
    713 static NODE *
    714 movtoreg(NODE *p, int rno)
    715 {
    716 	NODE *r;
    717 
    718 	r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
    719 	regno(r) = rno;
    720 	return clocal(buildtree(ASSIGN, r, p));
    721 }
    722 
    723 static NODE *
    724 movtomem(NODE *p, int off, int reg)
    725 {
    726 	struct symtab s;
    727 	NODE *r, *l;
    728 
    729 	s.stype = p->n_type;
    730 	s.squal = 0;
    731 	s.sdf = p->n_df;
    732 	s.sap = p->n_ap;
    733 	s.soffset = off;
    734 	s.sclass = AUTO;
    735 
    736 	l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
    737 	slval(l, 0);
    738 	regno(l) = reg;
    739 
    740 	r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
    741 	r->n_sp = &s;
    742 	r = stref(block(STREF, l, r, 0, 0, 0));
    743 
    744 	return clocal(buildtree(ASSIGN, r, p));
    745 }
    746 
    747 /*
    748  * Check what to do with a struct.  We traverse down in the struct to
    749  * find which types it is and where the struct really should be.
    750  * The return vals we may end up with are:
    751  *	STRREG - The whole struct is saved in general registers.
    752  *	STRMEM - the struct is saved in memory.
    753  *	STRSSE - the whole struct is saved in SSE registers.
    754  *	STRIF  - First word of struct is saved in general reg, other SSE.
    755  *	STRFI  - First word of struct is saved in SSE, next in general reg.
    756  *
    757  * - If size > 16 bytes or there are packed fields, use memory.
    758  * - If any part of an eight-byte should be in a general register,
    759  *    the eight-byte is stored in a general register
    760  * - If the eight-byte only contains float or double, use a SSE register
    761  * - Otherwise use memory.
    762  *
    763  * Arrays must be broken up as separate elements, since the elements
    764  * are classified separately. For example;
    765  * 	struct s { short s; float f[3]; } S;
    766  * will have the first 64 bits passed in general reg and the second in SSE.
    767  *
    768  * sp below is a pointer to a member list.
    769  * off tells whether is is the first or second eight-byte to check.
    770  */
    771 static int
    772 classifystruct(struct symtab *sp, int off)
    773 {
    774 	struct symtab sps[16];
    775 	union dimfun *df;
    776 	TWORD t;
    777 	int cl, cl2, sz, i;
    778 
    779 
    780 	for (cl = 0; sp; sp = sp->snext) {
    781 		t = sp->stype;
    782 
    783 		/* fake a linked list of all array members */
    784 		if (ISARY(t)) {
    785 			sz = 1;
    786 			df = sp->sdf;
    787 			do {
    788 				sz *= df->ddim;
    789 				t = DECREF(t);
    790 				df++;
    791 			} while (ISARY(t));
    792 			for (i = 0; i < sz; i++) {
    793 				sps[i] = *sp;
    794 				sps[i].stype = t;
    795 				sps[i].sdf = df;
    796 				sps[i].snext = &sps[i+1];
    797 				sps[i].soffset = i * tsize(t, df, sp->sap);
    798 				sps[i].soffset += sp->soffset;
    799 			}
    800 			sps[i-1].snext = sp->snext;
    801 			sp = &sps[0];
    802 		}
    803 
    804 		if (off == 0) {
    805 			if (sp->soffset >= SZLONG)
    806 				continue;
    807 		} else {
    808 			if (sp->soffset < SZLONG)
    809 				continue;
    810 		}
    811 
    812 		if (t <= ULONGLONG || ISPTR(t)) {
    813 			if (cl == 0 || cl == STRSSE)
    814 				cl = STRREG;
    815 		} else if (t <= DOUBLE) {
    816 			if (cl == 0)
    817 				cl = STRSSE;
    818 		} else if (t == LDOUBLE) {
    819 			return STRMEM;
    820 		} else if (ISSOU(t)) {
    821 #ifdef GCC_COMPAT
    822 			if (attr_find(sp->sap, GCC_ATYP_PACKED)) {
    823 				cl = STRMEM;
    824 			} else
    825 #endif
    826 			{
    827 				cl2 = classifystruct(strmemb(sp->sap), off);
    828 				if (cl2 == STRMEM) {
    829 					cl = STRMEM;
    830 				} else if (cl2 == STRREG) {
    831 					if (cl == 0 || cl == STRSSE)
    832 						cl = STRREG;
    833 				} else if (cl2 == STRSSE) {
    834 					if (cl == 0)
    835 						cl = STRSSE;
    836 				}
    837 			}
    838 		} else
    839 			cerror("classifystruct: unknown type %x", t);
    840 		if (cl == STRMEM)
    841 			break;
    842 	}
    843 	if (cl == 0)
    844 		cerror("classifystruct: failed classify");
    845 	return cl;
    846 }
    847 
    848 /*
    849  * Check for long double complex structs.
    850  */
    851 static int
    852 iscplx87(struct symtab *sp)
    853 {
    854 	if (sp->stype == LDOUBLE && sp->snext->stype == LDOUBLE &&
    855 	    sp->snext->snext == NULL)
    856 		return STRX87;
    857 	return 0;
    858 }
    859 
    860 /*
    861  * AMD64 parameter classification.
    862  */
    863 static int
    864 argtyp(TWORD t, union dimfun *df, struct attr *ap)
    865 {
    866 	int cl2, cl = 0;
    867 
    868 	if (t <= ULONG || ISPTR(t) || t == BOOL) {
    869 		cl = ngpr < 6 ? INTEGER : INTMEM;
    870 	} else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
    871 		cl = nsse < 8 ? SSE : SSEMEM;
    872 	} else if (t == LDOUBLE || t == LIMAG) {
    873 		cl = X87; /* XXX */
    874 	} else if (t == STRTY || t == UNIONTY) {
    875 		int sz = tsize(t, df, ap);
    876 
    877 #ifdef GCC_COMPAT
    878 		if (attr_find(ap, GCC_ATYP_PACKED)) {
    879 			cl = STRMEM;
    880 		} else
    881 #endif
    882 		if (iscplx87(strmemb(ap)) == STRX87) {
    883 			cl = STRX87;
    884 		} else if (sz > 2*SZLONG) {
    885 			cl = STRMEM;
    886 		} else if (sz <= SZLONG) {
    887 			/* only one member to check */
    888 			cl = classifystruct(strmemb(ap), 0);
    889 			if (cl == STRREG && ngpr > 5)
    890 				cl = STRMEM;
    891 			else if (cl == STRSSE && nsse > 7)
    892 				cl = STRMEM;
    893 		} else {
    894 			cl = classifystruct(strmemb(ap), 0);
    895 			cl2 = classifystruct(strmemb(ap), 1);
    896 			if (cl == STRMEM || cl2 == STRMEM)
    897 				cl = STRMEM;
    898 			else if (cl == STRREG && cl2 == STRSSE)
    899 				cl = STRIF;
    900 			else if (cl2 == STRREG && cl == STRSSE)
    901 				cl = STRFI;
    902 
    903 			if (cl == STRREG && ngpr > 4)
    904 				cl = STRMEM;
    905 			else if (cl == STRSSE && nsse > 6)
    906 				cl = STRMEM;
    907 			else if ((cl == STRIF || cl == STRFI) &&
    908 			    (ngpr > 5 || nsse > 7))
    909 				cl = STRMEM;
    910 		}
    911 	} else
    912 		cerror("FIXME: classify");
    913 	return cl;
    914 }
    915 
    916 /*
    917  * Do the "hard work" in assigning correct destination for arguments.
    918  * Also convert arguments < INT to inte (default argument promotions).
    919  * XXX - should be dome elsewhere.
    920  */
    921 static NODE *
    922 argput(NODE *p)
    923 {
    924 	NODE *q, *ql;
    925 	TWORD ty;
    926 	int typ, r, ssz, rn;
    927 
    928 	if (p->n_op == CM) {
    929 		p->n_left = argput(p->n_left);
    930 		p->n_right = argput(p->n_right);
    931 		return p;
    932 	}
    933 
    934 	/* first arg may be struct return pointer */
    935 	/* XXX - check if varargs; setup al */
    936 	switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) {
    937 	case INTEGER:
    938 	case SSE:
    939 		if (typ == SSE)
    940 			r = XMM0 + nsse++;
    941 		else
    942 			r = argregsi[ngpr++];
    943 		if (p->n_type < INT || p->n_type == BOOL)
    944 			p = cast(p, INT, 0);
    945 		p = movtoreg(p, r);
    946 		break;
    947 
    948 	case X87:
    949 		r = nrsp;
    950 		nrsp += SZLDOUBLE;
    951 		p = movtomem(p, r, STKREG);
    952 		break;
    953 
    954 	case SSEMEM:
    955 		r = nrsp;
    956 		nrsp += SZDOUBLE;
    957 		p = movtomem(p, r, STKREG);
    958 		break;
    959 
    960 	case INTMEM:
    961 		r = nrsp;
    962 		nrsp += SZLONG;
    963 		if (p->n_type < INT || p->n_type == BOOL)
    964 			p = cast(p, INT, 0);
    965 		p = movtomem(p, r, STKREG);
    966 		break;
    967 
    968 	case STRFI:
    969 	case STRIF:
    970 	case STRSSE:
    971 	case STRREG: /* Struct in registers */
    972 		/* Cast to long/sse pointer and move to the registers */
    973 		/* XXX can overrun struct size */
    974 		ssz = tsize(p->n_type, p->n_df, p->n_ap);
    975 
    976 		if (typ == STRSSE || typ == STRFI) {
    977 			r = XMM0 + nsse++;
    978 			ty = DOUBLE;
    979 		} else {
    980 			r = argregsi[ngpr++];
    981 			ty = LONG;
    982 		}
    983 
    984 		p = nfree(p);	/* remove STARG */
    985 		p = makety(p, PTR|ty, 0, 0, 0);
    986 		ql = tempnode(0, PTR|ty, 0, 0);
    987 		rn = regno(ql);
    988 		p = buildtree(ASSIGN, ql, p);
    989 		ql = tempnode(rn, PTR|ty, 0, 0);
    990 		ql = movtoreg(buildtree(UMUL, ql, NIL), r);
    991 		p = buildtree(COMOP, p, ql);
    992 
    993 		if (ssz > SZLONG) {
    994 			if (typ == STRSSE || typ == STRIF) {
    995 				r = XMM0 + nsse++;
    996 				ty = DOUBLE;
    997 			} else {
    998 				r = argregsi[ngpr++];
    999 				ty = LONG;
   1000 			}
   1001 
   1002 			ql = tempnode(rn, PTR|ty, 0, 0);
   1003 			ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL);
   1004 			ql = movtoreg(ql, r);
   1005 
   1006 			p = buildtree(CM, p, ql);
   1007 		}
   1008 		break;
   1009 
   1010 	case STRX87:
   1011 	case STRMEM: {
   1012 		struct symtab s;
   1013 		NODE *l, *t;
   1014 
   1015 		q = buildtree(UMUL, p->n_left, NIL);
   1016 
   1017 		s.stype = p->n_type;
   1018 		s.squal = 0;
   1019 		s.sdf = p->n_df;
   1020 		s.sap = p->n_ap;
   1021 		s.soffset = nrsp;
   1022 		s.sclass = AUTO;
   1023 
   1024 		nrsp += tsize(p->n_type, p->n_df, p->n_ap);
   1025 
   1026 		l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
   1027 		slval(l, 0);
   1028 		regno(l) = STKREG;
   1029 
   1030 		t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
   1031 		t->n_sp = &s;
   1032 		t = stref(block(STREF, l, t, 0, 0, 0));
   1033 
   1034 		t = (buildtree(ASSIGN, t, q));
   1035 		nfree(p);
   1036 		p = t->n_left;
   1037 		nfree(t);
   1038 		break;
   1039 		}
   1040 
   1041 	default:
   1042 		cerror("argument %d", typ);
   1043 	}
   1044 	return p;
   1045 }
   1046 
   1047 /*
   1048  * Sort arglist so that register assignments ends up last.
   1049  */
   1050 static int
   1051 argsort(NODE *p)
   1052 {
   1053 	NODE *q, *r;
   1054 	int rv = 0;
   1055 
   1056 	if (p->n_op != CM) {
   1057 		if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
   1058 		    coptype(p->n_right->n_op) != LTYPE) {
   1059 			q = tempnode(0, p->n_type, p->n_df, p->n_ap);
   1060 			r = ccopy(q);
   1061 			p->n_right = buildtree(COMOP,
   1062 			    buildtree(ASSIGN, q, p->n_right), r);
   1063 		}
   1064 		return rv;
   1065 	}
   1066 	if (p->n_right->n_op == CM) {
   1067 		/* fixup for small structs in regs */
   1068 		q = p->n_right->n_left;
   1069 		p->n_right->n_left = p->n_left;
   1070 		p->n_left = p->n_right;
   1071 		p->n_right = p->n_left->n_right;
   1072 		p->n_left->n_right = q;
   1073 	}
   1074 	if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
   1075 	    coptype(p->n_right->n_right->n_op) != LTYPE) {
   1076 		/* move before everything to avoid reg trashing */
   1077 		q = tempnode(0, p->n_right->n_type,
   1078 		    p->n_right->n_df, p->n_right->n_ap);
   1079 		r = ccopy(q);
   1080 		p->n_right->n_right = buildtree(COMOP,
   1081 		    buildtree(ASSIGN, q, p->n_right->n_right), r);
   1082 	}
   1083 	if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
   1084 		if (p->n_left->n_op == CM &&
   1085 		    p->n_left->n_right->n_op == STASG) {
   1086 			q = p->n_left->n_right;
   1087 			p->n_left->n_right = p->n_right;
   1088 			p->n_right = q;
   1089 			rv = 1;
   1090 		} else if (p->n_left->n_op == STASG) {
   1091 			q = p->n_left;
   1092 			p->n_left = p->n_right;
   1093 			p->n_right = q;
   1094 			rv = 1;
   1095 		}
   1096 	}
   1097 	return rv | argsort(p->n_left);
   1098 }
   1099 
   1100 /*
   1101  * Called with a function call with arguments as argument.
   1102  * This is done early in buildtree() and only done once.
   1103  * Returns p.
   1104  */
   1105 NODE *
   1106 funcode(NODE *p)
   1107 {
   1108 	NODE *l, *r;
   1109 	TWORD t;
   1110 	int i;
   1111 
   1112 	nsse = ngpr = nrsp = 0;
   1113 	/* Check if hidden arg needed */
   1114 	/* If so, add it in pass2 */
   1115 	if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
   1116 	    l->n_type == INCREF(FTN)+UNIONTY) {
   1117 		int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap);
   1118 		struct symtab *sp = strmemb(l->n_ap);
   1119 		if (ssz == 2*SZLDOUBLE && sp->stype == LDOUBLE &&
   1120 		    sp->snext->stype == LDOUBLE)
   1121 			; /* long complex struct */
   1122 		else if (ssz > 2*SZLONG)
   1123 			ngpr++;
   1124 	}
   1125 
   1126 	/* Convert just regs to assign insn's */
   1127 	p->n_right = argput(p->n_right);
   1128 
   1129 	/* Must sort arglist so that STASG ends up first */
   1130 	/* This avoids registers being clobbered */
   1131 	while (argsort(p->n_right))
   1132 		;
   1133 	/* Check if there are varargs */
   1134 	if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
   1135 		; /* Need RAX */
   1136 	} else {
   1137 		union arglist *al = l->n_df->dfun;
   1138 
   1139 		for (; al->type != TELLIPSIS; al++) {
   1140 			if ((t = al->type) == TNULL)
   1141 				return p; /* No need */
   1142 			if (ISSOU(BTYPE(t)))
   1143 				al++;
   1144 			for (i = 0; t > BTMASK; t = DECREF(t))
   1145 				if (ISARY(t) || ISFTN(t))
   1146 					i++;
   1147 			if (i)
   1148 				al++;
   1149 		}
   1150 	}
   1151 
   1152 	/* Always emit number of SSE regs used */
   1153 	l = movtoreg(bcon(nsse), RAX);
   1154 	if (p->n_right->n_op != CM) {
   1155 		p->n_right = block(CM, l, p->n_right, INT, 0, 0);
   1156 	} else {
   1157 		for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
   1158 			;
   1159 		r->n_left = block(CM, l, r->n_left, INT, 0, 0);
   1160 	}
   1161 	return p;
   1162 }
   1163 
   1164 /* fix up type of field p */
   1165 void
   1166 fldty(struct symtab *p)
   1167 {
   1168 }
   1169 
   1170 /*
   1171  * XXX - fix genswitch.
   1172  */
   1173 int
   1174 mygenswitch(int num, TWORD type, struct swents **p, int n)
   1175 {
   1176 	return 0;
   1177 }
   1178 
   1179 /*
   1180  * Return return as given by a.
   1181  */
   1182 NODE *
   1183 builtin_return_address(const struct bitable *bt, NODE *a)
   1184 {
   1185 	int nframes;
   1186 	NODE *f;
   1187 
   1188 	nframes = glval(a);
   1189 	tfree(a);
   1190 
   1191 	f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
   1192 	regno(f) = FPREG;
   1193 
   1194 	while (nframes--)
   1195 		f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
   1196 
   1197 	f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
   1198 	f = buildtree(UMUL, f, NIL);
   1199 
   1200 	return f;
   1201 }
   1202 
   1203 /*
   1204  * Return frame as given by a.
   1205  */
   1206 NODE *
   1207 builtin_frame_address(const struct bitable *bt, NODE *a)
   1208 {
   1209 	int nframes;
   1210 	NODE *f;
   1211 
   1212 	nframes = glval(a);
   1213 	tfree(a);
   1214 
   1215 	f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
   1216 	regno(f) = FPREG;
   1217 
   1218 	while (nframes--)
   1219 		f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
   1220 
   1221 	return f;
   1222 }
   1223 
   1224 /*
   1225  * Return "canonical frame address".
   1226  */
   1227 NODE *
   1228 builtin_cfa(const struct bitable *bt, NODE *a)
   1229 {
   1230 	NODE *f;
   1231 
   1232 	f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
   1233 	regno(f) = FPREG;
   1234 	return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0);
   1235 }
   1236 
   1237 int codeatyp(NODE *);
   1238 int
   1239 codeatyp(NODE *p)
   1240 {
   1241 	TWORD t;
   1242 	int typ;
   1243 
   1244 	ngpr = nsse = 0;
   1245 	t = DECREF(p->n_type);
   1246 	if (ISSOU(t) == 0) {
   1247 		p = p->n_left;
   1248 		t = DECREF(DECREF(p->n_type));
   1249 	}
   1250 	if (ISSOU(t) == 0)
   1251 		cerror("codeatyp");
   1252 	typ = argtyp(t, p->n_df, p->n_ap);
   1253 	return typ;
   1254 }
   1255