xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/i386/local2.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
1 /*	Id: local2.c,v 1.186 2015/11/17 19:19:40 ragge Exp 	*/
2 /*	$NetBSD: local2.c,v 1.1.1.8 2016/02/09 20:28:17 plunky Exp $	*/
3 /*
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 # include "pass2.h"
31 # include <ctype.h>
32 # include <string.h>
33 
34 #if defined(PECOFFABI) || defined(MACHOABI) || defined(AOUTABI)
35 #define EXPREFIX	"_"
36 #else
37 #define EXPREFIX	""
38 #endif
39 
40 int msettings = MI686;
41 static int stkpos;
42 
43 void
deflab(int label)44 deflab(int label)
45 {
46 	printf(LABFMT ":\n", label);
47 }
48 
49 static int regoff[7];
50 static TWORD ftype;
51 
52 /*
53  * Print out the prolog assembler.
54  * addto and regoff are already calculated.
55  */
56 static void
prtprolog(struct interpass_prolog * ipp,int addto)57 prtprolog(struct interpass_prolog *ipp, int addto)
58 {
59 	int i;
60 
61 #if 1
62 #if defined(MACHOABI)
63 	addto += 8;
64 #endif
65 	if (addto == 0 || addto > 65535) {
66 		printf("	pushl %%ebp\n\tmovl %%esp,%%ebp\n");
67 		if (addto)
68 			printf("	subl $%d,%%esp\n", addto);
69 	} else
70 		printf("	enter $%d,$0\n", addto);
71 #endif
72 	for (i = 0; i < MAXREGS; i++)
73 		if (TESTBIT(ipp->ipp_regs, i))
74 			printf("	movl %s,-%d(%s)\n",
75 			    rnames[i], regoff[i], rnames[FPREG]);
76 }
77 
78 /*
79  * calculate stack size and offsets
80  */
81 static int
offcalc(struct interpass_prolog * ipp)82 offcalc(struct interpass_prolog *ipp)
83 {
84 	int i, addto;
85 
86 	addto = p2maxautooff;
87 	if (addto >= AUTOINIT/SZCHAR)
88 		addto -= AUTOINIT/SZCHAR;
89 	for (i = 0; i < MAXREGS; i++)
90 		if (TESTBIT(ipp->ipp_regs, i)) {
91 			addto += SZINT/SZCHAR;
92 			regoff[i] = addto;
93 		}
94 	return addto;
95 }
96 
97 void
prologue(struct interpass_prolog * ipp)98 prologue(struct interpass_prolog *ipp)
99 {
100 	int addto;
101 
102 	ftype = ipp->ipp_type;
103 
104 #ifdef LANG_F77
105 	if (ipp->ipp_vis)
106 		printf("	.globl %s\n", ipp->ipp_name);
107 	printf("	.align 4\n");
108 	printf("%s:\n", ipp->ipp_name);
109 #endif
110 	/*
111 	 * We here know what register to save and how much to
112 	 * add to the stack.
113 	 */
114 	addto = offcalc(ipp);
115 #if defined(MACHOABI)
116 	addto = (addto + 15) & ~15;	/* stack alignment */
117 #endif
118 	prtprolog(ipp, addto);
119 }
120 
121 void
eoftn(struct interpass_prolog * ipp)122 eoftn(struct interpass_prolog *ipp)
123 {
124 	int i;
125 
126 	if (ipp->ipp_ip.ip_lbl == 0)
127 		return; /* no code needs to be generated */
128 
129 	/* return from function code */
130 	for (i = 0; i < MAXREGS; i++)
131 		if (TESTBIT(ipp->ipp_regs, i))
132 			printf("	movl -%d(%s),%s\n",
133 			    regoff[i], rnames[FPREG], rnames[i]);
134 
135 	/* struct return needs special treatment */
136 	if (ftype == STRTY || ftype == UNIONTY) {
137 		printf("	movl 8(%%ebp),%%eax\n");
138 		printf("	leave\n");
139 		printf("	ret $%d\n", 4 + ipp->ipp_argstacksize);
140 	} else {
141 		printf("	leave\n");
142 		if (ipp->ipp_argstacksize)
143 			printf("	ret $%d\n", ipp->ipp_argstacksize);
144 		else
145 			printf("	ret\n");
146 	}
147 
148 #if defined(ELFABI)
149 	printf("\t.size " EXPREFIX "%s,.-" EXPREFIX "%s\n", ipp->ipp_name,
150 	    ipp->ipp_name);
151 #endif
152 }
153 
154 /*
155  * add/sub/...
156  *
157  * Param given:
158  */
159 void
hopcode(int f,int o)160 hopcode(int f, int o)
161 {
162 	char *str;
163 
164 	switch (o) {
165 	case PLUS:
166 		str = "add";
167 		break;
168 	case MINUS:
169 		str = "sub";
170 		break;
171 	case AND:
172 		str = "and";
173 		break;
174 	case OR:
175 		str = "or";
176 		break;
177 	case ER:
178 		str = "xor";
179 		break;
180 	default:
181 		comperr("hopcode2: %d", o);
182 		str = 0; /* XXX gcc */
183 	}
184 	printf("%s%c", str, f);
185 }
186 
187 /*
188  * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
189  */
190 int
tlen(NODE * p)191 tlen(NODE *p)
192 {
193 	switch(p->n_type) {
194 		case CHAR:
195 		case UCHAR:
196 			return(1);
197 
198 		case SHORT:
199 		case USHORT:
200 			return(SZSHORT/SZCHAR);
201 
202 		case DOUBLE:
203 			return(SZDOUBLE/SZCHAR);
204 
205 		case INT:
206 		case UNSIGNED:
207 		case LONG:
208 		case ULONG:
209 			return(SZINT/SZCHAR);
210 
211 		case LONGLONG:
212 		case ULONGLONG:
213 			return SZLONGLONG/SZCHAR;
214 
215 		default:
216 			if (!ISPTR(p->n_type))
217 				comperr("tlen type %d not pointer");
218 			return SZPOINT(p->n_type)/SZCHAR;
219 		}
220 }
221 
222 /*
223  * Emit code to compare two longlong numbers.
224  */
225 static void
twollcomp(NODE * p)226 twollcomp(NODE *p)
227 {
228 	int u;
229 	int s = getlab2();
230 	int e = p->n_label;
231 	int cb1, cb2;
232 
233 	u = p->n_op;
234 	switch (p->n_op) {
235 	case NE:
236 		cb1 = 0;
237 		cb2 = NE;
238 		break;
239 	case EQ:
240 		cb1 = NE;
241 		cb2 = 0;
242 		break;
243 	case LE:
244 	case LT:
245 		u += (ULE-LE);
246 		/* FALLTHROUGH */
247 	case ULE:
248 	case ULT:
249 		cb1 = GT;
250 		cb2 = LT;
251 		break;
252 	case GE:
253 	case GT:
254 		u += (ULE-LE);
255 		/* FALLTHROUGH */
256 	case UGE:
257 	case UGT:
258 		cb1 = LT;
259 		cb2 = GT;
260 		break;
261 
262 	default:
263 		cb1 = cb2 = 0; /* XXX gcc */
264 	}
265 	if (p->n_op >= ULE)
266 		cb1 += 4, cb2 += 4;
267 	expand(p, 0, "	cmpl UR,UL\n");
268 	if (cb1) cbgen(cb1, s);
269 	if (cb2) cbgen(cb2, e);
270 	expand(p, 0, "	cmpl AR,AL\n");
271 	cbgen(u, e);
272 	deflab(s);
273 }
274 
275 int
fldexpand(NODE * p,int cookie,char ** cp)276 fldexpand(NODE *p, int cookie, char **cp)
277 {
278 	comperr("fldexpand");
279 	return 0;
280 }
281 
282 /*
283  * Push a structure on stack as argument.
284  * the scratch registers are already free here
285  */
286 static void
starg(NODE * p)287 starg(NODE *p)
288 {
289 	struct attr *ap;
290 	NODE *q = p->n_left;
291 
292 	ap = attr_find(p->n_ap, ATTR_P2STRUCT);
293 	printf("	subl $%d,%%esp\n", (ap->iarg(0) + 3) & ~3);
294 	p->n_left = mklnode(OREG, 0, ESP, INT);
295 	zzzcode(p, 'Q');
296 	tfree(p->n_left);
297 	p->n_left = q;
298 }
299 
300 /*
301  * Compare two floating point numbers.
302  */
303 static void
fcomp(NODE * p)304 fcomp(NODE *p)
305 {
306 	static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
307 
308 	if (msettings & MI686) {
309 		if ((p->n_su & DORIGHT) == 0)
310 			expand(p, 0, "\tfxch\n");
311 		expand(p, 0, "\tfucomip %st(1),%st\n");	/* emit compare insn  */
312 		expand(p, 0, "\tfstp %st(0)\n");	/* pop fromstack */
313 
314 		if (p->n_op == NE || p->n_op == GT || p->n_op == GE)
315 			expand(p, 0, "\tjp LC\n");
316 		else if (p->n_op == EQ)
317 			printf("\tjp 1f\n");
318 		printf("	%s ", fpcb[p->n_op - EQ]);
319 		expand(p, 0, "LC\n");
320 		if (p->n_op == EQ)
321 			printf("1:\n");
322 	} else {
323 		int swap = ((p->n_su & DORIGHT) == 0);
324 
325 		if (p->n_op == GT || p->n_op == GE)
326 			swap ^= 1;
327 		if (swap)
328 			expand(p, 0, "\tfxch\n");
329 
330 		/*
331 		 * Flags for x87:
332 		 * C3 C2 C0
333 		 * 0  0  0	st0 > st1
334 		 * 0  0  1	st0 < st1
335 		 * 1  0  0	st0 = st1
336 		 * 1  1  1	unordered
337 		 */
338 
339 		/* ax avoided in nspecial() */
340 		printf("\tfucompp\n\tfnstsw %%ax\n");
341 		if (p->n_op == GE || p->n_op == LE) {
342 			printf("\ttestb $0x45,%%ah\n");
343 		} else if (p->n_op == GT || p->n_op == LT) {
344 			printf("\ttestb $0x05,%%ah\n");
345 		} else if (p->n_op == NE) {
346 			printf("\tandb $0x45,%%ah\n");
347 			printf("\txorb $0x40,%%ah\n");
348 		} else if (p->n_op == EQ) {
349 			printf("\tandb $0x45,%%ah\n");
350 			printf("\tcmpb $0x40,%%ah\n");
351 		}
352 		if (p->n_op == EQ) {
353 			expand(p, 0, "\tje LC\n");
354 		} else
355 			expand(p, 0, "\tjne LC\n");
356 	}
357 }
358 
359 /*
360  * Convert an unsigned long long to floating point number.
361  */
362 static void
ulltofp(NODE * p)363 ulltofp(NODE *p)
364 {
365 	int jmplab;
366 
367 #if defined(ELFABI) || defined(PECOFFABI)
368 	static int loadlab;
369 
370 	if (loadlab == 0) {
371 		loadlab = getlab2();
372 		expand(p, 0, "	.data\n");
373 		printf(LABFMT ":	.long 0,0x80000000,0x403f\n", loadlab);
374 		expand(p, 0, "	.text\n");
375 	}
376 #endif
377 
378 	jmplab = getlab2();
379 	expand(p, 0, "	pushl UL\n	pushl AL\n");
380 	expand(p, 0, "	fildq (%esp)\n");
381 	expand(p, 0, "	addl $8,%esp\n");
382 	expand(p, 0, "	cmpl $0,UL\n");
383 	printf("	jge " LABFMT "\n", jmplab);
384 
385 #if defined(ELFABI)
386 	printf("	fldt " LABFMT "%s\n", loadlab, kflag ? "@GOTOFF" : "");
387 #elif defined(MACHOABI)
388 	printf("\tpushl 0x5f800000\n");
389 	printf("\tfadds (%%esp)\n");
390 	printf("\taddl $4,%%esp\n");
391 #else
392 #error incomplete implementation
393 #endif
394 
395 	printf("	faddp %%st,%%st(1)\n");
396 	printf(LABFMT ":\n", jmplab);
397 }
398 
399 static int
argsiz(NODE * p)400 argsiz(NODE *p)
401 {
402 	TWORD t = p->n_type;
403 
404 	if (t < LONGLONG || t == FLOAT || t > BTMASK)
405 		return 4;
406 	if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
407 		return 8;
408 	if (t == LDOUBLE)
409 		return 12;
410 	if (t == STRTY || t == UNIONTY)
411 		return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) & ~3;
412 	comperr("argsiz");
413 	return 0;
414 }
415 
416 static void
fcast(NODE * p)417 fcast(NODE *p)
418 {
419 	TWORD t = p->n_type;
420 	int sz, c;
421 
422 	if (t >= p->n_left->n_type)
423 		return; /* cast to more precision */
424 	if (t == FLOAT)
425 		sz = 4, c = 's';
426 	else
427 		sz = 8, c = 'l';
428 
429 	printf("	sub $%d,%%esp\n", sz);
430 	printf("	fstp%c (%%esp)\n", c);
431 	printf("	fld%c (%%esp)\n", c);
432 	printf("	add $%d,%%esp\n", sz);
433 }
434 
435 static void
llshft(NODE * p)436 llshft(NODE *p)
437 {
438 	char *d[3];
439 
440 	if (p->n_op == LS) {
441 		d[0] = "l", d[1] = "%eax", d[2] = "%edx";
442 	} else
443 		d[0] = "r", d[1] = "%edx", d[2] = "%eax";
444 
445 	printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]);
446 	printf("\ts%s%sl %%cl,%s\n", p->n_op == RS &&
447 	    p->n_left->n_type == ULONGLONG ? "h" : "a", d[0], d[1]);
448 	printf("\ttestb $32,%%cl\n");
449 	printf("\tje 1f\n");
450 	printf("\tmovl %s,%s\n", d[1], d[2]);
451 	if (p->n_op == RS && p->n_left->n_type == LONGLONG)
452 		printf("\tsarl $31,%%edx\n");
453 	else
454 		printf("\txorl %s,%s\n",d[1],d[1]);
455 	printf("1:\n");
456 }
457 
458 void
zzzcode(NODE * p,int c)459 zzzcode(NODE *p, int c)
460 {
461 	struct attr *ap;
462 	NODE *l;
463 	int pr, lr;
464 	char *ch;
465 
466 	switch (c) {
467 	case 'A': /* swap st0 and st1 if right is evaluated second */
468 		if ((p->n_su & DORIGHT) == 0) {
469 			if (logop(p->n_op))
470 				printf("	fxch\n");
471 			else
472 				printf("r");
473 		}
474 		break;
475 
476 	case 'C':  /* remove from stack after subroutine call */
477 #ifdef GCC_COMPAT
478 		if (attr_find(p->n_left->n_ap, GCC_ATYP_STDCALL))
479 			break;
480 #endif
481 		pr = p->n_qual;
482 		if (attr_find(p->n_ap, ATTR_I386_FPPOP))
483 			printf("	fstp	%%st(0)\n");
484 		if (p->n_op == UCALL)
485 			return; /* XXX remove ZC from UCALL */
486 		if (pr)
487 			printf("	addl $%d, %s\n", pr, rnames[ESP]);
488 #if defined(os_openbsd)
489 		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
490 		if (p->n_op == STCALL && (ap->iarg(0) == 1 ||
491 		    ap->iarg(0) == 2 || ap->iarg(0) == 4 ||
492 		    ap->iarg(0) == 8)) {
493 			/* save on stack */
494 			printf("\tmovl %%eax,-%d(%%ebp)\n", stkpos);
495 			printf("\tmovl %%edx,-%d(%%ebp)\n", stkpos+4);
496 			printf("\tleal -%d(%%ebp),%%eax\n", stkpos);
497 		}
498 #endif
499 		break;
500 
501 	case 'D': /* Long long comparision */
502 		twollcomp(p);
503 		break;
504 
505 	case 'F': /* Structure argument */
506 		starg(p);
507 		break;
508 
509 	case 'G': /* Floating point compare */
510 		fcomp(p);
511 		break;
512 
513 	case 'H': /* assign of longlong between regs */
514 		rmove(DECRA(p->n_right->n_reg, 0),
515 		    DECRA(p->n_left->n_reg, 0), LONGLONG);
516 		break;
517 
518 	case 'I': /* float casts */
519 		fcast(p);
520 		break;
521 
522 	case 'J': /* convert unsigned long long to floating point */
523 		ulltofp(p);
524 		break;
525 
526 	case 'K': /* Load longlong reg into another reg */
527 		rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
528 		break;
529 
530 	case 'M': /* Output sconv move, if needed */
531 		l = getlr(p, 'L');
532 		/* XXX fixneed: regnum */
533 		pr = DECRA(p->n_reg, 0);
534 		lr = DECRA(l->n_reg, 0);
535 		if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) ||
536 		    (pr == CL && lr == ECX) || (pr == DL && lr == EDX))
537 			;
538 		else
539 			printf("	movb %%%cl,%s\n",
540 			    rnames[lr][2], rnames[pr]);
541 		l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
542 		break;
543 
544 	case 'N': /* output extended reg name */
545 		printf("%s", rnames[getlr(p, '1')->n_rval]);
546 		break;
547 
548 	case 'O': /* print out emulated ops */
549 		pr = 16;
550 		if (p->n_op == RS || p->n_op == LS) {
551 			llshft(p);
552 			break;
553 		} else if (p->n_op == MUL) {
554 			printf("\timull %%ecx, %%edx\n");
555 			printf("\timull %%eax, %%esi\n");
556 			printf("\taddl %%edx, %%esi\n");
557 			printf("\tmull %%ecx\n");
558 			printf("\taddl %%esi, %%edx\n");
559 			break;
560 		}
561 		expand(p, INCREG, "\tpushl UR\n\tpushl AR\n");
562 		expand(p, INCREG, "\tpushl UL\n\tpushl AL\n");
563 		if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
564 		else if (p->n_op == DIV) ch = "div";
565 		else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
566 		else if (p->n_op == MOD) ch = "mod";
567 		else ch = 0, comperr("ZO");
568 #ifdef ELFABI
569 		printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n",
570 			ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]);
571 #else
572 		printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n",
573 			ch, pr, rnames[ESP]);
574 #endif
575                 break;
576 
577 	case 'Q': /* emit struct assign */
578 		/*
579 		 * Put out some combination of movs{b,w,l}
580 		 * esi/edi/ecx are available.
581 		 */
582 		expand(p, INAREG, "	leal AL,%edi\n");
583 		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
584 		if (ap->iarg(0) < 32) {
585 			int i = ap->iarg(0) >> 2;
586 			while (i) {
587 				expand(p, INAREG, "	movsl\n");
588 				i--;
589 			}
590 		} else {
591 			printf("\tmovl $%d,%%ecx\n", ap->iarg(0) >> 2);
592 			printf("	rep movsl\n");
593 		}
594 		if (ap->iarg(0) & 2)
595 			printf("	movsw\n");
596 		if (ap->iarg(0) & 1)
597 			printf("	movsb\n");
598 		break;
599 
600 	case 'S': /* emit eventual move after cast from longlong */
601 		pr = DECRA(p->n_reg, 0);
602 		lr = p->n_left->n_rval;
603 		switch (p->n_type) {
604 		case CHAR:
605 		case UCHAR:
606 			if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' &&
607 			    rnames[pr][1] == rnames[lr][1])
608 				break;
609 			if (rnames[lr][2] == 'x') {
610 				printf("\tmovb %%%cl,%s\n",
611 				    rnames[lr][1], rnames[pr]);
612 				break;
613 			}
614 			/* Must go via stack */
615 			expand(p, INAREG, "\tmovl AL,A2\n");
616 			expand(p, INBREG, "\tmovb A2,A1\n");
617 #ifdef notdef
618 			/* cannot use freetemp() in instruction emission */
619 			s = freetemp(1);
620 			printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s);
621 			printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]);
622 #endif
623 			break;
624 
625 		case SHORT:
626 		case USHORT:
627 			if (rnames[lr][1] == rnames[pr][2] &&
628 			    rnames[lr][2] == rnames[pr][3])
629 				break;
630 			printf("\tmovw %%%c%c,%%%s\n",
631 			    rnames[lr][1], rnames[lr][2], rnames[pr]+2);
632 			break;
633 		case INT:
634 		case UNSIGNED:
635 			if (rnames[lr][1] == rnames[pr][2] &&
636 			    rnames[lr][2] == rnames[pr][3])
637 				break;
638 			printf("\tmovl %%e%c%c,%s\n",
639 				    rnames[lr][1], rnames[lr][2], rnames[pr]);
640 			break;
641 
642 		default:
643 			if (rnames[lr][1] == rnames[pr][2] &&
644 			    rnames[lr][2] == rnames[pr][3])
645 				break;
646 			comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
647 			break;
648 		}
649 		break;
650 
651 	default:
652 		comperr("zzzcode %c", c);
653 	}
654 }
655 
656 int canaddr(NODE *);
657 int
canaddr(NODE * p)658 canaddr(NODE *p)
659 {
660 	int o = p->n_op;
661 
662 	if (o==NAME || o==REG || o==ICON || o==OREG ||
663 	    (o==UMUL && shumul(p->n_left, SOREG)))
664 		return(1);
665 	return(0);
666 }
667 
668 /*
669  * Does the bitfield shape match?
670  */
671 int
flshape(NODE * p)672 flshape(NODE *p)
673 {
674 	comperr("flshape");
675 	return 0;
676 }
677 
678 /* INTEMP shapes must not contain any temporary registers */
679 /* XXX should this go away now? */
680 int
shtemp(NODE * p)681 shtemp(NODE *p)
682 {
683 	return 0;
684 #if 0
685 	int r;
686 
687 	if (p->n_op == STARG )
688 		p = p->n_left;
689 
690 	switch (p->n_op) {
691 	case REG:
692 		return (!istreg(p->n_rval));
693 
694 	case OREG:
695 		r = p->n_rval;
696 		if (R2TEST(r)) {
697 			if (istreg(R2UPK1(r)))
698 				return(0);
699 			r = R2UPK2(r);
700 		}
701 		return (!istreg(r));
702 
703 	case UMUL:
704 		p = p->n_left;
705 		return (p->n_op != UMUL && shtemp(p));
706 	}
707 
708 	if (optype(p->n_op) != LTYPE)
709 		return(0);
710 	return(1);
711 #endif
712 }
713 
714 void
adrcon(CONSZ val)715 adrcon(CONSZ val)
716 {
717 	printf("$" CONFMT, val);
718 }
719 
720 void
conput(FILE * fp,NODE * p)721 conput(FILE *fp, NODE *p)
722 {
723 	int val = (int)getlval(p);
724 
725 	switch (p->n_op) {
726 	case ICON:
727 		if (p->n_name[0] != '\0') {
728 			fprintf(fp, "%s", p->n_name);
729 			if (val)
730 				fprintf(fp, "+%d", val);
731 		} else
732 			fprintf(fp, "%d", val);
733 		return;
734 
735 	default:
736 		comperr("illegal conput, p %p", p);
737 	}
738 }
739 
740 /*ARGSUSED*/
741 void
insput(NODE * p)742 insput(NODE *p)
743 {
744 	comperr("insput");
745 }
746 
747 /*
748  * Write out the upper address, like the upper register of a 2-register
749  * reference, or the next memory location.
750  */
751 void
upput(NODE * p,int size)752 upput(NODE *p, int size)
753 {
754 
755 	size /= SZCHAR;
756 	switch (p->n_op) {
757 	case REG:
758 		printf("%%%s", &rnames[p->n_rval][3]);
759 		break;
760 
761 	case NAME:
762 	case OREG:
763 		setlval(p, getlval(p) + size);
764 		adrput(stdout, p);
765 		setlval(p, getlval(p) - size);
766 		break;
767 	case ICON:
768 		printf("$" CONFMT, getlval(p) >> 32);
769 		break;
770 	default:
771 		comperr("upput bad op %d size %d", p->n_op, size);
772 	}
773 }
774 
775 void
adrput(FILE * io,NODE * p)776 adrput(FILE *io, NODE *p)
777 {
778 	int r;
779 	/* output an address, with offsets, from p */
780 
781 	switch (p->n_op) {
782 
783 	case NAME:
784 		if (p->n_name[0] != '\0') {
785 			fputs(p->n_name, io);
786 			if (getlval(p) != 0)
787 				fprintf(io, "+" CONFMT, getlval(p));
788 		} else
789 			fprintf(io, CONFMT, getlval(p));
790 		return;
791 
792 	case OREG:
793 		r = p->n_rval;
794 		if (p->n_name[0])
795 			printf("%s%s", p->n_name, getlval(p) ? "+" : "");
796 		if (getlval(p))
797 			fprintf(io, "%d", (int)getlval(p));
798 		if (R2TEST(r)) {
799 			fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)],
800 			    rnames[R2UPK2(r)]);
801 		} else
802 			fprintf(io, "(%s)", rnames[p->n_rval]);
803 		return;
804 	case ICON:
805 #ifdef PCC_DEBUG
806 		/* Sanitycheck for PIC, to catch adressable constants */
807 		if (kflag && p->n_name[0] && 0) {
808 			static int foo;
809 
810 			if (foo++ == 0) {
811 				printf("\nfailing...\n");
812 				fwalk(p, e2print, 0);
813 				comperr("pass2 conput");
814 			}
815 		}
816 #endif
817 		/* addressable value of the constant */
818 		fputc('$', io);
819 		conput(io, p);
820 		return;
821 
822 	case REG:
823 		switch (p->n_type) {
824 		case LONGLONG:
825 		case ULONGLONG:
826 			fprintf(io, "%%%c%c%c", rnames[p->n_rval][0],
827 			    rnames[p->n_rval][1], rnames[p->n_rval][2]);
828 			break;
829 		case SHORT:
830 		case USHORT:
831 			fprintf(io, "%%%s", &rnames[p->n_rval][2]);
832 			break;
833 		default:
834 			fprintf(io, "%s", rnames[p->n_rval]);
835 		}
836 		return;
837 
838 	default:
839 		comperr("illegal address, op %d, node %p", p->n_op, p);
840 		return;
841 
842 	}
843 }
844 
845 static char *
846 ccbranches[] = {
847 	"je",		/* jumpe */
848 	"jne",		/* jumpn */
849 	"jle",		/* jumple */
850 	"jl",		/* jumpl */
851 	"jge",		/* jumpge */
852 	"jg",		/* jumpg */
853 	"jbe",		/* jumple (jlequ) */
854 	"jb",		/* jumpl (jlssu) */
855 	"jae",		/* jumpge (jgequ) */
856 	"ja",		/* jumpg (jgtru) */
857 };
858 
859 
860 /*   printf conditional and unconditional branches */
861 void
cbgen(int o,int lab)862 cbgen(int o, int lab)
863 {
864 	if (o < EQ || o > UGT)
865 		comperr("bad conditional branch: %s", opst[o]);
866 	printf("	%s " LABFMT "\n", ccbranches[o-EQ], lab);
867 }
868 
869 static void
fixcalls(NODE * p,void * arg)870 fixcalls(NODE *p, void *arg)
871 {
872 	struct attr *ap;
873 
874 	/* Prepare for struct return by allocating bounce space on stack */
875 	switch (p->n_op) {
876 	case STCALL:
877 	case USTCALL:
878 		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
879 		if (ap->iarg(0)+p2autooff > stkpos)
880 			stkpos = ap->iarg(0)+p2autooff;
881 		if (8+p2autooff > stkpos)
882 			stkpos = ap->iarg(0)+p2autooff;
883 		break;
884 	case LS:
885 	case RS:
886 		if (p->n_type != LONGLONG && p->n_type != ULONGLONG)
887 			break;
888 		if (p->n_right->n_op == ICON) /* constants must be char */
889 			p->n_right->n_type = CHAR;
890 		break;
891 	}
892 }
893 
894 /*
895  * Must store floats in memory if there are two function calls involved.
896  */
897 static int
storefloat(struct interpass * ip,NODE * p)898 storefloat(struct interpass *ip, NODE *p)
899 {
900 	int l, r;
901 
902 	switch (optype(p->n_op)) {
903 	case BITYPE:
904 		l = storefloat(ip, p->n_left);
905 		r = storefloat(ip, p->n_right);
906 		if (p->n_op == CM)
907 			return 0; /* arguments, don't care */
908 		if (callop(p->n_op))
909 			return 1; /* found one */
910 #define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \
911 	(p)->n_type == LDOUBLE)
912 		if (ISF(p->n_left) && ISF(p->n_right) && l && r) {
913 			/* must store one. store left */
914 			struct interpass *nip;
915 			TWORD t = p->n_left->n_type;
916 			NODE *ll;
917 			int off;
918 
919                 	off = freetemp(szty(t));
920                 	ll = mklnode(OREG, off, FPREG, t);
921 			nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
922 			p->n_left = mklnode(OREG, off, FPREG, t);
923                 	DLIST_INSERT_BEFORE(ip, nip, qelem);
924 		}
925 		return l|r;
926 
927 	case UTYPE:
928 		l = storefloat(ip, p->n_left);
929 		if (callop(p->n_op))
930 			l = 1;
931 		return l;
932 	default:
933 		return 0;
934 	}
935 }
936 
937 static void
outfargs(struct interpass * ip,NODE ** ary,int num,int * cwp,int c)938 outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
939 {
940 	struct interpass *ip2;
941 	NODE *q, *r;
942 	int i;
943 
944 	for (i = 0; i < num; i++)
945 		if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT)))
946 			break;
947 	if (i == num)
948 		return;
949 	q = ary[i]->n_left;
950 	r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
951 	ary[i]->n_left = tcopy(r);
952 	ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type));
953 	DLIST_INSERT_AFTER(ip, ip2, qelem);
954 }
955 
956 static void
infargs(struct interpass * ip,NODE ** ary,int num,int * cwp,int c)957 infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
958 {
959 	struct interpass *ip2;
960 	NODE *q, *r;
961 	int i;
962 
963 	for (i = 0; i < num; i++)
964 		if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0)
965 			break;
966 	if (i == num)
967 		return;
968 	q = ary[i]->n_left;
969 	q = (cwp[i] & XASMINOUT) ? tcopy(q) : q;
970 	r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
971 	if ((cwp[i] & XASMINOUT) == 0)
972 		ary[i]->n_left = tcopy(r);
973 	ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type));
974 	DLIST_INSERT_BEFORE(ip, ip2, qelem);
975 }
976 
977 /*
978  * Extract float args to XASM and ensure that they are put on the stack
979  * in correct order.
980  * This should be done sow other way.
981  */
982 static void
fixxfloat(struct interpass * ip,NODE * p)983 fixxfloat(struct interpass *ip, NODE *p)
984 {
985 	NODE *w, **ary;
986 	int nn, i, c, *cwp;
987 
988 	nn = 1;
989 	w = p->n_left;
990 	if (w->n_op == ICON && w->n_type == STRTY)
991 		return;
992 	/* index all xasm args first */
993 	for (; w->n_op == CM; w = w->n_left)
994 		nn++;
995 	ary = tmpcalloc(nn * sizeof(NODE *));
996 	cwp = tmpcalloc(nn * sizeof(int));
997 	for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) {
998 		ary[i] = w->n_right;
999 		cwp[i] = xasmcode(ary[i]->n_name);
1000 		i++;
1001 	}
1002 	ary[i] = w;
1003 	cwp[i] = xasmcode(ary[i]->n_name);
1004 	for (i = 0; i < nn; i++)
1005 		if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u')
1006 			break;
1007 	if (i == nn)
1008 		return;
1009 
1010 	for (i = 0; i < nn; i++) {
1011 		c = XASMVAL(cwp[i]);
1012 		if (c >= '0' && c <= '9')
1013 			cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']);
1014 	}
1015 	infargs(ip, ary, nn, cwp, 'u');
1016 	infargs(ip, ary, nn, cwp, 't');
1017 	outfargs(ip, ary, nn, cwp, 't');
1018 	outfargs(ip, ary, nn, cwp, 'u');
1019 }
1020 
1021 static NODE *
lptr(NODE * p)1022 lptr(NODE *p)
1023 {
1024 	if (p->n_op == ASSIGN && p->n_right->n_op == REG &&
1025 	    regno(p->n_right) == EBP)
1026 		return p->n_right;
1027 	if (p->n_op == FUNARG && p->n_left->n_op == REG &&
1028 	    regno(p->n_left) == EBP)
1029 		return p->n_left;
1030 	return NIL;
1031 }
1032 
1033 /*
1034  * Find arg reg that should be struct reference instead.
1035  */
1036 static void
updatereg(NODE * p,void * arg)1037 updatereg(NODE *p, void *arg)
1038 {
1039 	NODE *q;
1040 
1041 	if (p->n_op != STCALL)
1042 		return;
1043 #if defined(os_openbsd)
1044 	struct attr *ap = attr_find(p->n_ap, ATTR_P2STRUCT);
1045 	if (ap->iarg(0) == 1 || ap->iarg(0) == 2 || ap->iarg(0) == 4 ||
1046 	    ap->iarg(0) == 8)
1047 		return;
1048 #endif
1049 	if (attr_find(p->n_ap, ATTR_I386_FCMPLRET))
1050 		return;
1051 
1052 	if (p->n_right->n_op != CM)
1053 		p = p->n_right;
1054 	else for (p = p->n_right;
1055 	    p->n_op == CM && p->n_left->n_op == CM; p = p->n_left)
1056 		;
1057 	if (p->n_op == CM) {
1058 		if ((q = lptr(p->n_left)))
1059 			;
1060 		else
1061 			q = lptr(p->n_right);
1062 	} else
1063 		q = lptr(p);
1064 	if (q == NIL)
1065 		comperr("bad STCALL hidden reg");
1066 
1067 	/* q is now the hidden arg */
1068 	q->n_op = MINUS;
1069 	q->n_type = INCREF(CHAR);
1070 	q->n_left = mklnode(REG, 0, EBP, INCREF(CHAR));
1071 	q->n_right = mklnode(ICON, stkpos, 0, INT);
1072 }
1073 
1074 void
myreader(struct interpass * ipole)1075 myreader(struct interpass *ipole)
1076 {
1077 	struct interpass *ip;
1078 
1079 	stkpos = p2autooff;
1080 	DLIST_FOREACH(ip, ipole, qelem) {
1081 		if (ip->type != IP_NODE)
1082 			continue;
1083 		walkf(ip->ip_node, fixcalls, 0);
1084 		storefloat(ip, ip->ip_node);
1085 		if (ip->ip_node->n_op == XASM)
1086 			fixxfloat(ip, ip->ip_node);
1087 	}
1088 	if (stkpos != p2autooff) {
1089 		DLIST_FOREACH(ip, ipole, qelem) {
1090 			if (ip->type != IP_NODE)
1091 				continue;
1092 			walkf(ip->ip_node, updatereg, 0);
1093 		}
1094 	}
1095 	if (stkpos > p2autooff)
1096 		p2autooff = stkpos;
1097 	if (stkpos > p2maxautooff)
1098 		p2maxautooff = stkpos;
1099 	if (x2debug)
1100 		printip(ipole);
1101 }
1102 
1103 /*
1104  * Remove some PCONVs after OREGs are created.
1105  */
1106 static void
pconv2(NODE * p,void * arg)1107 pconv2(NODE *p, void *arg)
1108 {
1109 	NODE *q;
1110 
1111 	if (p->n_op == PLUS) {
1112 		if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
1113 			if (p->n_right->n_op != ICON)
1114 				return;
1115 			if (p->n_left->n_op != PCONV)
1116 				return;
1117 			if (p->n_left->n_left->n_op != OREG)
1118 				return;
1119 			q = p->n_left->n_left;
1120 			nfree(p->n_left);
1121 			p->n_left = q;
1122 			/*
1123 			 * This will be converted to another OREG later.
1124 			 */
1125 		}
1126 	}
1127 }
1128 
1129 void
mycanon(NODE * p)1130 mycanon(NODE *p)
1131 {
1132 	walkf(p, pconv2, 0);
1133 }
1134 
1135 void
myoptim(struct interpass * ip)1136 myoptim(struct interpass *ip)
1137 {
1138 }
1139 
1140 static char rl[] =
1141   { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI };
1142 static char rh[] =
1143   { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI };
1144 
1145 void
rmove(int s,int d,TWORD t)1146 rmove(int s, int d, TWORD t)
1147 {
1148 	int sl, sh, dl, dh;
1149 
1150 	switch (t) {
1151 	case LONGLONG:
1152 	case ULONGLONG:
1153 #if 1
1154 		sl = rl[s-EAXEDX];
1155 		sh = rh[s-EAXEDX];
1156 		dl = rl[d-EAXEDX];
1157 		dh = rh[d-EAXEDX];
1158 
1159 		/* sanity checks, remove when satisfied */
1160 		if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 ||
1161 		    memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0)
1162 			comperr("rmove source error");
1163 		if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 ||
1164 		    memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0)
1165 			comperr("rmove dest error");
1166 #define	SW(x,y) { int i = x; x = y; y = i; }
1167 		if (sh == dl) {
1168 			/* Swap if overwriting */
1169 			SW(sl, sh);
1170 			SW(dl, dh);
1171 		}
1172 		if (sl != dl)
1173 			printf("	movl %s,%s\n", rnames[sl], rnames[dl]);
1174 		if (sh != dh)
1175 			printf("	movl %s,%s\n", rnames[sh], rnames[dh]);
1176 #else
1177 		if (memcmp(rnames[s], rnames[d], 3) != 0)
1178 			printf("	movl %%%c%c%c,%%%c%c%c\n",
1179 			    rnames[s][0],rnames[s][1],rnames[s][2],
1180 			    rnames[d][0],rnames[d][1],rnames[d][2]);
1181 		if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0)
1182 			printf("	movl %%%c%c%c,%%%c%c%c\n",
1183 			    rnames[s][3],rnames[s][4],rnames[s][5],
1184 			    rnames[d][3],rnames[d][4],rnames[d][5]);
1185 #endif
1186 		break;
1187 	case CHAR:
1188 	case UCHAR:
1189 		printf("	movb %s,%s\n", rnames[s], rnames[d]);
1190 		break;
1191 	case FLOAT:
1192 	case DOUBLE:
1193 	case LDOUBLE:
1194 #ifdef notdef
1195 		/* a=b()*c(); will generate this */
1196 		comperr("bad float rmove: %d %d", s, d);
1197 #endif
1198 		break;
1199 	default:
1200 		printf("	movl %s,%s\n", rnames[s], rnames[d]);
1201 	}
1202 }
1203 
1204 /*
1205  * For class c, find worst-case displacement of the number of
1206  * registers in the array r[] indexed by class.
1207  */
1208 int
COLORMAP(int c,int * r)1209 COLORMAP(int c, int *r)
1210 {
1211 	int num;
1212 
1213 	switch (c) {
1214 	case CLASSA:
1215 		num = r[CLASSB] > 4 ? 4 : r[CLASSB];
1216 		num += 2*r[CLASSC];
1217 		num += r[CLASSA];
1218 		return num < 6;
1219 	case CLASSB:
1220 		num = r[CLASSA];
1221 		num += 2*r[CLASSC];
1222 		num += r[CLASSB];
1223 		return num < 4;
1224 	case CLASSC:
1225 		num = r[CLASSA];
1226 		num += r[CLASSB] > 4 ? 4 : r[CLASSB];
1227 		num += 2*r[CLASSC];
1228 		return num < 5;
1229 	case CLASSD:
1230 		return r[CLASSD] < DREGCNT;
1231 	}
1232 	return 0; /* XXX gcc */
1233 }
1234 
1235 char *rnames[] = {
1236 	"%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
1237 	"%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh",
1238 	"eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx",
1239 	"edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi",
1240 	"ebxesi", "ebxedi", "esiedi",
1241 	"%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7",
1242 };
1243 
1244 /*
1245  * Return a class suitable for a specific type.
1246  */
1247 int
gclass(TWORD t)1248 gclass(TWORD t)
1249 {
1250 	if (t == CHAR || t == UCHAR)
1251 		return CLASSB;
1252 	if (t == LONGLONG || t == ULONGLONG)
1253 		return CLASSC;
1254 	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
1255 		return CLASSD;
1256 	return CLASSA;
1257 }
1258 
1259 /*
1260  * Calculate argument sizes.
1261  */
1262 void
lastcall(NODE * p)1263 lastcall(NODE *p)
1264 {
1265 	NODE *op = p;
1266 	int nr = 0, size = 0;
1267 
1268 	p->n_qual = 0;
1269 	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
1270 		return;
1271 	for (p = p->n_right; p->n_op == CM; p = p->n_left) {
1272 		if (p->n_right->n_op != ASSIGN)
1273 			size += argsiz(p->n_right);
1274 		else
1275 			nr = 1;
1276 	}
1277 	if (p->n_op != ASSIGN)
1278 		size += argsiz(p);
1279 	else
1280 		nr++;
1281 	if (op->n_op == STCALL) {
1282 		if (kflag)
1283 			nr--;
1284 		if (nr == 0)
1285 			size -= 4; /* XXX OpenBSD? */
1286 	}
1287 
1288 #if defined(MACHOABI)
1289 	int newsize = (size + 15) & ~15;	/* stack alignment */
1290 	int align = newsize-size;
1291 
1292 	if (align != 0)
1293 		printf("	subl $%d,%%esp\n", align);
1294 
1295 	size=newsize;
1296 #endif
1297 
1298 	op->n_qual = size; /* XXX */
1299 }
1300 
1301 /*
1302  * Special shapes.
1303  */
1304 int
special(NODE * p,int shape)1305 special(NODE *p, int shape)
1306 {
1307 	int o = p->n_op;
1308 
1309 	switch (shape) {
1310 	case SFUNCALL:
1311 		if (o == STCALL || o == USTCALL)
1312 			return SRREG;
1313 		break;
1314 	case SPCON:
1315 		if (o != ICON || p->n_name[0] ||
1316 		    getlval(p) < 0 || getlval(p) > 0x7fffffff)
1317 			break;
1318 		return SRDIR;
1319 	case SMIXOR:
1320 		return tshape(p, SZERO);
1321 	case SMILWXOR:
1322 		if (o != ICON || p->n_name[0] ||
1323 		    getlval(p) == 0 || getlval(p) & 0xffffffff)
1324 			break;
1325 		return SRDIR;
1326 	case SMIHWXOR:
1327 		if (o != ICON || p->n_name[0] ||
1328 		     getlval(p) == 0 || (getlval(p) >> 32) != 0)
1329 			break;
1330 		return SRDIR;
1331 	}
1332 	return SRNOPE;
1333 }
1334 
1335 /*
1336  * Target-dependent command-line options.
1337  */
1338 void
mflags(char * str)1339 mflags(char *str)
1340 {
1341 #define	MSET(s,a) if (strcmp(str, s) == 0) \
1342 	msettings = (msettings & ~MCPUMSK) | a
1343 
1344 	MSET("arch=i386",MI386);
1345 	MSET("arch=i486",MI486);
1346 	MSET("arch=i586",MI586);
1347 	MSET("arch=i686",MI686);
1348 }
1349 
1350 /*
1351  * Do something target-dependent for xasm arguments.
1352  */
1353 int
myxasm(struct interpass * ip,NODE * p)1354 myxasm(struct interpass *ip, NODE *p)
1355 {
1356 	struct interpass *ip2;
1357 	int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 };
1358 	NODE *in = 0, *ut = 0;
1359 	TWORD t;
1360 	char *w;
1361 	int reg;
1362 	int c, cw;
1363 	CONSZ v;
1364 
1365 	cw = xasmcode(p->n_name);
1366 	if (cw & (XASMASG|XASMINOUT))
1367 		ut = p->n_left;
1368 	if ((cw & XASMASG) == 0)
1369 		in = p->n_left;
1370 
1371 	c = XASMVAL(cw);
1372 	switch (c) {
1373 	case 'D': reg = EDI; break;
1374 	case 'S': reg = ESI; break;
1375 	case 'a': reg = EAX; break;
1376 	case 'b': reg = EBX; break;
1377 	case 'c': reg = ECX; break;
1378 	case 'd': reg = EDX; break;
1379 
1380 	case 't':
1381 	case 'u':
1382 		p->n_name = tmpstrdup(p->n_name);
1383 		w = strchr(p->n_name, XASMVAL(cw));
1384 		*w = 'r'; /* now reg */
1385 		return 1;
1386 
1387 	case 'A': reg = EAXEDX; break;
1388 	case 'q': {
1389 		/* Set edges in MYSETXARG */
1390 		if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
1391 			return 1;
1392 		t = p->n_left->n_type;
1393 		if (in && ut)
1394 			in = tcopy(in);
1395 		p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
1396 		if (ut) {
1397 			ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
1398 			DLIST_INSERT_AFTER(ip, ip2, qelem);
1399 		}
1400 		if (in) {
1401 			ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
1402 			DLIST_INSERT_BEFORE(ip, ip2, qelem);
1403 		}
1404 		return 1;
1405 	}
1406 
1407 	case 'I':
1408 	case 'J':
1409 	case 'K':
1410 	case 'L':
1411 	case 'M':
1412 	case 'N':
1413 		if (p->n_left->n_op != ICON) {
1414 			if ((c = XASMVAL1(cw)) != 0) {
1415 				p->n_name++;
1416 				return 0; /* Try again */
1417 			}
1418 			uerror("xasm arg not constant");
1419 		}
1420 		v = getlval(p->n_left);
1421 		if ((c == 'K' && v < -128) ||
1422 		    (c == 'L' && v != 0xff && v != 0xffff) ||
1423 		    (c != 'K' && v < 0) ||
1424 		    (v > Cmax[c-'I']))
1425 			uerror("xasm val out of range");
1426 		p->n_name = "i";
1427 		return 1;
1428 
1429 	default:
1430 		return 0;
1431 	}
1432 	/* If there are requested either memory or register, delete memory */
1433 	w = p->n_name = tmpstrdup(p->n_name);
1434 	if (*w == '=')
1435 		w++;
1436 	*w++ = 'r';
1437 	*w = 0;
1438 
1439 	t = p->n_left->n_type;
1440 	if (reg == EAXEDX) {
1441 		;
1442 	} else {
1443 		if (t == CHAR || t == UCHAR) {
1444 			reg = reg * 2 + 8;
1445 		}
1446 	}
1447 	if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
1448 		reg += 037;
1449 	}
1450 
1451 	if (in && ut)
1452 		in = tcopy(in);
1453 	p->n_left = mklnode(REG, 0, reg, t);
1454 	if (ut) {
1455 		ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
1456 		DLIST_INSERT_AFTER(ip, ip2, qelem);
1457 	}
1458 	if (in) {
1459 		ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
1460 		DLIST_INSERT_BEFORE(ip, ip2, qelem);
1461 	}
1462 	return 1;
1463 }
1464 
1465 void
targarg(char * w,void * arg)1466 targarg(char *w, void *arg)
1467 {
1468 	NODE **ary = arg;
1469 	NODE *p, *q;
1470 
1471 	if (ary[(int)w[1]-'0'] == 0)
1472 		p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */
1473 	else
1474 		p = ary[(int)w[1]-'0']->n_left;
1475 	if (optype(p->n_op) != LTYPE)
1476 		comperr("bad xarg op %d", p->n_op);
1477 	q = tcopy(p);
1478 	if (q->n_op == REG) {
1479 		if (*w == 'k') {
1480 			q->n_type = INT;
1481 		} else if (*w != 'w') {
1482 			if (q->n_type > UCHAR) {
1483 				regno(q) = regno(q)*2+8;
1484 				if (*w == 'h')
1485 					regno(q)++;
1486 			}
1487 			q->n_type = INT;
1488 		} else
1489 			q->n_type = SHORT;
1490 	}
1491 	adrput(stdout, q);
1492 	tfree(q);
1493 }
1494 
1495 /*
1496  * target-specific conversion of numeric arguments.
1497  */
1498 int
numconv(void * ip,void * p1,void * q1)1499 numconv(void *ip, void *p1, void *q1)
1500 {
1501 	NODE *p = p1, *q = q1;
1502 	int cw = xasmcode(q->n_name);
1503 
1504 	switch (XASMVAL(cw)) {
1505 	case 'a':
1506 	case 'b':
1507 	case 'c':
1508 	case 'd':
1509 		p->n_name = tmpcalloc(2);
1510 		p->n_name[0] = (char)XASMVAL(cw);
1511 		return 1;
1512 	default:
1513 		return 0;
1514 	}
1515 }
1516 
1517 static struct {
1518 	char *name; int num;
1519 } xcr[] = {
1520 	{ "eax", EAX },
1521 	{ "ebx", EBX },
1522 	{ "ecx", ECX },
1523 	{ "edx", EDX },
1524 	{ "esi", ESI },
1525 	{ "edi", EDI },
1526 	{ "ax", EAX },
1527 	{ "bx", EBX },
1528 	{ "cx", ECX },
1529 	{ "dx", EDX },
1530 	{ NULL, 0 },
1531 };
1532 
1533 /*
1534  * Check for other names of the xasm constraints registers.
1535  */
1536 
1537 /*
1538  * Check for other names of the xasm constraints registers.
1539  */
xasmconstregs(char * s)1540 int xasmconstregs(char *s)
1541 {
1542 	int i;
1543 
1544 	if (strncmp(s, "st", 2) == 0) {
1545 		int off =0;
1546 		if (s[2] == '(' && s[4] == ')')
1547 			off = s[3] - '0';
1548 		return ESIEDI + 1 + off;
1549 	}
1550 
1551 	for (i = 0; xcr[i].name; i++)
1552 		if (strcmp(xcr[i].name, s) == 0)
1553 			return xcr[i].num;
1554 	return -1;
1555 }
1556 
1557