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