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