xref: /netbsd/external/bsd/pcc/dist/pcc/arch/amd64/local2.c (revision 6550d01e)
1 /*	Id: local2.c,v 1.18 2010/05/30 15:32:45 ragge Exp 	*/
2 /*	$NetBSD: local2.c,v 1.1.1.2 2010/06/03 18:57:08 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
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 
47 /*
48  * Print out the prolog assembler.
49  * addto and regoff are already calculated.
50  */
51 static void
52 prtprolog(struct interpass_prolog *ipp, int addto)
53 {
54 	int i;
55 
56 	/* XXX should look if there is any need to emit this */
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 			fprintf(stdout, "\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
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 void
90 prologue(struct interpass_prolog *ipp)
91 {
92 	int addto;
93 
94 	ftype = ipp->ipp_type;
95 
96 #ifdef LANG_F77
97 	if (ipp->ipp_vis)
98 		printf("	.globl %s\n", ipp->ipp_name);
99 	printf("	.align 16\n");
100 	printf("%s:\n", ipp->ipp_name);
101 #endif
102 	/*
103 	 * We here know what register to save and how much to
104 	 * add to the stack.
105 	 */
106 	addto = offcalc(ipp);
107 	prtprolog(ipp, addto);
108 }
109 
110 void
111 eoftn(struct interpass_prolog *ipp)
112 {
113 	int i;
114 
115 	if (ipp->ipp_ip.ip_lbl == 0)
116 		return; /* no code needs to be generated */
117 
118 	/* return from function code */
119 	for (i = 0; i < MAXREGS; i++)
120 		if (TESTBIT(ipp->ipp_regs, i))
121 			fprintf(stdout, "	movq -%d(%s),%s\n",
122 			    regoff[i], rnames[FPREG], rnames[i]);
123 
124 	/* struct return needs special treatment */
125 	if (ftype == STRTY || ftype == UNIONTY) {
126 		printf("	movl 8(%%ebp),%%eax\n");
127 		printf("	leave\n");
128 		printf("	ret $%d\n", 4);
129 	} else {
130 		printf("	leave\n");
131 		printf("	ret\n");
132 	}
133 	printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name);
134 }
135 
136 /*
137  * add/sub/...
138  *
139  * Param given:
140  */
141 void
142 hopcode(int f, int o)
143 {
144 	char *str;
145 
146 	switch (o) {
147 	case PLUS:
148 		str = "add";
149 		break;
150 	case MINUS:
151 		str = "sub";
152 		break;
153 	case AND:
154 		str = "and";
155 		break;
156 	case OR:
157 		str = "or";
158 		break;
159 	case ER:
160 		str = "xor";
161 		break;
162 	default:
163 		comperr("hopcode2: %d", o);
164 		str = 0; /* XXX gcc */
165 	}
166 	printf("%s%c", str, f);
167 }
168 
169 /*
170  * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
171  */
172 int
173 tlen(NODE *p)
174 {
175 	switch(p->n_type) {
176 		case CHAR:
177 		case UCHAR:
178 			return(1);
179 
180 		case SHORT:
181 		case USHORT:
182 			return(SZSHORT/SZCHAR);
183 
184 		case DOUBLE:
185 			return(SZDOUBLE/SZCHAR);
186 
187 		case INT:
188 		case UNSIGNED:
189 			return(SZINT/SZCHAR);
190 
191 		case LONG:
192 		case ULONG:
193 		case LONGLONG:
194 		case ULONGLONG:
195 			return SZLONGLONG/SZCHAR;
196 
197 		default:
198 			if (!ISPTR(p->n_type))
199 				comperr("tlen type %d not pointer");
200 			return SZPOINT(p->n_type)/SZCHAR;
201 		}
202 }
203 
204 #if 0
205 /*
206  * Emit code to compare two longlong numbers.
207  */
208 static void
209 twollcomp(NODE *p)
210 {
211 	int o = p->n_op;
212 	int s = getlab2();
213 	int e = p->n_label;
214 	int cb1, cb2;
215 
216 	if (o >= ULE)
217 		o -= (ULE-LE);
218 	switch (o) {
219 	case NE:
220 		cb1 = 0;
221 		cb2 = NE;
222 		break;
223 	case EQ:
224 		cb1 = NE;
225 		cb2 = 0;
226 		break;
227 	case LE:
228 	case LT:
229 		cb1 = GT;
230 		cb2 = LT;
231 		break;
232 	case GE:
233 	case GT:
234 		cb1 = LT;
235 		cb2 = GT;
236 		break;
237 
238 	default:
239 		cb1 = cb2 = 0; /* XXX gcc */
240 	}
241 	if (p->n_op >= ULE)
242 		cb1 += 4, cb2 += 4;
243 	expand(p, 0, "	cmpl UR,UL\n");
244 	if (cb1) cbgen(cb1, s);
245 	if (cb2) cbgen(cb2, e);
246 	expand(p, 0, "	cmpl AR,AL\n");
247 	cbgen(p->n_op, e);
248 	deflab(s);
249 }
250 #endif
251 
252 int
253 fldexpand(NODE *p, int cookie, char **cp)
254 {
255 	CONSZ val;
256 
257 	if (p->n_op == ASSIGN)
258 		p = p->n_left;
259 	switch (**cp) {
260 	case 'S':
261 		printf("%d", UPKFSZ(p->n_rval));
262 		break;
263 	case 'H':
264 		printf("%d", UPKFOFF(p->n_rval));
265 		break;
266 	case 'M':
267 	case 'N':
268 		val = (CONSZ)1 << UPKFSZ(p->n_rval);
269 		--val;
270 		val <<= UPKFOFF(p->n_rval);
271 		if (p->n_type > UNSIGNED)
272 			printf("0x%llx", (**cp == 'M' ? val : ~val));
273 		else
274 			printf("0x%llx", (**cp == 'M' ? val : ~val)&0xffffffff);
275 		break;
276 	default:
277 		comperr("fldexpand");
278 	}
279 	return 1;
280 }
281 
282 static void
283 bfext(NODE *p)
284 {
285 	int ch = 0, sz = 0;
286 
287 	if (ISUNSIGNED(p->n_right->n_type))
288 		return;
289 	switch (p->n_right->n_type) {
290 	case CHAR:
291 		ch = 'b';
292 		sz = 8;
293 		break;
294 	case SHORT:
295 		ch = 'w';
296 		sz = 16;
297 		break;
298 	case INT:
299 		ch = 'l';
300 		sz = 32;
301 		break;
302 	case LONG:
303 		ch = 'q';
304 		sz = 64;
305 		break;
306 	default:
307 		comperr("bfext");
308 	}
309 
310 	sz -= UPKFSZ(p->n_left->n_rval);
311 	printf("\tshl%c $%d,", ch, sz);
312 	adrput(stdout, getlr(p, 'D'));
313 	printf("\n\tsar%c $%d,", ch, sz);
314 	adrput(stdout, getlr(p, 'D'));
315 	printf("\n");
316 }
317 #if 0
318 
319 /*
320  * Push a structure on stack as argument.
321  * the scratch registers are already free here
322  */
323 static void
324 starg(NODE *p)
325 {
326 	FILE *fp = stdout;
327 
328 	fprintf(fp, "	subl $%d,%%esp\n", p->n_stsize);
329 	fprintf(fp, "	pushl $%d\n", p->n_stsize);
330 	expand(p, 0, "	pushl AL\n");
331 	expand(p, 0, "	leal 8(%esp),A1\n");
332 	expand(p, 0, "	pushl A1\n");
333 	fprintf(fp, "	call memcpy\n");
334 	fprintf(fp, "	addl $12,%%esp\n");
335 }
336 
337 #endif
338 /*
339  * Generate code to convert an unsigned long to xmm float/double.
340  */
341 static void
342 ultofd(NODE *p)
343 {
344 
345 #define	E(x)	expand(p, 0, x)
346 	E("	movq AL,A1\n");
347 	E("	testq A1,A1\n");
348 	E("	js 2f\n");
349 	E("	cvtsi2sZfq A1,A3\n");
350 	E("	jmp 3f\n");
351 	E("2:\n");
352 	E("	movq A1,A2\n");
353 	E("	shrq A2\n");
354 	E("	andq $1,A1\n");
355 	E("	orq A1,A2\n");
356 	E("	cvtsi2sZfq A2,A3\n");
357 	E("	addsZf A3,A3\n");
358 	E("3:\n");
359 #undef E
360 }
361 
362 static int
363 argsiz(NODE *p)
364 {
365 	TWORD t = p->n_type;
366 
367 	if (p->n_left->n_op == REG)
368 		return 0; /* not on stack */
369 	if (t == LDOUBLE)
370 		return 16;
371 	if (t == STRTY || t == UNIONTY)
372 		return p->n_stsize;
373 	return 8;
374 }
375 
376 void
377 zzzcode(NODE *p, int c)
378 {
379 	NODE *l;
380 	int pr, lr, s;
381 	char **rt;
382 
383 	switch (c) {
384 #if 0
385 	case 'A': /* swap st0 and st1 if right is evaluated second */
386 		if ((p->n_su & DORIGHT) == 0) {
387 			if (logop(p->n_op))
388 				printf("	fxch\n");
389 			else
390 				printf("r");
391 		}
392 		break;
393 #endif
394 
395 	case 'C':  /* remove from stack after subroutine call */
396 		pr = p->n_qual;
397 		if (p->n_op == UCALL)
398 			return; /* XXX remove ZC from UCALL */
399 		if (pr)
400 			printf("	addq $%d, %s\n", pr, rnames[RSP]);
401 		break;
402 
403 	case 'E': /* Perform bitfield sign-extension */
404 		bfext(p);
405 		break;
406 
407 #if 0
408 	case 'F': /* Structure argument */
409 		if (p->n_stalign != 0) /* already on stack */
410 			starg(p);
411 		break;
412 #endif
413 	case 'j': /* convert unsigned long to f/d */
414 		ultofd(p);
415 		break;
416 
417 	case 'M': /* Output sconv move, if needed */
418 		l = getlr(p, 'L');
419 		/* XXX fixneed: regnum */
420 		pr = DECRA(p->n_reg, 0);
421 		lr = DECRA(l->n_reg, 0);
422 		if (pr == lr)
423 			break;
424 		printf("	movb %s,%s\n", rbyte[lr], rbyte[pr]);
425 		l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
426 		break;
427 
428 #if 0
429 	case 'N': /* output extended reg name */
430 		printf("%s", rnames[getlr(p, '1')->n_rval]);
431 		break;
432 #endif
433 
434 	case 'P': /* Put hidden argument in rdi */
435 		printf("\tleaq -%d(%%rbp),%%rdi\n", stkpos);
436 		break;
437 
438 #if 0
439 
440 	case 'S': /* emit eventual move after cast from longlong */
441 		pr = DECRA(p->n_reg, 0);
442 		lr = p->n_left->n_rval;
443 		switch (p->n_type) {
444 		case CHAR:
445 		case UCHAR:
446 			if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' &&
447 			    rnames[pr][1] == rnames[lr][1])
448 				break;
449 			if (rnames[lr][2] == 'x') {
450 				printf("\tmovb %%%cl,%s\n",
451 				    rnames[lr][1], rnames[pr]);
452 				break;
453 			}
454 			/* Must go via stack */
455 			s = BITOOR(freetemp(1));
456 			printf("\tmovl %%e%ci,%d(%%rbp)\n", rnames[lr][1], s);
457 			printf("\tmovb %d(%%rbp),%s\n", s, rnames[pr]);
458 			comperr("SCONV1 %s->%s", rnames[lr], rnames[pr]);
459 			break;
460 
461 		case SHORT:
462 		case USHORT:
463 			if (rnames[lr][1] == rnames[pr][2] &&
464 			    rnames[lr][2] == rnames[pr][3])
465 				break;
466 			printf("\tmovw %%%c%c,%%%s\n",
467 			    rnames[lr][1], rnames[lr][2], rnames[pr]+2);
468 			comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
469 			break;
470 		case INT:
471 		case UNSIGNED:
472 			if (rnames[lr][1] == rnames[pr][2] &&
473 			    rnames[lr][2] == rnames[pr][3])
474 				break;
475 			printf("\tmovl %%e%c%c,%s\n",
476 				    rnames[lr][1], rnames[lr][2], rnames[pr]);
477 			comperr("SCONV3 %s->%s", rnames[lr], rnames[pr]);
478 			break;
479 
480 		default:
481 			if (rnames[lr][1] == rnames[pr][2] &&
482 			    rnames[lr][2] == rnames[pr][3])
483 				break;
484 			comperr("SCONV4 %s->%s", rnames[lr], rnames[pr]);
485 			break;
486 		}
487 		break;
488 #endif
489         case 'Q': /* emit struct assign */
490 		/* XXX - optimize for small structs */
491 		printf("\tmovq $%d,%%rdx\n", p->n_stsize);
492 		expand(p, INAREG, "\tmovq AR,%rsi\n");
493 		expand(p, INAREG, "\tleaq AL,%rdi\n\n");
494 		printf("\tcall memcpy\n");
495 		break;
496 
497 	case 'R': /* print opname based on right type */
498 	case 'L': /* print opname based on left type */
499 		switch (getlr(p, c)->n_type) {
500 		case CHAR: case UCHAR: s = 'b'; break;
501 		case SHORT: case USHORT: s = 'w'; break;
502 		case INT: case UNSIGNED: s = 'l'; break;
503 		default: s = 'q'; break;
504 		printf("%c", s);
505 		}
506 		break;
507 
508 	case '8': /* special reg name printout (64-bit) */
509 	case '1': /* special reg name printout (32-bit) */
510 		l = getlr(p, '1');
511 		rt = c == '8' ? rnames : rlong;
512 		printf("%s", rt[l->n_rval]);
513 		break;
514 
515 	case 'g':
516 		p = p->n_left;
517 		/* FALLTHROUGH */
518 	case 'f': /* float or double */
519 		printf("%c", p->n_type == FLOAT ? 's' : 'd');
520 		break;
521 
522 	case 'q': /* int or long */
523 		printf("%c", p->n_left->n_type == LONG ? 'q' : ' ');
524 		break;
525 
526 	default:
527 		comperr("zzzcode %c", c);
528 	}
529 }
530 
531 /*ARGSUSED*/
532 int
533 rewfld(NODE *p)
534 {
535 	return(1);
536 }
537 
538 int canaddr(NODE *);
539 int
540 canaddr(NODE *p)
541 {
542 	int o = p->n_op;
543 
544 	if (o==NAME || o==REG || o==ICON || o==OREG ||
545 	    (o==UMUL && shumul(p->n_left, SOREG)))
546 		return(1);
547 	return(0);
548 }
549 
550 /*
551  * Does the bitfield shape match?
552  */
553 int
554 flshape(NODE *p)
555 {
556 	int o = p->n_op;
557 
558 	if (o == OREG || o == REG || o == NAME)
559 		return SRDIR; /* Direct match */
560 	if (o == UMUL && shumul(p->n_left, SOREG))
561 		return SROREG; /* Convert into oreg */
562 	return SRREG; /* put it into a register */
563 }
564 
565 /* INTEMP shapes must not contain any temporary registers */
566 /* XXX should this go away now? */
567 int
568 shtemp(NODE *p)
569 {
570 	return 0;
571 #if 0
572 	int r;
573 
574 	if (p->n_op == STARG )
575 		p = p->n_left;
576 
577 	switch (p->n_op) {
578 	case REG:
579 		return (!istreg(p->n_rval));
580 
581 	case OREG:
582 		r = p->n_rval;
583 		if (R2TEST(r)) {
584 			if (istreg(R2UPK1(r)))
585 				return(0);
586 			r = R2UPK2(r);
587 		}
588 		return (!istreg(r));
589 
590 	case UMUL:
591 		p = p->n_left;
592 		return (p->n_op != UMUL && shtemp(p));
593 	}
594 
595 	if (optype(p->n_op) != LTYPE)
596 		return(0);
597 	return(1);
598 #endif
599 }
600 
601 void
602 adrcon(CONSZ val)
603 {
604 	printf("$" CONFMT, val);
605 }
606 
607 void
608 conput(FILE *fp, NODE *p)
609 {
610 	long val = p->n_lval;
611 
612 	switch (p->n_op) {
613 	case ICON:
614 		if (p->n_name[0] != '\0') {
615 			fprintf(fp, "%s", p->n_name);
616 			if (val)
617 				fprintf(fp, "+%ld", val);
618 		} else
619 			fprintf(fp, "%ld", val);
620 		return;
621 
622 	default:
623 		comperr("illegal conput, p %p", p);
624 	}
625 }
626 
627 /*ARGSUSED*/
628 void
629 insput(NODE *p)
630 {
631 	comperr("insput");
632 }
633 
634 /*
635  * Write out the upper address, like the upper register of a 2-register
636  * reference, or the next memory location.
637  * XXX - not needed on amd64
638  */
639 void
640 upput(NODE *p, int size)
641 {
642 
643 	size /= SZCHAR;
644 	switch (p->n_op) {
645 	case REG:
646 		fprintf(stdout, "%%%s", &rnames[p->n_rval][3]);
647 		break;
648 
649 	case NAME:
650 	case OREG:
651 		p->n_lval += size;
652 		adrput(stdout, p);
653 		p->n_lval -= size;
654 		break;
655 	case ICON:
656 		fprintf(stdout, "$" CONFMT, p->n_lval >> 32);
657 		break;
658 	default:
659 		comperr("upput bad op %d size %d", p->n_op, size);
660 	}
661 }
662 
663 void
664 adrput(FILE *io, NODE *p)
665 {
666 	int r;
667 	char **rc;
668 	/* output an address, with offsets, from p */
669 
670 	if (p->n_op == FLD)
671 		p = p->n_left;
672 
673 	switch (p->n_op) {
674 
675 	case NAME:
676 		if (p->n_name[0] != '\0') {
677 			fputs(p->n_name, io);
678 			if (p->n_lval != 0)
679 				fprintf(io, "+" CONFMT, p->n_lval);
680 		} else
681 			fprintf(io, CONFMT, p->n_lval);
682 		return;
683 
684 	case OREG:
685 		r = p->n_rval;
686 		if (p->n_name[0])
687 			printf("%s%s", p->n_name, p->n_lval ? "+" : "");
688 		if (p->n_lval)
689 			fprintf(io, "%lld", p->n_lval);
690 		if (R2TEST(r)) {
691 			int r1 = R2UPK1(r);
692 			int r2 = R2UPK2(r);
693 			int sh = R2UPK3(r);
694 
695 			fprintf(io, "(%s,%s,%d)",
696 			    r1 == MAXREGS ? "" : rnames[r1],
697 			    r2 == MAXREGS ? "" : rnames[r2], sh);
698 		} else
699 			fprintf(io, "(%s)", rnames[p->n_rval]);
700 		return;
701 	case ICON:
702 #ifdef PCC_DEBUG
703 		/* Sanitycheck for PIC, to catch adressable constants */
704 		if (kflag && p->n_name[0]) {
705 			static int foo;
706 
707 			if (foo++ == 0) {
708 				printf("\nfailing...\n");
709 				fwalk(p, e2print, 0);
710 				comperr("pass2 conput");
711 			}
712 		}
713 #endif
714 		/* addressable value of the constant */
715 		fputc('$', io);
716 		conput(io, p);
717 		return;
718 
719 	case REG:
720 		switch (p->n_type) {
721 		case CHAR:
722 		case UCHAR:
723 			rc = rbyte;
724 			break;
725 		case SHORT:
726 		case USHORT:
727 			rc = rshort;
728 			break;
729 		case INT:
730 		case UNSIGNED:
731 			rc = rlong;
732 			break;
733 		default:
734 			rc = rnames;
735 			break;
736 		}
737 		fprintf(io, "%s", rc[p->n_rval]);
738 		return;
739 
740 	default:
741 		comperr("illegal address, op %d, node %p", p->n_op, p);
742 		return;
743 
744 	}
745 }
746 
747 static char *
748 ccbranches[] = {
749 	"je",		/* jumpe */
750 	"jne",		/* jumpn */
751 	"jle",		/* jumple */
752 	"jl",		/* jumpl */
753 	"jge",		/* jumpge */
754 	"jg",		/* jumpg */
755 	"jbe",		/* jumple (jlequ) */
756 	"jb",		/* jumpl (jlssu) */
757 	"jae",		/* jumpge (jgequ) */
758 	"ja",		/* jumpg (jgtru) */
759 };
760 
761 
762 /*   printf conditional and unconditional branches */
763 void
764 cbgen(int o, int lab)
765 {
766 	if (o < EQ || o > UGT)
767 		comperr("bad conditional branch: %s", opst[o]);
768 	printf("	%s " LABFMT "\n", ccbranches[o-EQ], lab);
769 }
770 
771 static void
772 fixcalls(NODE *p, void *arg)
773 {
774 	/* Prepare for struct return by allocating bounce space on stack */
775 	switch (p->n_op) {
776 	case STCALL:
777 	case USTCALL:
778 		if (p->n_stsize+p2autooff > stkpos)
779 			stkpos = p->n_stsize+p2autooff;
780 		break;
781 	}
782 }
783 
784 void
785 myreader(struct interpass *ipole)
786 {
787 	struct interpass *ip;
788 
789 	stkpos = p2autooff;
790 	DLIST_FOREACH(ip, ipole, qelem) {
791 		if (ip->type != IP_NODE)
792 			continue;
793 		walkf(ip->ip_node, fixcalls, 0);
794 	}
795 	if (stkpos > p2autooff)
796 		p2autooff = stkpos;
797 	if (stkpos > p2maxautooff)
798 		p2maxautooff = stkpos;
799 	if (x2debug)
800 		printip(ipole);
801 }
802 
803 /*
804  * Remove some PCONVs after OREGs are created.
805  */
806 static void
807 pconv2(NODE *p, void *arg)
808 {
809 	NODE *q;
810 
811 	if (p->n_op == PLUS) {
812 		if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
813 			if (p->n_right->n_op != ICON)
814 				return;
815 			if (p->n_left->n_op != PCONV)
816 				return;
817 			if (p->n_left->n_left->n_op != OREG)
818 				return;
819 			q = p->n_left->n_left;
820 			nfree(p->n_left);
821 			p->n_left = q;
822 			/*
823 			 * This will be converted to another OREG later.
824 			 */
825 		}
826 	}
827 }
828 
829 void
830 mycanon(NODE *p)
831 {
832 	walkf(p, pconv2, 0);
833 }
834 
835 void
836 myoptim(struct interpass *ip)
837 {
838 }
839 
840 void
841 rmove(int s, int d, TWORD t)
842 {
843 
844 	switch (t) {
845 	case INT:
846 	case UNSIGNED:
847 		printf("	movl %s,%s\n", rlong[s], rlong[d]);
848 		break;
849 	case CHAR:
850 	case UCHAR:
851 		printf("	movb %s,%s\n", rbyte[s], rbyte[d]);
852 		break;
853 	case SHORT:
854 	case USHORT:
855 		printf("	movw %s,%s\n", rshort[s], rshort[d]);
856 		break;
857 	case FLOAT:
858 		printf("	movss %s,%s\n", rnames[s], rnames[d]);
859 		break;
860 	case DOUBLE:
861 		printf("	movsd %s,%s\n", rnames[s], rnames[d]);
862 		break;
863 	case LDOUBLE:
864 		/* a=b()*c(); will generate this */
865 		comperr("bad float rmove: %d %d", s, d);
866 		break;
867 	default:
868 		printf("	movq %s,%s\n", rnames[s], rnames[d]);
869 		break;
870 	}
871 }
872 
873 /*
874  * For class c, find worst-case displacement of the number of
875  * registers in the array r[] indexed by class.
876  */
877 int
878 COLORMAP(int c, int *r)
879 {
880 
881 	switch (c) {
882 	case CLASSA:
883 		return r[CLASSA] < 14;
884 	case CLASSB:
885 		return r[CLASSB] < 16;
886 	}
887 	return 0; /* XXX gcc */
888 }
889 
890 char *rnames[] = {
891 	"%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp",
892 	"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
893 	"%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
894 	"%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14",
895 	"%xmm15",
896 };
897 
898 /* register names for shorter sizes */
899 char *rbyte[] = {
900 	"%al", "%dl", "%cl", "%bl", "%sil", "%dil", "%bpl", "%spl",
901 	"%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b",
902 };
903 char *rshort[] = {
904 	"%ax", "%dx", "%cx", "%bx", "%si", "%di", "%bp", "%sp",
905 	"%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w",
906 };
907 char *rlong[] = {
908 	"%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
909 	"%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d",
910 };
911 
912 
913 /*
914  * Return a class suitable for a specific type.
915  */
916 int
917 gclass(TWORD t)
918 {
919 	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
920 		return CLASSB;
921 	return CLASSA;
922 }
923 
924 /*
925  * Calculate argument sizes.
926  */
927 void
928 lastcall(NODE *p)
929 {
930 	NODE *op = p;
931 	int size = 0;
932 
933 	p->n_qual = 0;
934 	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
935 		return;
936 	for (p = p->n_right; p->n_op == CM; p = p->n_left)
937 		size += argsiz(p->n_right);
938 	size += argsiz(p);
939 	size = (size+15) & ~15;
940 	if (size)
941 		printf("	subq $%d,%s\n", size, rnames[RSP]);
942 	op->n_qual = size; /* XXX */
943 }
944 
945 /*
946  * Special shapes.
947  */
948 int
949 special(NODE *p, int shape)
950 {
951 	int o = p->n_op;
952 
953 	switch (shape) {
954 	case SFUNCALL:
955 		if (o == STCALL || o == USTCALL)
956 			return SRREG;
957 		break;
958 	case SPCON:
959 		if (o != ICON || p->n_name[0] ||
960 		    p->n_lval < 0 || p->n_lval > 0x7fffffff)
961 			break;
962 		return SRDIR;
963 	case SMIXOR:
964 		return tshape(p, SZERO);
965 	case SMILWXOR:
966 		if (o != ICON || p->n_name[0] ||
967 		    p->n_lval == 0 || p->n_lval & 0xffffffff)
968 			break;
969 		return SRDIR;
970 	case SMIHWXOR:
971 		if (o != ICON || p->n_name[0] ||
972 		     p->n_lval == 0 || (p->n_lval >> 32) != 0)
973 			break;
974 		return SRDIR;
975 	case SCON32:
976 		if (o != ICON || p->n_name[0])
977 			break;
978 		if (p->n_lval < MIN_INT || p->n_lval > MAX_INT)
979 			break;
980 		return SRDIR;
981 	default:
982 		cerror("special: %x\n", shape);
983 	}
984 	return SRNOPE;
985 }
986 
987 /*
988  * Target-dependent command-line options.
989  */
990 void
991 mflags(char *str)
992 {
993 }
994 
995 /*
996  * Do something target-dependent for xasm arguments.
997  */
998 int
999 myxasm(struct interpass *ip, NODE *p)
1000 {
1001 	return 0;
1002 #if 0
1003 	struct interpass *ip2;
1004 	NODE *in = 0, *ut = 0;
1005 	TWORD t;
1006 	char *w;
1007 	int reg;
1008 	int cw;
1009 
1010 	cw = xasmcode(p->n_name);
1011 	if (cw & (XASMASG|XASMINOUT))
1012 		ut = p->n_left;
1013 	if ((cw & XASMASG) == 0)
1014 		in = p->n_left;
1015 
1016 	switch (XASMVAL(cw)) {
1017 	case 'D': reg = EDI; break;
1018 	case 'S': reg = ESI; break;
1019 	case 'a': reg = EAX; break;
1020 	case 'b': reg = EBX; break;
1021 	case 'c': reg = ECX; break;
1022 	case 'd': reg = EDX; break;
1023 	case 't': reg = 0; break;
1024 	case 'u': reg = 1; break;
1025 	case 'A': reg = EAXEDX; break;
1026 	case 'q': /* XXX let it be CLASSA as for now */
1027 		p->n_name = tmpstrdup(p->n_name);
1028 		w = strchr(p->n_name, 'q');
1029 		*w = 'r';
1030 		return 0;
1031 	default:
1032 		return 0;
1033 	}
1034 	p->n_name = tmpstrdup(p->n_name);
1035 	for (w = p->n_name; *w; w++)
1036 		;
1037 	w[-1] = 'r'; /* now reg */
1038 	t = p->n_left->n_type;
1039 	if (reg == EAXEDX) {
1040 		p->n_label = CLASSC;
1041 	} else {
1042 		p->n_label = CLASSA;
1043 		if (t == CHAR || t == UCHAR) {
1044 			p->n_label = CLASSB;
1045 			reg = reg * 2 + 8;
1046 		}
1047 	}
1048 	if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
1049 		p->n_label = CLASSD;
1050 		reg += 037;
1051 	}
1052 
1053 	if (in && ut)
1054 		in = tcopy(in);
1055 	p->n_left = mklnode(REG, 0, reg, t);
1056 	if (ut) {
1057 		ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
1058 		DLIST_INSERT_AFTER(ip, ip2, qelem);
1059 	}
1060 	if (in) {
1061 		ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
1062 		DLIST_INSERT_BEFORE(ip, ip2, qelem);
1063 	}
1064 #endif
1065 	return 1;
1066 }
1067 
1068 void
1069 targarg(char *w, void *arg)
1070 {
1071 cerror("targarg");
1072 #if 0
1073 	NODE **ary = arg;
1074 	NODE *p, *q;
1075 
1076 	p = ary[(int)w[1]-'0']->n_left;
1077 	if (optype(p->n_op) != LTYPE)
1078 		comperr("bad xarg op %d", p->n_op);
1079 	q = tcopy(p);
1080 	if (q->n_op == REG) {
1081 		if (*w == 'k') {
1082 			q->n_type = INT;
1083 		} else if (*w != 'w') {
1084 			if (q->n_type > UCHAR) {
1085 				regno(q) = regno(q)*2+8;
1086 				if (*w == 'h')
1087 					regno(q)++;
1088 			}
1089 			q->n_type = INT;
1090 		} else
1091 			q->n_type = SHORT;
1092 	}
1093 	adrput(stdout, q);
1094 	tfree(q);
1095 #endif
1096 }
1097 
1098 /*
1099  * target-specific conversion of numeric arguments.
1100  */
1101 int
1102 numconv(void *ip, void *p1, void *q1)
1103 {
1104 	NODE *p = p1, *q = q1;
1105 	int cw = xasmcode(q->n_name);
1106 
1107 	switch (XASMVAL(cw)) {
1108 	case 'a':
1109 	case 'b':
1110 	case 'c':
1111 	case 'd':
1112 		p->n_name = tmpcalloc(2);
1113 		p->n_name[0] = XASMVAL(cw);
1114 		return 1;
1115 	default:
1116 		return 0;
1117 	}
1118 }
1119