xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/amd64/local2.c (revision 41b9722a1abf231082724f766574d77aa46a5bdd)
1 /*	Id: local2.c,v 1.62 2015/12/13 09:00:04 ragge Exp 	*/
2 /*	$NetBSD: local2.c,v 1.4 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 # include "pass2.h"
32 # include <ctype.h>
33 # include <string.h>
34 
35 static int stkpos;
36 
37 void
deflab(int label)38 deflab(int label)
39 {
40 	printf(LABFMT ":\n", label);
41 }
42 
43 static int regoff[MAXREGS];
44 static TWORD ftype;
45 char *rbyte[], *rshort[], *rlong[];
46 static int needframe;
47 
48 /*
49  * Print out the prolog assembler.
50  * addto and regoff are already calculated.
51  */
52 static void
prtprolog(struct interpass_prolog * ipp,int addto)53 prtprolog(struct interpass_prolog *ipp, int addto)
54 {
55 	int i;
56 
57 	printf("\tpushq %%rbp\n");
58 	printf("\tmovq %%rsp,%%rbp\n");
59 	addto = (addto+15) & ~15; /* 16-byte aligned */
60 	if (addto)
61 		printf("\tsubq $%d,%%rsp\n", addto);
62 
63 	/* save permanent registers */
64 	for (i = 0; i < MAXREGS; i++)
65 		if (TESTBIT(ipp->ipp_regs, i))
66 			printf("\tmovq %s,-%d(%s)\n",
67 			    rnames[i], regoff[i], rnames[FPREG]);
68 }
69 
70 /*
71  * calculate stack size and offsets
72  */
73 static int
offcalc(struct interpass_prolog * ipp)74 offcalc(struct interpass_prolog *ipp)
75 {
76 	int i, addto;
77 
78 	addto = p2maxautooff;
79 	if (addto >= AUTOINIT/SZCHAR)
80 		addto -= AUTOINIT/SZCHAR;
81 	for (i = 0; i < MAXREGS; i++)
82 		if (TESTBIT(ipp->ipp_regs, i)) {
83 			addto += SZLONG/SZCHAR;
84 			regoff[i] = addto;
85 		}
86 	return addto;
87 }
88 
89 /*
90  * Traverse a tree to check if we need to emit a frame at all.
91  * We emit it if:
92  * - any function call
93  * - rsp or rbp referenced
94  * Return 1 if frame is needed, 0 otherwise.
95  */
96 static int
chkf(NODE * p)97 chkf(NODE *p)
98 {
99 	int o = p->n_op;
100 
101 	if ((o == REG || o == OREG) && (regno(p) == RBP || regno(p) == RSP))
102 		return 1;
103 	if (callop(o))
104 		return 1;
105 	if (optype(o) == UTYPE)
106 		return chkf(p->n_left);
107 	else if (optype(o) == BITYPE)
108 		return chkf(p->n_left) || chkf(p->n_right);
109 	return 0;
110 }
111 
112 static int
chkframe(struct interpass_prolog * ipp)113 chkframe(struct interpass_prolog *ipp)
114 {
115 	struct interpass *ip;
116 
117 	DLIST_FOREACH(ip, &ipp->ipp_ip, qelem) {
118 		if (ip->type == IP_EPILOG)
119 			break;
120 		if (ip->type == IP_NODE) {
121 			if (chkf(ip->ip_node))
122 				return 1;
123 		}
124 	}
125 	return 0;
126 }
127 
128 void
prologue(struct interpass_prolog * ipp)129 prologue(struct interpass_prolog *ipp)
130 {
131 	int addto;
132 
133 	ftype = ipp->ipp_type;
134 
135 	if (xdeljumps)
136 		needframe = chkframe(ipp);
137 	else
138 		needframe = 1;
139 
140 #ifdef LANG_F77
141 	if (ipp->ipp_vis)
142 		printf("	.globl %s\n", ipp->ipp_name);
143 	printf("	.align 16\n");
144 	printf("%s:\n", ipp->ipp_name);
145 #endif
146 	/*
147 	 * We here know what register to save and how much to
148 	 * add to the stack.
149 	 */
150 	addto = offcalc(ipp);
151 	if (addto)
152 		needframe = 1;
153 	if (needframe)
154 		prtprolog(ipp, addto);
155 }
156 
157 void
eoftn(struct interpass_prolog * ipp)158 eoftn(struct interpass_prolog *ipp)
159 {
160 	int i;
161 
162 	if (ipp->ipp_ip.ip_lbl == 0)
163 		return; /* no code needs to be generated */
164 
165 	if (needframe) {
166 		/* return from function code */
167 		for (i = 0; i < MAXREGS; i++)
168 			if (TESTBIT(ipp->ipp_regs, i))
169 				printf("	movq -%d(%s),%s\n",
170 				    regoff[i], rnames[FPREG], rnames[i]);
171 
172 		/* struct return needs special treatment */
173 		if (ftype == STRTY || ftype == UNIONTY) {
174 			printf("	movl 8(%%ebp),%%eax\n");
175 			printf("	leave\n");
176 			printf("	ret $%d\n", 4);
177 		} else {
178 			printf("	leave\n");
179 			printf("	ret\n");
180 		}
181 	} else
182 		printf("\tret\n");
183 
184 #ifndef MACHOABI
185 	printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name);
186 #endif
187 }
188 
189 /*
190  * add/sub/...
191  *
192  * Param given:
193  */
194 void
hopcode(int f,int o)195 hopcode(int f, int o)
196 {
197 	char *str;
198 
199 	switch (o) {
200 	case PLUS:
201 		str = "add";
202 		break;
203 	case MINUS:
204 		str = "sub";
205 		break;
206 	case AND:
207 		str = "and";
208 		break;
209 	case OR:
210 		str = "or";
211 		break;
212 	case ER:
213 		str = "xor";
214 		break;
215 	default:
216 		comperr("hopcode2: %d", o);
217 		str = 0; /* XXX gcc */
218 	}
219 	printf("%s%c", str, f);
220 }
221 
222 /*
223  * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
224  */
225 int
tlen(NODE * p)226 tlen(NODE *p)
227 {
228 	switch(p->n_type) {
229 		case CHAR:
230 		case UCHAR:
231 			return(1);
232 
233 		case SHORT:
234 		case USHORT:
235 			return(SZSHORT/SZCHAR);
236 
237 		case DOUBLE:
238 			return(SZDOUBLE/SZCHAR);
239 
240 		case INT:
241 		case UNSIGNED:
242 			return(SZINT/SZCHAR);
243 
244 		case LONG:
245 		case ULONG:
246 		case LONGLONG:
247 		case ULONGLONG:
248 			return SZLONGLONG/SZCHAR;
249 
250 		default:
251 			if (!ISPTR(p->n_type))
252 				comperr("tlen type %d not pointer");
253 			return SZPOINT(p->n_type)/SZCHAR;
254 		}
255 }
256 
257 /*
258  * Compare two floating point numbers.
259  */
260 static void
fcomp(NODE * p)261 fcomp(NODE *p)
262 {
263 
264 	if (p->n_left->n_op != REG)
265 		comperr("bad compare %p\n", p);
266 	if ((p->n_su & DORIGHT) == 0)
267 		expand(p, 0, "\tfxch\n");
268 	expand(p, 0, "\tfucomip %st(1),%st\n");	/* emit compare insn  */
269 	expand(p, 0, "\tfstp %st(0)\n");	/* pop fromstack */
270 	zzzcode(p, 'U');
271 }
272 
273 int
fldexpand(NODE * p,int cookie,char ** cp)274 fldexpand(NODE *p, int cookie, char **cp)
275 {
276 	comperr("fldexpand");
277 	return 0;
278 }
279 
280 static void
stasg(NODE * p)281 stasg(NODE *p)
282 {
283 	struct attr *ap = attr_find(p->n_ap, ATTR_P2STRUCT);
284 	expand(p, INAREG, "	leaq AL,%rdi\n");
285 	if (ap->iarg(0) >= 8)
286 		printf("\tmovl $%d,%%ecx\n\trep movsq\n", ap->iarg(0) >> 3);
287 	if (ap->iarg(0) & 4)
288 		printf("\tmovsl\n");
289 	if (ap->iarg(0) & 2)
290 		printf("\tmovsw\n");
291 	if (ap->iarg(0) & 1)
292 		printf("\tmovsb\n");
293 }
294 
295 #define	E(x)	expand(p, 0, x)
296 /*
297  * Generate code to convert an unsigned long to xmm float/double.
298  */
299 static void
ultofd(NODE * p)300 ultofd(NODE *p)
301 {
302 
303 	E("	movq AL,A1\n");
304 	E("	testq A1,A1\n");
305 	E("	js 2f\n");
306 	E("	cvtsi2sZfq A1,A3\n");
307 	E("	jmp 3f\n");
308 	E("2:\n");
309 	E("	movq A1,A2\n");
310 	E("	shrq A2\n");
311 	E("	andq $1,A1\n");
312 	E("	orq A1,A2\n");
313 	E("	cvtsi2sZfq A2,A3\n");
314 	E("	addsZf A3,A3\n");
315 	E("3:\n");
316 }
317 
318 /*
319  * Generate code to convert an x87 long double to an unsigned long.
320  * This is ugly :-/
321  */
322 static void
ldtoul(NODE * p)323 ldtoul(NODE *p)
324 {
325 
326 	E("	subq $16,%rsp\n");
327 	E("	movl $0x5f000000,(%rsp)\n"); /* More than long can have */
328 	E("	flds (%rsp)\n");
329 	if (p->n_left->n_op == REG) {
330 		E("	fxch\n");
331 	} else
332 		E("	fldt AL\n");
333 	E("	fucomi %st(1), %st\n");
334 	E("	jae 2f\n");
335 
336 	E("	fstp %st(1)\n");	 /* Pop huge val from stack */
337 	E("	fnstcw (%rsp)\n");	 /* store cw */
338 	E("	movw $0x0f3f,4(%rsp)\n");/* round towards 0 */
339 	E("	fldcw 4(%rsp)\n");	 /* new cw */
340 	E("	fistpll 8(%rsp)\n");	 /* save val */
341 	E("	fldcw (%rsp)\n");	 /* fetch old cw */
342 	E("	movq 8(%rsp),A1\n");
343 
344 	E("	jmp 3f\n");
345 
346 	E("2:\n");
347 
348 	E("	fsubp %st, %st(1)\n");
349 	E("	fnstcw (%rsp)\n");
350 	E("	movw $0x0f3f,4(%rsp)\n");
351 	E("	fldcw 4(%rsp)\n");
352 	E("	fistpll 8(%rsp)\n");
353 	E("	fldcw (%rsp)\n");
354 	E("	movabsq $0x8000000000000000,A1\n");
355 	E("	xorq 8(%rsp),A1\n");
356 
357 	E("3:	addq $16,%rsp\n");
358 }
359 
360 /*
361  * Generate code to convert an SSE float/double to an unsigned long.
362  */
363 static void
fdtoul(NODE * p)364 fdtoul(NODE *p)
365 {
366 	if (p->n_left->n_type == FLOAT)
367 		E("	movabsq $0x5f000000,A1\n");
368 	else
369 		E("	movabsq $0x43e0000000000000,A1\n");
370 	E("	movd A1,A3\n");
371 	E("	ucomisZg A3,AL\n");
372 	E("	jae 2f\n");
373 	E("	cvttsZg2siq AL,A1\n");
374 	E("	jmp 3f\n");
375 	E("2:\n");
376 	E("	subsZg A3,AL\n");
377 	E("	cvttsZg2siq AL,A1\n");
378 	E("	movabsq $0x8000000000000000,A2\n");
379 	E("	xorq A2,A1\n");
380 	E("3:\n");
381 }
382 #undef E
383 
384 void
zzzcode(NODE * p,int c)385 zzzcode(NODE *p, int c)
386 {
387 	struct attr *ap, *ap2;
388 	NODE *l;
389 	int pr, lr, s;
390 	char **rt;
391 
392 	switch (c) {
393 	case 'A': /* swap st0 and st1 if right is evaluated second */
394 		if ((p->n_su & DORIGHT) == 0) {
395 			if (logop(p->n_op))
396 				printf("	fxch\n");
397 			else
398 				printf("r");
399 		}
400 		break;
401 
402 	case 'B': /* ldouble to unsigned long cast */
403 		ldtoul(p);
404 		break;
405 
406 	case 'b': /* float/double to unsigned long cast */
407 		fdtoul(p);
408 		break;
409 
410 	case 'C':  /* remove from stack after subroutine call */
411 		pr = p->n_qual;
412 		if (p->n_op == UCALL)
413 			return; /* XXX remove ZC from UCALL */
414 		if (pr)
415 			printf("	addq $%d, %s\n", pr, rnames[RSP]);
416 #define	STRREG 6
417 #define	STRSSE 8
418 #define	STRIF  9
419 #define	STRFI  10
420 #define	STRX87 11
421 		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
422 		ap2 = attr_find(p->n_ap, ATTR_AMD64_CMPLRET);
423 		if ((p->n_op == STCALL || p->n_op == USTCALL) &&
424 		    ap->iarg(0) == 32 && ap2->iarg(0) == STRX87) {
425 			printf("\tfstpt -%d(%%rbp)\n", stkpos);
426 			printf("\tfstpt -%d(%%rbp)\n", stkpos-16);
427 			printf("\tleaq -%d(%%rbp),%%rax\n", stkpos);
428 		}
429 		if ((p->n_op == STCALL || p->n_op == USTCALL) &&
430 		    ap->iarg(0) <= 16) {
431 			/* store reg-passed structs on stack */
432 			if (ap2->iarg(0) == STRREG || ap2->iarg(0) == STRIF)
433 				printf("\tmovq %%rax,-%d(%%rbp)\n", stkpos);
434 			else
435 				printf("\tmovsd %%xmm0,-%d(%%rbp)\n", stkpos);
436 			if (ap->iarg(0) > 8) {
437 				if (ap2->iarg(0) == STRREG)
438 					printf("\tmovq %%rdx");
439 				else if (ap2->iarg(0) == STRFI)
440 					printf("\tmovq %%rax");
441 				else if (ap2->iarg(0) == STRIF)
442 					printf("\tmovsd %%xmm0");
443 				else
444 					printf("\tmovsd %%xmm1");
445 				printf(",-%d(%%rbp)\n", stkpos-8);
446 			}
447 			printf("\tleaq -%d(%%rbp),%%rax\n", stkpos);
448 		}
449 		break;
450 
451 	case 'c': /* xor label */
452 		if ((ap = attr_find(p->n_ap, ATTR_AMD64_XORLBL)) == NULL)
453 			comperr("missing xor label");
454 		printf(LABFMT, ap->iarg(0));
455 		break;
456 
457 	case 'F': /* Structure argument */
458 		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
459 		printf("	subq $%d,%%rsp\n", ap->iarg(0));
460 		printf("	movq %%rsp,%%rsi\n");
461 		stasg(p);
462 		break;
463 
464 	case 'G': /* Floating point compare */
465 		fcomp(p);
466 		break;
467 
468 	case 'j': /* convert unsigned long to f/d */
469 		ultofd(p);
470 		break;
471 
472 	case 'M': /* Output sconv move, if needed */
473 		l = getlr(p, 'L');
474 		/* XXX fixneed: regnum */
475 		pr = DECRA(p->n_reg, 0);
476 		lr = DECRA(l->n_reg, 0);
477 		if (pr == lr)
478 			break;
479 		printf("	movb %s,%s\n", rbyte[lr], rbyte[pr]);
480 		l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
481 		break;
482 
483 	case 'N': /* output long reg name */
484 		printf("%s", rlong[getlr(p, '1')->n_rval]);
485 		break;
486 
487 	case 'P': /* Put hidden argument in rdi */
488 		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
489 		ap2 = attr_find(p->n_ap, ATTR_AMD64_CMPLRET);
490 		if (ap->iarg(0) > 16 && ap2->iarg(0) != STRX87)
491 			printf("\tleaq -%d(%%rbp),%%rdi\n", stkpos);
492 		break;
493 
494         case 'Q': /* emit struct assign */
495 		stasg(p);
496 		break;
497 
498 	case 'R': /* print opname based on right type */
499 	case 'L': /* print opname based on left type */
500 		switch (getlr(p, c)->n_type) {
501 		case CHAR: case UCHAR: s = 'b'; break;
502 		case SHORT: case USHORT: s = 'w'; break;
503 		case INT: case UNSIGNED: s = 'l'; break;
504 		default: s = 'q'; break;
505 		printf("%c", s);
506 		}
507 		break;
508 
509 	case 'U': { /* output branch insn for ucomi */
510 		static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
511 		if (p->n_op < EQ || p->n_op > GT)
512 			comperr("bad fp branch");
513 		if (p->n_op == NE || p->n_op == GT || p->n_op == GE)
514 			expand(p, 0, "	jp LC\n");
515 		else if (p->n_op == EQ)
516 			printf("\tjp 1f\n");
517 		printf("	%s ", fpcb[p->n_op - EQ]);
518 		expand(p, 0, "LC\n");
519 		if (p->n_op == EQ)
520 			printf("1:\n");
521 		break;
522 		}
523 
524 	case '8': /* special reg name printout (64-bit) */
525 	case '1': /* special reg name printout (32-bit) */
526 		l = getlr(p, '1');
527 		rt = c == '8' ? rnames : rlong;
528 		printf("%s", rt[l->n_rval]);
529 		break;
530 
531 	case 'g':
532 		p = p->n_left;
533 		/* FALLTHROUGH */
534 	case 'f': /* float or double */
535 		printf("%c", p->n_type == FLOAT ? 's' : 'd');
536 		break;
537 
538 	case 'q': /* int or long */
539 		printf("%c", p->n_left->n_type == LONG ? 'q' : ' ');
540 		break;
541 
542 	default:
543 		comperr("zzzcode %c", c);
544 	}
545 }
546 
547 int canaddr(NODE *);
548 int
canaddr(NODE * p)549 canaddr(NODE *p)
550 {
551 	int o = p->n_op;
552 
553 	if (o==NAME || o==REG || o==ICON || o==OREG ||
554 	    (o==UMUL && shumul(p->n_left, SOREG)))
555 		return(1);
556 	return(0);
557 }
558 
559 /*
560  * Does the bitfield shape match?
561  */
562 int
flshape(NODE * p)563 flshape(NODE *p)
564 {
565 	comperr("flshape");
566 	return(0);
567 }
568 
569 /* INTEMP shapes must not contain any temporary registers */
570 /* XXX should this go away now? */
571 int
shtemp(NODE * p)572 shtemp(NODE *p)
573 {
574 	return 0;
575 #if 0
576 	int r;
577 
578 	if (p->n_op == STARG )
579 		p = p->n_left;
580 
581 	switch (p->n_op) {
582 	case REG:
583 		return (!istreg(p->n_rval));
584 
585 	case OREG:
586 		r = p->n_rval;
587 		if (R2TEST(r)) {
588 			if (istreg(R2UPK1(r)))
589 				return(0);
590 			r = R2UPK2(r);
591 		}
592 		return (!istreg(r));
593 
594 	case UMUL:
595 		p = p->n_left;
596 		return (p->n_op != UMUL && shtemp(p));
597 	}
598 
599 	if (optype(p->n_op) != LTYPE)
600 		return(0);
601 	return(1);
602 #endif
603 }
604 
605 void
adrcon(CONSZ val)606 adrcon(CONSZ val)
607 {
608 	printf("$" CONFMT, val);
609 }
610 
611 void
conput(FILE * fp,NODE * p)612 conput(FILE *fp, NODE *p)
613 {
614 	long val = getlval(p);
615 
616 	switch (p->n_op) {
617 	case ICON:
618 		if (p->n_name[0] != '\0') {
619 			fprintf(fp, "%s", p->n_name);
620 			if (val)
621 				fprintf(fp, "+%ld", val);
622 		} else
623 			fprintf(fp, "%ld", val);
624 		return;
625 
626 	default:
627 		comperr("illegal conput, p %p", p);
628 	}
629 }
630 
631 /*ARGSUSED*/
632 void
insput(NODE * p)633 insput(NODE *p)
634 {
635 	comperr("insput");
636 }
637 
638 /*
639  * Write out the upper address, like the upper register of a 2-register
640  * reference, or the next memory location.
641  * XXX - not needed on amd64
642  */
643 void
upput(NODE * p,int size)644 upput(NODE *p, int size)
645 {
646 
647 	size /= SZCHAR;
648 	switch (p->n_op) {
649 	case REG:
650 		printf("%%%s", &rnames[p->n_rval][3]);
651 		break;
652 
653 	case NAME:
654 	case OREG:
655 		setlval(p, getlval(p) + size);
656 		adrput(stdout, p);
657 		setlval(p, getlval(p) - size);
658 		break;
659 	case ICON:
660 		printf("$" CONFMT, getlval(p) >> 32);
661 		break;
662 	default:
663 		comperr("upput bad op %d size %d", p->n_op, size);
664 	}
665 }
666 
667 void
adrput(FILE * io,NODE * p)668 adrput(FILE *io, NODE *p)
669 {
670 	int r;
671 	char **rc;
672 	/* output an address, with offsets, from p */
673 
674 	switch (p->n_op) {
675 
676 	case NAME:
677 		if (p->n_name[0] != '\0') {
678 			if (getlval(p) != 0)
679 				fprintf(io, CONFMT "+", getlval(p));
680 			fprintf(io, "%s(%%rip)", p->n_name);
681 		} else
682 			fprintf(io, CONFMT, getlval(p));
683 		return;
684 
685 	case OREG:
686 		r = p->n_rval;
687 		if (p->n_name[0])
688 			printf("%s%s", p->n_name, getlval(p) ? "+" : "");
689 		if (getlval(p))
690 			fprintf(io, "%lld", getlval(p));
691 		if (R2TEST(r)) {
692 			int r1 = R2UPK1(r);
693 			int r2 = R2UPK2(r);
694 			int sh = R2UPK3(r);
695 
696 			fprintf(io, "(%s,%s,%d)",
697 			    r1 == MAXREGS ? "" : rnames[r1],
698 			    r2 == MAXREGS ? "" : rnames[r2], sh);
699 		} else
700 			fprintf(io, "(%s)", rnames[p->n_rval]);
701 		return;
702 	case ICON:
703 		/* addressable value of the constant */
704 		fputc('$', io);
705 		conput(io, p);
706 		return;
707 
708 	case REG:
709 		switch (p->n_type) {
710 		case CHAR:
711 		case UCHAR:
712 			rc = rbyte;
713 			break;
714 		case SHORT:
715 		case USHORT:
716 			rc = rshort;
717 			break;
718 		case INT:
719 		case UNSIGNED:
720 			rc = rlong;
721 			break;
722 		default:
723 			rc = rnames;
724 			break;
725 		}
726 		fprintf(io, "%s", rc[p->n_rval]);
727 		return;
728 
729 	default:
730 		comperr("illegal address, op %d, node %p", p->n_op, p);
731 		return;
732 
733 	}
734 }
735 
736 static char *
737 ccbranches[] = {
738 	"je",		/* jumpe */
739 	"jne",		/* jumpn */
740 	"jle",		/* jumple */
741 	"jl",		/* jumpl */
742 	"jge",		/* jumpge */
743 	"jg",		/* jumpg */
744 	"jbe",		/* jumple (jlequ) */
745 	"jb",		/* jumpl (jlssu) */
746 	"jae",		/* jumpge (jgequ) */
747 	"ja",		/* jumpg (jgtru) */
748 };
749 
750 
751 /*   printf conditional and unconditional branches */
752 void
cbgen(int o,int lab)753 cbgen(int o, int lab)
754 {
755 	if (o < EQ || o > UGT)
756 		comperr("bad conditional branch: %s", opst[o]);
757 	printf("	%s " LABFMT "\n", ccbranches[o-EQ], lab);
758 }
759 
760 /*
761  * gcc xasm has the ability to generate different asm types
762  * via some magic.
763  *
764  * Only support AT&T asm for now.
765  */
766 static char *
adjustname(char * s)767 adjustname(char *s)
768 {
769 	int len = strlen(s);
770 	char *d = tmpalloc(len+1);
771 	int i, j, flvl, tlvl;
772 
773 	flvl = tlvl = 0;
774 	for (i = j = 0; i < len; i++) {
775 		switch (s[i]) {
776 		case '{': tlvl++; break;
777 		case '}': if (tlvl)tlvl--; else flvl--; break;
778 		case '|': tlvl--; flvl++; break;
779 		default:
780 			if (flvl == 0)
781 				d[j++] = s[i];
782 			break;
783 		}
784 	}
785 	d[j] = 0;
786 	return d;
787 }
788 
789 static void
fixcalls(NODE * p,void * arg)790 fixcalls(NODE *p, void *arg)
791 {
792 	int ps;
793 
794 	/* Prepare for struct return by allocating bounce space on stack */
795 	switch (p->n_op) {
796 	case STCALL:
797 	case USTCALL:
798 		ps = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
799 		if (ps < 16)
800 			ps = 16;
801 		if (ps+p2autooff > stkpos)
802 			stkpos = ps+p2autooff;
803 		break;
804 	case XASM:
805 		p->n_name = adjustname(p->n_name);
806 		break;
807 	}
808 }
809 
810 void
myreader(struct interpass * ipole)811 myreader(struct interpass *ipole)
812 {
813 	struct interpass *ip;
814 
815 	stkpos = p2autooff;
816 	DLIST_FOREACH(ip, ipole, qelem) {
817 		if (ip->type != IP_NODE)
818 			continue;
819 		walkf(ip->ip_node, fixcalls, 0);
820 	}
821 	if (stkpos > p2autooff)
822 		p2autooff = stkpos;
823 	if (stkpos > p2maxautooff)
824 		p2maxautooff = stkpos;
825 	if (x2debug)
826 		printip(ipole);
827 }
828 
829 /*
830  * Remove some PCONVs after OREGs are created.
831  */
832 static void
pconv2(NODE * p,void * arg)833 pconv2(NODE *p, void *arg)
834 {
835 	NODE *q;
836 
837 	if (p->n_op == PLUS) {
838 		if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
839 			if (p->n_right->n_op != ICON)
840 				return;
841 			if (p->n_left->n_op != PCONV)
842 				return;
843 			if (p->n_left->n_left->n_op != OREG)
844 				return;
845 			q = p->n_left->n_left;
846 			nfree(p->n_left);
847 			p->n_left = q;
848 			/*
849 			 * This will be converted to another OREG later.
850 			 */
851 		}
852 	}
853 }
854 
855 void
mycanon(NODE * p)856 mycanon(NODE *p)
857 {
858 	walkf(p, pconv2, 0);
859 }
860 
861 void
myoptim(struct interpass * ip)862 myoptim(struct interpass *ip)
863 {
864 }
865 
866 void
rmove(int s,int d,TWORD t)867 rmove(int s, int d, TWORD t)
868 {
869 
870 	switch (t) {
871 	case INT:
872 	case UNSIGNED:
873 		printf("	movl %s,%s\n", rlong[s], rlong[d]);
874 		break;
875 	case CHAR:
876 	case UCHAR:
877 		printf("	movb %s,%s\n", rbyte[s], rbyte[d]);
878 		break;
879 	case SHORT:
880 	case USHORT:
881 		printf("	movw %s,%s\n", rshort[s], rshort[d]);
882 		break;
883 	case FLOAT:
884 		printf("	movss %s,%s\n", rnames[s], rnames[d]);
885 		break;
886 	case DOUBLE:
887 		printf("	movsd %s,%s\n", rnames[s], rnames[d]);
888 		break;
889 	case LDOUBLE:
890 #ifdef notdef
891 		/* a=b()*c(); will generate this */
892 		/* XXX can it fail anyway? */
893 		comperr("bad float rmove: %d %d", s, d);
894 #endif
895 		break;
896 	default:
897 		printf("	movq %s,%s\n", rnames[s], rnames[d]);
898 		break;
899 	}
900 }
901 
902 /*
903  * For class c, find worst-case displacement of the number of
904  * registers in the array r[] indexed by class.
905  */
906 int
COLORMAP(int c,int * r)907 COLORMAP(int c, int *r)
908 {
909 
910 	switch (c) {
911 	case CLASSA:
912 		return r[CLASSA] < 14;
913 	case CLASSB:
914 		return r[CLASSB] < 16;
915 	case CLASSC:
916 		return r[CLASSC] < CREGCNT;
917 	}
918 	return 0; /* XXX gcc */
919 }
920 
921 char *rnames[] = {
922 	"%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp",
923 	"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
924 	"%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
925 	"%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14",
926 	"%xmm15",
927 };
928 
929 /* register names for shorter sizes */
930 char *rbyte[] = {
931 	"%al", "%dl", "%cl", "%bl", "%sil", "%dil", "%bpl", "%spl",
932 	"%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b",
933 };
934 char *rshort[] = {
935 	"%ax", "%dx", "%cx", "%bx", "%si", "%di", "%bp", "%sp",
936 	"%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w",
937 };
938 char *rlong[] = {
939 	"%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
940 	"%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d",
941 };
942 
943 
944 /*
945  * Return a class suitable for a specific type.
946  */
947 int
gclass(TWORD t)948 gclass(TWORD t)
949 {
950 	if (t == LDOUBLE)
951 		return CLASSC;
952 	if (t == FLOAT || t == DOUBLE)
953 		return CLASSB;
954 	return CLASSA;
955 }
956 
957 static int
argsiz(NODE * p)958 argsiz(NODE *p)
959 {
960 	TWORD t = p->n_type;
961 
962 	if (p->n_left->n_op == REG)
963 		return 0; /* not on stack */
964 	if (t == LDOUBLE)
965 		return 16;
966 	if (p->n_op == STASG)
967 		return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
968 	return 8;
969 }
970 
971 /*
972  * Calculate argument sizes.
973  */
974 void
lastcall(NODE * p)975 lastcall(NODE *p)
976 {
977 	NODE *op = p;
978 	int size = 0;
979 
980 	p->n_qual = 0;
981 	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
982 		return;
983 	for (p = p->n_right; p->n_op == CM; p = p->n_left)
984 		size += argsiz(p->n_right);
985 	size += argsiz(p);
986 	size = (size+15) & ~15;
987 	if (size)
988 		printf("	subq $%d,%s\n", size, rnames[RSP]);
989 	op->n_qual = size; /* XXX */
990 }
991 
992 /*
993  * Special shapes.
994  */
995 int
special(NODE * p,int shape)996 special(NODE *p, int shape)
997 {
998 	int o = p->n_op;
999 
1000 	switch (shape) {
1001 	case SFUNCALL:
1002 		if (o == STCALL || o == USTCALL)
1003 			return SRREG;
1004 		break;
1005 	case SPCON:
1006 		if (o != ICON || p->n_name[0] ||
1007 		    getlval(p) < 0 || getlval(p) > 0x7fffffff)
1008 			break;
1009 		return SRDIR;
1010 	case SMIXOR:
1011 		return tshape(p, SZERO);
1012 	case SMILWXOR:
1013 		if (o != ICON || p->n_name[0] ||
1014 		    getlval(p) == 0 || getlval(p) & 0xffffffff)
1015 			break;
1016 		return SRDIR;
1017 	case SMIHWXOR:
1018 		if (o != ICON || p->n_name[0] ||
1019 		     getlval(p) == 0 || (getlval(p) >> 32) != 0)
1020 			break;
1021 		return SRDIR;
1022 	case SCON32:
1023 		if (o != ICON || p->n_name[0])
1024 			break;
1025 		if (getlval(p) < MIN_INT || getlval(p) > MAX_INT)
1026 			break;
1027 		return SRDIR;
1028 	default:
1029 		cerror("special: %x\n", shape);
1030 	}
1031 	return SRNOPE;
1032 }
1033 
1034 /*
1035  * Target-dependent command-line options.
1036  */
1037 void
mflags(char * str)1038 mflags(char *str)
1039 {
1040 }
1041 
1042 /*
1043  * Do something target-dependent for xasm arguments.
1044  */
1045 int
myxasm(struct interpass * ip,NODE * p)1046 myxasm(struct interpass *ip, NODE *p)
1047 {
1048 	struct interpass *ip2;
1049 	int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 };
1050 	NODE *in = 0, *ut = 0;
1051 	TWORD t;
1052 	char *w;
1053 	int reg;
1054 	int c, cw, v;
1055 
1056 	cw = xasmcode(p->n_name);
1057 	if (cw & (XASMASG|XASMINOUT))
1058 		ut = p->n_left;
1059 	if ((cw & XASMASG) == 0)
1060 		in = p->n_left;
1061 
1062 	c = XASMVAL(cw);
1063 retry:	switch (c) {
1064 	case 'D': reg = RDI; break;
1065 	case 'S': reg = RSI; break;
1066 	case 'A':
1067 	case 'a': reg = RAX; break;
1068 	case 'b': reg = RBX; break;
1069 	case 'c': reg = RCX; break;
1070 	case 'd': reg = RDX; break;
1071 
1072 	case 'Q': reg = RDX; break; /* Always dx for now */
1073 
1074 	case 'x':
1075 	case 'q':
1076 	case 't':
1077 	case 'u':
1078 		p->n_name = tmpstrdup(p->n_name);
1079 		w = strchr(p->n_name, c);
1080 		*w = 'r'; /* now reg */
1081 		return c == 'q' || c == 'x' || c == 't' ? 0 : 1;
1082 
1083 	case 'I':
1084 	case 'J':
1085 	case 'K':
1086 	case 'L':
1087 	case 'M':
1088 	case 'N':
1089 		if (p->n_left->n_op != ICON) {
1090 			if ((c = XASMVAL1(cw))) {
1091 				if (c == 'r') {
1092 					p->n_name++;
1093 					return 0;
1094 				}
1095 				goto retry;
1096 			}
1097 			uerror("xasm arg not constant");
1098 		}
1099 		v = getlval(p->n_left);
1100 		if ((c == 'K' && v < -128) ||
1101 		    (c == 'L' && v != 0xff && v != 0xffff) ||
1102 		    (c != 'K' && v < 0) ||
1103 		    (v > Cmax[c-'I']))
1104 			uerror("xasm val out of range");
1105 		p->n_name = "i";
1106 		return 1;
1107 
1108 	default:
1109 		return 0;
1110 	}
1111 	/* If there are requested either memory or register, delete memory */
1112 	w = p->n_name = tmpstrdup(p->n_name);
1113 	if (*w == '=')
1114 		w++;
1115 	*w++ = 'r';
1116 	*w = 0;
1117 
1118 	t = p->n_left->n_type;
1119 
1120 	if (t == FLOAT || t == DOUBLE) {
1121 		reg += 16;
1122 	} else if (t == LDOUBLE) {
1123 		reg += 32;
1124 	}
1125 
1126 	if (in && ut)
1127 		in = tcopy(in);
1128 	p->n_left = mklnode(REG, 0, reg, t);
1129 	if (ut) {
1130 		ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
1131 		DLIST_INSERT_AFTER(ip, ip2, qelem);
1132 	}
1133 	if (in) {
1134 		ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
1135 		DLIST_INSERT_BEFORE(ip, ip2, qelem);
1136 	}
1137 
1138 	return 1;
1139 }
1140 
1141 void
targarg(char * w,void * arg,int n)1142 targarg(char *w, void *arg, int n)
1143 {
1144 	NODE **ary = arg;
1145 	NODE *p, *q;
1146 
1147 	if (w[1] < '0' || w[1] > (n + '0'))
1148 		uerror("bad xasm arg number %c", w[1]);
1149 	if (w[1] == (n + '0'))
1150 		p = ary[(int)w[1]-'0' - 1]; /* XXX */
1151 	else
1152 		p = ary[(int)w[1]-'0'];
1153 	p = p->n_left;
1154 
1155 	if (optype(p->n_op) != LTYPE)
1156 		comperr("bad xarg op %d", p->n_op);
1157 	q = tcopy(p);
1158 	if (q->n_op == REG) {
1159 		if (*w == 'k') {
1160 			q->n_type = INT;
1161 		} else if (*w == 'q') {
1162 			q->n_type = LONG;
1163 		} else if (*w == 'h' || *w == 'b') {
1164 			/* Can do this only because we know dx is used */
1165 			printf("%%d%c", *w == 'h' ? 'h' : 'l');
1166 			tfree(q);
1167 			return;
1168 		} else if (*w != 'w') {
1169 			cerror("targarg"); /* XXX ??? */
1170 			if (q->n_type > UCHAR) {
1171 				regno(q) = regno(q)*2+8;
1172 				if (*w == 'h')
1173 					regno(q)++;
1174 			}
1175 			q->n_type = INT;
1176 		} else
1177 			q->n_type = SHORT;
1178 	}
1179 	adrput(stdout, q);
1180 	tfree(q);
1181 }
1182 
1183 /*
1184  * target-specific conversion of numeric arguments.
1185  */
1186 int
numconv(void * ip,void * p1,void * q1)1187 numconv(void *ip, void *p1, void *q1)
1188 {
1189 	NODE *p = p1, *q = q1;
1190 	int cw = xasmcode(q->n_name);
1191 
1192 	switch (XASMVAL(cw)) {
1193 	case 'a':
1194 	case 'b':
1195 	case 'c':
1196 	case 'd':
1197 		p->n_name = tmpcalloc(2);
1198 		p->n_name[0] = XASMVAL(cw);
1199 		return 1;
1200 	default:
1201 		return 0;
1202 	}
1203 }
1204 
1205 static struct {
1206 	char *name; int num;
1207 } xcr[] = {
1208 	{ "rax", RAX },
1209 	{ "rbx", RBX },
1210 	{ "rcx", RCX },
1211 	{ "rdx", RDX },
1212 	{ "rsi", RSI },
1213 	{ "rdi", RDI },
1214 	{ "r8", R08 },
1215 	{ "r9", R09 },
1216 	{ "r10", R10 },
1217 	{ "r11", R11 },
1218 	{ "r12", R12 },
1219 	{ "r13", R13 },
1220 	{ "r14", R14 },
1221 	{ "r15", R15 },
1222 	{ "st", 040 },
1223 	{ "st(0)", 040 },
1224 	{ "st(1)", 041 },
1225 	{ "st(2)", 042 },
1226 	{ "st(3)", 043 },
1227 	{ "st(4)", 044 },
1228 	{ "st(5)", 045 },
1229 	{ "st(6)", 046 },
1230 	{ "st(7)", 047 },
1231 	{ NULL, 0 },
1232 };
1233 
1234 /*
1235  * Check for other names of the xasm constraints registers.
1236  */
xasmconstregs(char * s)1237 int xasmconstregs(char *s)
1238 {
1239 	int i;
1240 
1241 	for (i = 0; xcr[i].name; i++)
1242 		if (strcmp(xcr[i].name, s) == 0)
1243 			return xcr[i].num;
1244 	return -1;
1245 }
1246 
1247