xref: /netbsd/external/bsd/pcc/dist/pcc/arch/amd64/code.c (revision c555ae24)
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@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
setseg(int seg,char * name)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
setseg(int seg,char * name)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
defloc(struct symtab * sp)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
efcode(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
bfcode(struct symtab ** s,int cnt)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
ejobcode(int flag)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
bjobcode(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 *
mkstkref(int off,TWORD typ)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 *
amd64_builtin_stdarg_start(const struct bitable * bt,NODE * a)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 *
mkvacall(char * fun,NODE * a,int typ)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 *
amd64_builtin_va_arg(const struct bitable * bt,NODE * a)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 *
amd64_builtin_va_end(const struct bitable * bt,NODE * a)696 amd64_builtin_va_end(const struct bitable *bt, NODE *a)
697 {
698 	tfree(a);
699 	return bcon(0); /* nothing */
700 }
701 
702 NODE *
amd64_builtin_va_copy(const struct bitable * bt,NODE * a)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 *
movtoreg(NODE * p,int rno)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 *
movtomem(NODE * p,int off,int reg)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
classifystruct(struct symtab * sp,int off)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
iscplx87(struct symtab * sp)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
argtyp(TWORD t,union dimfun * df,struct attr * ap)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 *
argput(NODE * p)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
argsort(NODE * p)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 *
funcode(NODE * p)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
fldty(struct symtab * p)1166 fldty(struct symtab *p)
1167 {
1168 }
1169 
1170 /*
1171  * XXX - fix genswitch.
1172  */
1173 int
mygenswitch(int num,TWORD type,struct swents ** p,int n)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 *
builtin_return_address(const struct bitable * bt,NODE * a)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 *
builtin_frame_address(const struct bitable * bt,NODE * a)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 *
builtin_cfa(const struct bitable * bt,NODE * a)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
codeatyp(NODE * p)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