xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/m68k/local2.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
1 /*	Id: local2.c,v 1.17 2016/01/30 17:26:19 ragge Exp 	*/
2 /*	$NetBSD: local2.c,v 1.1.1.2 2016/02/09 20:28:34 plunky Exp $	*/
3 /*
4  * Copyright (c) 2014 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 # include "pass2.h"
29 # include <ctype.h>
30 # include <string.h>
31 
32 static int stkpos;
33 
34 void
deflab(int label)35 deflab(int label)
36 {
37 	printf(LABFMT ":\n", label);
38 }
39 
40 static int regm, regf, fpsub, nfp;
41 
42 void
prologue(struct interpass_prolog * ipp)43 prologue(struct interpass_prolog *ipp)
44 {
45 	int i;
46 
47 	/*
48 	 * Subtract both space for automatics and permanent regs.
49 	 * XXX - no struct return yet.
50 	 */
51 
52 	fpsub = p2maxautooff;
53 	if (fpsub >= AUTOINIT/SZCHAR)
54 		fpsub -= AUTOINIT/SZCHAR;
55 	regm = regf = nfp = 0;
56 	for (i = 0; i < MAXREGS; i++)
57 		if (TESTBIT(ipp->ipp_regs, i)) {
58 			if (i <= A7) {
59 				regm |= (1 << i);
60 				fpsub += 4;
61 			} else if (i >= FP0) {
62 				regf |= (1 << (i - FP0));
63 				fpsub += 12;
64 				nfp += 12;
65 			} else
66 				comperr("bad reg range");
67 		}
68 	printf("	link.%c %%fp,#%d\n", fpsub > 32768 ? 'l' : 'w', -fpsub);
69 	if (regm)
70 		printf("	movem.l #%d,%d(%%fp)\n", regm, -fpsub + nfp);
71 	if (regf)
72 		printf("	fmovem #%d,%d(%%fp)\n", regf, -fpsub);
73 }
74 
75 void
eoftn(struct interpass_prolog * ipp)76 eoftn(struct interpass_prolog *ipp)
77 {
78 	if (ipp->ipp_ip.ip_lbl == 0)
79 		return; /* no code needs to be generated */
80 
81 	if (regm)
82 		printf("	movem.l %d(%%fp),#%d\n", -fpsub + nfp, regm);
83 	if (regf)
84 		printf("	fmovem %d(%%fp),#%d\n", -fpsub, regf);
85 	printf("	unlk %%fp\n	rts\n");
86 }
87 
88 /*
89  * add/sub/...
90  *
91  * Param given:
92  */
93 void
hopcode(int f,int o)94 hopcode(int f, int o)
95 {
96 	char *str;
97 
98 	switch (o) {
99 	case PLUS:
100 		str = "add";
101 		break;
102 	case MINUS:
103 		str = "sub";
104 		break;
105 	case AND:
106 		str = "and";
107 		break;
108 	case OR:
109 		str = "or";
110 		break;
111 	case ER:
112 		str = "eor";
113 		break;
114 	default:
115 		comperr("hopcode2: %d", o);
116 		str = 0; /* XXX gcc */
117 	}
118 	printf("%s", str);
119 }
120 
121 /*
122  * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
123  */
124 int
tlen(NODE * p)125 tlen(NODE *p)
126 {
127 	switch(p->n_type) {
128 		case CHAR:
129 		case UCHAR:
130 			return(1);
131 
132 		case SHORT:
133 		case USHORT:
134 			return(SZSHORT/SZCHAR);
135 
136 		case DOUBLE:
137 			return(SZDOUBLE/SZCHAR);
138 
139 		case INT:
140 		case UNSIGNED:
141 			return(SZINT/SZCHAR);
142 
143 		case LONG:
144 		case ULONG:
145 		case LONGLONG:
146 		case ULONGLONG:
147 			return SZLONGLONG/SZCHAR;
148 
149 		default:
150 			if (!ISPTR(p->n_type))
151 				comperr("tlen type %d not pointer");
152 			return SZPOINT(p->n_type)/SZCHAR;
153 		}
154 }
155 
156 int
fldexpand(NODE * p,int cookie,char ** cp)157 fldexpand(NODE *p, int cookie, char **cp)
158 {
159 	comperr("fldexpand");
160 	return 0;
161 }
162 
163 static void
starg(NODE * p)164 starg(NODE *p)
165 {
166 	int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
167 	int subsz = (sz + 3) & ~3;
168 	int fr, tr, cr;
169 
170 	fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */
171 	cr = regno(getlr(p, '1')); /* count reg (number of words) */
172 	tr = regno(getlr(p, '2')); /* to reg (stack) */
173 
174 	/* Sub from stack and put in toreg */
175 	printf("	sub.l #%d,%%sp\n", subsz);
176 	printf("	move.l %%sp,%s\n", rnames[tr]);
177 
178 	/* Gen an even copy start */
179 	if (sz & 1)
180 		expand(p, INBREG, "	move.b (AL)+,(A2)+\n");
181 	if (sz & 2)
182 		expand(p, INBREG, "	move.w (AL)+,(A2)+\n");
183 	sz -= (sz & 3);
184 
185 	/* if more than 4 words, use loop, otherwise output instructions */
186 	if (sz > 16) {
187 		printf("	move.l #%d,%s\n", (sz/4)-1, rnames[cr]);
188 		expand(p, INBREG, "1:	move.l (AL)+,(A2)+\n");
189 		expand(p, INBREG, "	dbra A1,1b\n");
190 	} else {
191 		if (sz > 12)
192 			expand(p, INBREG, "	move.l (AL)+,(A2)+\n"), sz -= 4;
193 		if (sz > 8)
194 			expand(p, INBREG, "	move.l (AL)+,(A2)+\n"), sz -= 4;
195 		if (sz > 4)
196 			expand(p, INBREG, "	move.l (AL)+,(A2)+\n"), sz -= 4;
197 		if (sz == 4)
198 			expand(p, INBREG, "	move.l (AL)+,(A2)+\n");
199 	}
200 }
201 
202 void
zzzcode(NODE * p,int c)203 zzzcode(NODE *p, int c)
204 {
205 	TWORD t = p->n_type;
206 	char *s;
207 
208 	switch (c) {
209 	case 'L':
210 		t = p->n_left->n_type;
211 		/* FALLTHROUGH */
212 	case 'A':
213 		s = (t == CHAR || t == UCHAR ? "b" :
214 		    t == SHORT || t == USHORT ? "w" :
215 		    t == FLOAT ? "s" :
216 		    t == DOUBLE ? "d" :
217 		    t == LDOUBLE ? "x" : "l");
218 		printf("%s", s);
219 		break;
220 
221 	case 'B':
222 		if (p->n_qual)
223 			printf("	add.l #%d,%%sp\n", (int)p->n_qual);
224 		break;
225 
226 	case 'C': /* jsr or bsr.l XXX - type of CPU? */
227 		printf("%s", kflag ? "bsr.l" : "jsr");
228 		break;
229 
230 	case 'F': /* Emit float branches */
231 		switch (p->n_op) {
232 		case GT: s = "fjnle"; break;
233 		case GE: s = "fjnlt"; break;
234 		case LE: s = "fjngt"; break;
235 		case LT: s = "fjnge"; break;
236 		case NE: s = "fjne"; break;
237 		case EQ: s = "fjeq"; break;
238 		default: comperr("ZF"); s = 0;
239 		}
240 		printf("%s " LABFMT "\n", s, p->n_label);
241 		break;
242 
243 	case 'P':
244 		printf("	lea -%d(%%fp),%%a0\n", stkpos);
245 		break;
246 
247 	case 'Q': /* struct assign */
248 		printf("	move.l %d,-(%%sp)\n",
249 		    attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
250 		expand(p, INAREG, "	move.l AR,-(%sp)\n");
251 		expand(p, INAREG, "	move.l AL,-(%sp)\n");
252 		printf("	jsr memcpy\n");
253 		printf("	add.l #12,%%sp\n");
254 		break;
255 
256 	case 'S': /* struct arg */
257 		starg(p);
258 		break;
259 
260 	case '2':
261 		if (regno(getlr(p, '2')) != regno(getlr(p, 'L')))
262 			expand(p, INAREG, "	fmove.x AL,A2\n");
263 		break;
264 
265 	default:
266 		comperr("zzzcode %c", c);
267 	}
268 }
269 
270 #if 0
271 int canaddr(NODE *);
272 int
273 canaddr(NODE *p)
274 {
275 	int o = p->n_op;
276 
277 	if (o==NAME || o==REG || o==ICON || o==OREG ||
278 	    (o==UMUL && shumul(p->n_left, SOREG)))
279 		return(1);
280 	return(0);
281 }
282 #endif
283 
284 /*
285  * Does the bitfield shape match?
286  */
287 int
flshape(NODE * p)288 flshape(NODE *p)
289 {
290 	comperr("flshape");
291 	return(0);
292 }
293 
294 /* INTEMP shapes must not contain any temporary registers */
295 /* XXX should this go away now? */
296 int
shtemp(NODE * p)297 shtemp(NODE *p)
298 {
299 	return 0;
300 #if 0
301 	int r;
302 
303 	if (p->n_op == STARG )
304 		p = p->n_left;
305 
306 	switch (p->n_op) {
307 	case REG:
308 		return (!istreg(p->n_rval));
309 
310 	case OREG:
311 		r = p->n_rval;
312 		if (R2TEST(r)) {
313 			if (istreg(R2UPK1(r)))
314 				return(0);
315 			r = R2UPK2(r);
316 		}
317 		return (!istreg(r));
318 
319 	case UMUL:
320 		p = p->n_left;
321 		return (p->n_op != UMUL && shtemp(p));
322 	}
323 
324 	if (optype(p->n_op) != LTYPE)
325 		return(0);
326 	return(1);
327 #endif
328 }
329 
330 void
adrcon(CONSZ val)331 adrcon(CONSZ val)
332 {
333 	printf("#" CONFMT, val);
334 }
335 
336 void
conput(FILE * fp,NODE * p)337 conput(FILE *fp, NODE *p)
338 {
339 	long val = getlval(p);
340 
341 	if (p->n_type <= UCHAR)
342 		val &= 255;
343 	else if (p->n_type <= USHORT)
344 		val &= 65535;
345 
346 	switch (p->n_op) {
347 	case ICON:
348 		fprintf(fp, "%ld", val);
349 		if (p->n_name[0])
350 			printf("+%s", p->n_name);
351 		break;
352 
353 	default:
354 		comperr("illegal conput, p %p", p);
355 	}
356 }
357 
358 /*ARGSUSED*/
359 void
insput(NODE * p)360 insput(NODE *p)
361 {
362 	comperr("insput");
363 }
364 
365 /*
366  * Write out the upper address, like the upper register of a 2-register
367  * reference, or the next memory location.
368  */
369 void
upput(NODE * p,int size)370 upput(NODE *p, int size)
371 {
372 	switch (p->n_op) {
373 	case REG:
374 		printf("%%%s", &rnames[p->n_rval][2]);
375 		break;
376 	case NAME:
377 	case OREG:
378 		setlval(p, getlval(p) + 4);
379 		adrput(stdout, p);
380 		setlval(p, getlval(p) - 4);
381 		break;
382 
383 	case ICON:
384 		printf("#%d", (int)getlval(p));
385 		break;
386 
387 	default:
388 		comperr("upput bad op %d size %d", p->n_op, size);
389 	}
390 }
391 
392 void
adrput(FILE * io,NODE * p)393 adrput(FILE *io, NODE *p)
394 {
395 	int r;
396 
397 	/* output an address, with offsets, from p */
398 	switch (p->n_op) {
399 	case NAME:
400 		if (getlval(p))
401 			fprintf(io, CONFMT "%s", getlval(p),
402 			    *p->n_name ? "+" : "");
403 		if (p->n_name[0])
404 			printf("%s", p->n_name);
405 		else
406 			comperr("adrput");
407 		return;
408 
409 	case OREG:
410 		r = p->n_rval;
411 
412 		if (getlval(p))
413 			fprintf(io, CONFMT "%s", getlval(p),
414 			    *p->n_name ? "+" : "");
415 		if (p->n_name[0])
416 			printf("%s", p->n_name);
417 		if (R2TEST(r)) {
418 			int r1 = R2UPK1(r);
419 			int r2 = R2UPK2(r);
420 			int sh = R2UPK3(r);
421 
422 			fprintf(io, "(%s,%s,%d)",
423 			    r1 == MAXREGS ? "" : rnames[r1],
424 			    r2 == MAXREGS ? "" : rnames[r2], sh);
425 		} else
426 			fprintf(io, "(%s)", rnames[p->n_rval]);
427 		return;
428 	case ICON:
429 		/* addressable value of the constant */
430 		if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
431 			fprintf(io, "#" CONFMT, getlval(p) >> 32);
432 		} else {
433 			fputc('#', io);
434 			conput(io, p);
435 		}
436 		return;
437 
438 	case REG:
439 		if ((p->n_type == LONGLONG || p->n_type == ULONGLONG) &&
440 			/* XXX allocated reg may get wrong type here */
441 		    (p->n_rval > A7 && p->n_rval < FP0)) {
442 			fprintf(io, "%%%c%c", rnames[p->n_rval][0],
443 			    rnames[p->n_rval][1]);
444 		} else
445 			fprintf(io, "%s", rnames[p->n_rval]);
446 		return;
447 
448 	default:
449 		comperr("illegal address, op %d, node %p", p->n_op, p);
450 		return;
451 
452 	}
453 }
454 
455 static char *
456 ccbranches[] = {
457 	"jeq",		/* jumpe */
458 	"jne",		/* jumpn */
459 	"jle",		/* jumple */
460 	"jlt",		/* jumpl */
461 	"jge",		/* jumpge */
462 	"jgt",		/* jumpg */
463 	"jls",		/* jumple (jlequ) */
464 	"jcs",		/* jumpl (jlssu) */
465 	"jcc",		/* jumpge (jgequ) */
466 	"jhi",		/* jumpg (jgtru) */
467 };
468 
469 
470 /*   printf conditional and unconditional branches */
471 void
cbgen(int o,int lab)472 cbgen(int o, int lab)
473 {
474 	if (o < EQ || o > UGT)
475 		comperr("bad conditional branch: %s", opst[o]);
476 	printf("	%s " LABFMT "\n", ccbranches[o-EQ], lab);
477 }
478 
479 static void
mkcall(NODE * p,char * name)480 mkcall(NODE *p, char *name)
481 {
482 	p->n_op = CALL;
483 	p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
484 	p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
485 	p->n_left->n_name = name;
486 }
487 
488 static void
mkcall2(NODE * p,char * name)489 mkcall2(NODE *p, char *name)
490 {
491 	p->n_op = CALL;
492 	p->n_right = mkunode(FUNARG, p->n_right, 0, p->n_right->n_type);
493 	p->n_left = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
494 	p->n_right = mkbinode(CM, p->n_left, p->n_right, INT);
495 	p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
496 	p->n_left->n_name = name;
497 }
498 
499 
500 static void
fixcalls(NODE * p,void * arg)501 fixcalls(NODE *p, void *arg)
502 {
503 	struct attr *ap;
504 	TWORD lt;
505 
506 	switch (p->n_op) {
507 	case STCALL:
508 	case USTCALL:
509 		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
510 		if (ap->iarg(0)+p2autooff > stkpos)
511 			stkpos = ap->iarg(0)+p2autooff;
512 		break;
513 
514 	case DIV:
515 		if (p->n_type == LONGLONG)
516 			mkcall2(p, "__divdi3");
517 		else if (p->n_type == ULONGLONG)
518 			mkcall2(p, "__udivdi3");
519 		break;
520 
521 	case MOD:
522 		if (p->n_type == LONGLONG)
523 			mkcall2(p, "__moddi3");
524 		else if (p->n_type == ULONGLONG)
525 			mkcall2(p, "__umoddi3");
526 		break;
527 
528 	case MUL:
529 		if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
530 			mkcall2(p, "__muldi3");
531 		break;
532 
533 	case LS:
534 		if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
535 			mkcall2(p, "__ashldi3");
536 		break;
537 
538 	case RS:
539 		if (p->n_type == LONGLONG)
540 			mkcall2(p, "__ashrdi3");
541 		else if (p->n_type == ULONGLONG)
542 			mkcall2(p, "__lshrdi3");
543 		break;
544 
545 	case SCONV:
546 		lt = p->n_left->n_type;
547 		switch (p->n_type) {
548 		case LONGLONG:
549 			if (lt == FLOAT)
550 				mkcall(p, "__fixsfdi");
551 			else if (lt == DOUBLE)
552 				mkcall(p, "__fixdfdi");
553 			else if (lt == LDOUBLE)
554 				mkcall(p, "__fixxfdi");
555 			break;
556 		case ULONGLONG:
557 			if (lt == FLOAT)
558 				mkcall(p, "__fixunssfdi");
559 			else if (lt == DOUBLE)
560 				mkcall(p, "__fixunsdfdi");
561 			else if (lt == LDOUBLE)
562 				mkcall(p, "__fixunsxfdi");
563 			break;
564 		case FLOAT:
565 			if (lt == LONGLONG)
566 				mkcall(p, "__floatdisf");
567 			else if (lt == ULONGLONG)
568 				mkcall(p, "__floatundisf");
569 			break;
570 		case DOUBLE:
571 			if (lt == LONGLONG)
572 				mkcall(p, "__floatdidf");
573 			else if (lt == ULONGLONG)
574 				mkcall(p, "__floatundidf");
575 			break;
576 		case LDOUBLE:
577 			if (lt == LONGLONG)
578 				mkcall(p, "__floatdixf");
579 			else if (lt == ULONGLONG)
580 				mkcall(p, "__floatundixf");
581 			break;
582 		}
583 		break;
584 #if 0
585 	case XASM:
586 		p->n_name = adjustname(p->n_name);
587 		break;
588 #endif
589 	}
590 }
591 
592 void
myreader(struct interpass * ipole)593 myreader(struct interpass *ipole)
594 {
595 	struct interpass *ip;
596 
597 	stkpos = p2autooff;
598 	DLIST_FOREACH(ip, ipole, qelem) {
599 		if (ip->type != IP_NODE)
600 			continue;
601 		walkf(ip->ip_node, fixcalls, 0);
602 	}
603 	if (stkpos > p2autooff)
604 		p2autooff = stkpos;
605 	if (stkpos > p2maxautooff)
606 		p2maxautooff = stkpos;
607 	if (x2debug)
608 		printip(ipole);
609 }
610 
611 /*
612  * Remove some PCONVs after OREGs are created.
613  */
614 static void
pconv2(NODE * p,void * arg)615 pconv2(NODE *p, void *arg)
616 {
617 	NODE *q;
618 
619 	if (p->n_op == PLUS) {
620 		if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
621 			if (p->n_right->n_op != ICON)
622 				return;
623 			if (p->n_left->n_op != PCONV)
624 				return;
625 			if (p->n_left->n_left->n_op != OREG)
626 				return;
627 			q = p->n_left->n_left;
628 			nfree(p->n_left);
629 			p->n_left = q;
630 			/*
631 			 * This will be converted to another OREG later.
632 			 */
633 		}
634 	}
635 }
636 
637 void
mycanon(NODE * p)638 mycanon(NODE *p)
639 {
640 	walkf(p, pconv2, 0);
641 }
642 
643 void
myoptim(struct interpass * ip)644 myoptim(struct interpass *ip)
645 {
646 }
647 
648 void
rmove(int s,int d,TWORD t)649 rmove(int s, int d, TWORD t)
650 {
651 
652 	if (s >= D0D1 && s <= D6D7) {
653 		printf("	move.l %s,%s\n",
654 		    rnames[s-D0D1], rnames[d-D0D1]);
655 		printf("	move.l %s,%s\n",
656 		    rnames[s+1-D0D1], rnames[d+1-D0D1]);
657 	} else if (t >= FLOAT && t <= TDOUBLE)
658 		printf("	fmove.x %s,%s\n", rnames[s], rnames[d]);
659 	else
660 		printf("	move.l %s,%s\n", rnames[s], rnames[d]);
661 }
662 
663 /*
664  * For class cc, find worst-case displacement of the number of
665  * registers in the array r[] indexed by class.
666  */
667 int
COLORMAP(int cc,int * r)668 COLORMAP(int cc, int *r)
669 {
670 	int a,c;
671 
672 	a = r[CLASSA];
673 	c = r[CLASSC];
674 
675 	switch (cc) {
676 	case CLASSA:
677 		if (c * 2 + a < 8)
678 			return 1;
679 		break;
680 	case CLASSB:
681 		return r[CLASSB] < 6;
682 	case CLASSC:
683 		if (c > 2)
684 			return 0;
685 		if (c == 2 && a > 0)
686 			return 0;
687 		if (c == 1 && a > 1)
688 			return 0;
689 		if (c == 0 && a > 3)
690 			return 0;
691 		return 1;
692 	}
693 	return 0;
694 }
695 
696 char *rnames[] = {
697 	"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
698 	"%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
699 	"d0d1", "d1d2", "d2d3", "d3d4", "d4d5", "d5d6", "d6d7",
700 	"%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7",
701 };
702 
703 /*
704  * Return a class suitable for a specific type.
705  */
706 int
gclass(TWORD t)707 gclass(TWORD t)
708 {
709 	if (t > BTMASK)
710 		return CLASSB;
711 	if (t == LONGLONG || t == ULONGLONG)
712 		return CLASSC;
713 	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
714 		return CLASSD;
715 	return CLASSA;
716 }
717 
718 static int
argsiz(NODE * p)719 argsiz(NODE *p)
720 {
721 	TWORD t = p->n_type;
722 
723 	if (t < LONGLONG || t == FLOAT || t > BTMASK)
724 		return 4;
725 	if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
726 		return 8;
727 	if (t == LDOUBLE)
728 		return 12;
729 	if (t == STRTY || t == UNIONTY)
730 		return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3) & ~3;
731 	comperr("argsiz");
732 	return 0;
733 }
734 
735 /*
736  * Calculate argument sizes.
737  */
738 void
lastcall(NODE * p)739 lastcall(NODE *p)
740 {
741 	NODE *op = p;
742 	int size = 0;
743 
744 	p->n_qual = 0;
745 	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
746 		return;
747 	for (p = p->n_right; p->n_op == CM; p = p->n_left)
748 		size += argsiz(p->n_right);
749 	size += argsiz(p);
750 	op->n_qual = size; /* XXX */
751 }
752 
753 /*
754  * Special shapes.
755  */
756 int
special(NODE * p,int shape)757 special(NODE *p, int shape)
758 {
759 	return SRNOPE;
760 }
761 
762 /*
763  * Target-dependent command-line options.
764  */
765 void
mflags(char * str)766 mflags(char *str)
767 {
768 }
769 
770 /*
771  * Do something target-dependent for xasm arguments.
772  */
773 int
myxasm(struct interpass * ip,NODE * p)774 myxasm(struct interpass *ip, NODE *p)
775 {
776 	int cw = xasmcode(p->n_name);
777 	int ww;
778 	char *w;
779 
780 	ww = XASMVAL(cw);
781 again:	switch (ww) {
782 	case 'd': /* Just convert to reg */
783 	case 'a':
784 		p->n_name = tmpstrdup(p->n_name);
785 		w = strchr(p->n_name, XASMVAL(cw));
786 		*w = 'r'; /* now reg */
787 		break;
788 	case 'o': /* offsetable reg */
789 		if (p->n_left->n_op == UMUL || p->n_left->n_op == OREG ||
790 		    p->n_left->n_op == NAME) {
791 			return 1;
792 		}
793 		if (ww == XASMVAL(cw))
794 			ww = XASMVAL1(cw);
795 		else
796 			ww = XASMVAL2(cw);
797 		goto again;
798 	}
799 	return 0;
800 }
801 
802 /*
803  * Handle special characters following % in gcc extended assembler.
804  */
805 int
targarg(char * w,void * arg)806 targarg(char *w, void *arg)
807 {
808 	switch (w[1]) {
809 	case '.': /* Remove dot if not needed */
810 		printf(".");
811 		break;
812 	default:
813 		return 0;
814 	}
815 	return 1;
816 }
817