xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/pdp11/local2.c (revision f14316bcbc544b96a93e884bc5c2b15fd60e22ae)
1 /*	Id: local2.c,v 1.8 2009/07/29 12:34:19 ragge Exp 	*/
2 /*	$NetBSD: local2.c,v 1.1.1.2 2010/06/03 18:57:25 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 static int spcoff;
35 static int argsiz(NODE *p);
36 
37 void
38 deflab(int label)
39 {
40 	printf(LABFMT ":\n", label);
41 }
42 
43 void
44 prologue(struct interpass_prolog *ipp)
45 {
46 	int addto;
47 
48 #ifdef LANG_F77
49 	if (ipp->ipp_vis)
50 		printf("	.globl %s\n", ipp->ipp_name);
51 	printf("%s:\n", ipp->ipp_name);
52 #endif
53 	printf("jsr	r5,csv\n");
54 	addto = p2maxautooff;
55 	if (addto >= AUTOINIT/SZCHAR)
56 		addto -= AUTOINIT/SZCHAR;
57 	if (addto & 1)
58 		addto++;
59 	if (addto == 2)
60 		printf("tst	-(sp)\n");
61 	else if (addto == 4)
62 		printf("cmp	-(sp),-(sp)\n");
63 	else if (addto > 4)
64 		printf("sub	$%o,sp\n", addto);
65 	spcoff = 0;
66 }
67 
68 void
69 eoftn(struct interpass_prolog *ipp)
70 {
71 	if (spcoff)
72 		comperr("spcoff == %d", spcoff);
73 	if (ipp->ipp_ip.ip_lbl == 0)
74 		return; /* no code needs to be generated */
75 	printf("jmp	cret\n");
76 }
77 
78 /*
79  * add/sub/...
80  *
81  * Param given:
82  */
83 void
84 hopcode(int f, int o)
85 {
86 	char *str;
87 
88 	switch (o) {
89 	case PLUS:
90 		str = "add";
91 		break;
92 	case MINUS:
93 		str = "sub";
94 		break;
95 	case AND:
96 		str = "and";
97 		break;
98 	case OR:
99 		str = "or";
100 		break;
101 	case ER:
102 		str = "xor";
103 		break;
104 	default:
105 		comperr("hopcode2: %d", o);
106 		str = 0; /* XXX gcc */
107 	}
108 	printf("%s%c", str, f);
109 }
110 
111 /*
112  * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
113  */
114 int
115 tlen(p) NODE *p;
116 {
117 	switch(p->n_type) {
118 		case CHAR:
119 		case UCHAR:
120 			return(1);
121 
122 		case SHORT:
123 		case USHORT:
124 			return(SZSHORT/SZCHAR);
125 
126 		case DOUBLE:
127 			return(SZDOUBLE/SZCHAR);
128 
129 		case INT:
130 		case UNSIGNED:
131 		case LONG:
132 		case ULONG:
133 			return(SZINT/SZCHAR);
134 
135 		case LONGLONG:
136 		case ULONGLONG:
137 			return SZLONGLONG/SZCHAR;
138 
139 		default:
140 			if (!ISPTR(p->n_type))
141 				comperr("tlen type %d not pointer");
142 			return SZPOINT(p->n_type)/SZCHAR;
143 		}
144 }
145 
146 /*
147  * Emit code to compare two long numbers.
148  */
149 static void
150 twolcomp(NODE *p)
151 {
152 	int o = p->n_op;
153 	int s = getlab2();
154 	int e = p->n_label;
155 	int cb1, cb2;
156 
157 	if (o >= ULE)
158 		o -= (ULE-LE);
159 	switch (o) {
160 	case NE:
161 		cb1 = 0;
162 		cb2 = NE;
163 		break;
164 	case EQ:
165 		cb1 = NE;
166 		cb2 = 0;
167 		break;
168 	case LE:
169 	case LT:
170 		cb1 = GT;
171 		cb2 = LT;
172 		break;
173 	case GE:
174 	case GT:
175 		cb1 = LT;
176 		cb2 = GT;
177 		break;
178 
179 	default:
180 		cb1 = cb2 = 0; /* XXX gcc */
181 	}
182 	if (p->n_op >= ULE)
183 		cb1 += 2, cb2 += 2;
184 	expand(p, 0, "cmp	AR,AL\n");
185 	if (cb1) cbgen(cb1, s);
186 	if (cb2) cbgen(cb2, e);
187         expand(p, 0, "cmp	UR,UL\n");
188         cbgen(p->n_op, e);
189         deflab(s);
190 }
191 
192 
193 /*
194  * Generate compare code for long instructions when right node is 0.
195  */
196 static void
197 lcomp(NODE *p)
198 {
199 	switch (p->n_op) {
200 	case EQ:
201 		expand(p, FORCC, "tst	AL\n");
202 		printf("jne	1f\n");
203 		expand(p, FORCC, "tst	UL\n");
204 		cbgen(EQ, p->n_label);
205 		printf("1:\n");
206 		break;
207 	case NE:
208 		expand(p, FORCC, "tst	AL\n");
209 		cbgen(NE, p->n_label);
210 		expand(p, FORCC, "tst	UL\n");
211 		cbgen(NE, p->n_label);
212 		break;
213 	case GE:
214 		expand(p, FORCC, "tst	AL\n");
215 		cbgen(GE, p->n_label);
216 		break;
217 	default:
218 		comperr("lcomp %p", p);
219 	}
220 }
221 
222 void
223 zzzcode(NODE *p, int c)
224 {
225 	switch (c) {
226 	case 'A': /* print out - if not first arg */
227 		if (spcoff || (p->n_type == FLOAT || p->n_type == DOUBLE))
228 			printf("-");
229 		spcoff += argsiz(p);
230 		break;
231 
232 	case 'B': /* arg is pointer to block */
233 		expand(p->n_left, FOREFF, "mov	AL,ZA(sp)\n");
234 		expand(p->n_left, FOREFF, "sub	CR,(sp)\n");
235 		break;
236 
237 	case 'C': /* subtract stack after call */
238 		spcoff -= p->n_qual;
239 		if (spcoff == 0 && !(p->n_flags & NLOCAL1))
240 			p->n_qual -= 2;
241 		if (p->n_qual == 2)
242 			printf("tst	(sp)+\n");
243 		else if (p->n_qual == 4)
244 			printf("cmp	(sp)+,(sp)+\n");
245 		else if (p->n_qual > 2)
246 			printf("add	$%o,sp\n", (int)p->n_qual);
247 		break;
248 
249 	case 'D': /* long comparisions */
250 		lcomp(p);
251 		break;
252 
253 	case 'E': /* long move */
254 		rmove(p->n_right->n_reg, p->n_left->n_reg, p->n_type);
255 		break;
256 
257 	case 'F': /* long comparision */
258 		twolcomp(p);
259 		break;
260 
261 	case 'G': /* printout a subnode for post-inc */
262 		adrput(stdout, p->n_left->n_left);
263 		break;
264 
265 	case 'H': /* arg with post-inc */
266 		expand(p->n_left->n_left, FOREFF, "mov	AL,ZA(sp)\n");
267 		expand(p->n_left->n_left, FOREFF, "inc	AL\n");
268 		break;
269 
270 	case 'Q': /* struct assignment, no rv */
271 		printf("mov	$%o,", p->n_stsize/2);
272 		expand(p, INAREG, "A1\n");
273 		printf("1:\n");
274 		expand(p, INAREG, "mov	(AR)+,(AL)+\n");
275 		expand(p, INAREG, "dec	A1\n");
276 		printf("jne	1b\n");
277 		break;
278 
279 	case 'R': /* struct assignment with rv */
280 		printf("mov	$%o,", p->n_stsize/2);
281 		expand(p, INAREG, "A1\n");
282 		expand(p, INAREG, "mov	AR,A2\n");
283 		printf("1:\n");
284 		expand(p, INAREG, "mov	(A2)+,(AL)+\n");
285 		expand(p, INAREG, "dec	A1\n");
286 		printf("jne	1b\n");
287 		break;
288 
289 	case '1': /* lower part of double regs */
290 		p = getlr(p, '1');
291 		printf("r%c", rnames[p->n_rval][1]);
292 		break;
293 
294 	default:
295 		comperr("zzzcode %c", c);
296 	}
297 }
298 
299 /*ARGSUSED*/
300 int
301 rewfld(NODE *p)
302 {
303 	return(1);
304 }
305 
306 int canaddr(NODE *);
307 int
308 canaddr(NODE *p)
309 {
310 	int o = p->n_op;
311 
312 	if (o==NAME || o==REG || o==ICON || o==OREG ||
313 	    (o==UMUL && shumul(p->n_left, STARNM|SOREG)))
314 		return(1);
315 	return(0);
316 }
317 
318 /*
319  * Does the bitfield shape match?
320  */
321 int
322 flshape(NODE *p)
323 {
324 	int o = p->n_op;
325 
326 	if (o == OREG || o == REG || o == NAME)
327 		return SRDIR; /* Direct match */
328 	if (o == UMUL && shumul(p->n_left, SOREG))
329 		return SROREG; /* Convert into oreg */
330 	return SRREG; /* put it into a register */
331 }
332 
333 /* INTEMP shapes must not contain any temporary registers */
334 /* XXX should this go away now? */
335 int
336 shtemp(NODE *p)
337 {
338 	return 0;
339 #if 0
340 	int r;
341 
342 	if (p->n_op == STARG )
343 		p = p->n_left;
344 
345 	switch (p->n_op) {
346 	case REG:
347 		return (!istreg(p->n_rval));
348 
349 	case OREG:
350 		r = p->n_rval;
351 		if (R2TEST(r)) {
352 			if (istreg(R2UPK1(r)))
353 				return(0);
354 			r = R2UPK2(r);
355 		}
356 		return (!istreg(r));
357 
358 	case UMUL:
359 		p = p->n_left;
360 		return (p->n_op != UMUL && shtemp(p));
361 	}
362 
363 	if (optype(p->n_op) != LTYPE)
364 		return(0);
365 	return(1);
366 #endif
367 }
368 
369 static void
370 negcon(FILE *fp, int con)
371 {
372 	if (con < 0)
373 		fprintf(fp, "-"), con = -con;
374 	fprintf(fp, "%o", con & 0177777);
375 }
376 
377 void
378 adrcon(CONSZ val)
379 {
380 	printf("$" CONFMT, val);
381 }
382 
383 void
384 conput(FILE *fp, NODE *p)
385 {
386 	int val = p->n_lval;
387 
388 	switch (p->n_op) {
389 	case ICON:
390 		printf("$");
391 		if (p->n_name[0] != '\0') {
392 			fprintf(fp, "%s", p->n_name);
393 			if (val)
394 				fprintf(fp, "+%o", val & 0177777);
395 		} else if (p->n_type == LONG || p->n_type == ULONG)
396 			negcon(fp, val >> 16);
397 		else
398 			negcon(fp, val);
399 		return;
400 
401 	default:
402 		comperr("illegal conput, p %p", p);
403 	}
404 }
405 
406 /*ARGSUSED*/
407 void
408 insput(NODE *p)
409 {
410 	comperr("insput");
411 }
412 
413 /*
414  * Write out the upper address, like the upper register of a 2-register
415  * reference, or the next memory location.
416  */
417 void
418 upput(NODE *p, int size)
419 {
420 	size /= SZINT;
421 	switch (p->n_op) {
422 	case NAME:
423 	case OREG:
424 		p->n_lval += size;
425 		adrput(stdout, p);
426 		p->n_lval -= size;
427 		break;
428 	case REG:
429 		printf("r%c", rnames[p->n_rval][2]);
430 		break;
431 	case ICON:
432 		/* On PDP11 upper value is low 16 bits */
433 		printf("$");
434 		negcon(stdout, p->n_lval & 0177777);
435 		break;
436 	default:
437 		comperr("upput bad op %d size %d", p->n_op, size);
438 	}
439 }
440 
441 /*
442  * output an address, with offsets, from p
443  */
444 void
445 adrput(FILE *io, NODE *p)
446 {
447 	int r;
448 
449 	if (p->n_op == FLD)
450 		p = p->n_left;
451 
452 	switch (p->n_op) {
453 	case NAME:
454 		if (p->n_name[0] != '\0') {
455 			fputs(p->n_name, io);
456 			if (p->n_lval != 0)
457 				fprintf(io, "+%o", (int)(p->n_lval&0177777));
458 		} else
459 			negcon(io, p->n_lval);
460 		return;
461 
462 	case OREG:
463 		r = p->n_rval;
464 		if (p->n_name[0])
465 			printf("%s%s", p->n_name, p->n_lval ? "+" : "");
466 		if (R2TEST(r) && R2UPK3(r) == 0)
467 			printf("*");
468 		if (p->n_lval)
469 			negcon(io, p->n_lval);
470 		if (R2TEST(r)) {
471 			fprintf(io, "(%s)", rnames[R2UPK1(r)]);
472 			if (R2UPK3(r) == 1)
473 				fprintf(io, "+");
474 		} else
475 			fprintf(io, "(%s)", rnames[p->n_rval]);
476 		return;
477 	case ICON:
478 		/* addressable value of the constant */
479 		conput(io, p);
480 		return;
481 
482 	case REG:
483 		switch (p->n_type) {
484 		case LONG:
485 		case ULONG:
486 			fprintf(io, "r%c", rnames[p->n_rval][1]);
487 			break;
488 		default:
489 			fprintf(io, "%s", rnames[p->n_rval]);
490 		}
491 		return;
492 
493 	case UMUL:
494 		if (tshape(p, STARNM)) {
495 			printf("*");
496 			adrput(io, p->n_left);
497 			break;
498 		}
499 		/* FALLTHROUGH */
500 	default:
501 		comperr("illegal address, op %d, node %p", p->n_op, p);
502 		return;
503 
504 	}
505 }
506 
507 static char *
508 ccbranches[] = {
509 	"jeq",		/* jumpe */
510 	"jne",		/* jumpn */
511 	"jle",		/* jumple */
512 	"jlt",		/* jumpl */
513 	"jge",		/* jumpge */
514 	"jgt",		/* jumpg */
515 	"jlos",		/* jumple (jlequ) */
516 	"jlo",		/* jumpl (jlssu) */
517 	"jhis",		/* jumpge (jgequ) */
518 	"jhi",		/* jumpg (jgtru) */
519 };
520 
521 
522 /*   printf conditional and unconditional branches */
523 void
524 cbgen(int o, int lab)
525 {
526 	if (o < EQ || o > UGT)
527 		comperr("bad conditional branch: %s", opst[o]);
528 	printf("%s	" LABFMT "\n", ccbranches[o-EQ], lab);
529 }
530 
531 #define	IS1CON(p) ((p)->n_op == ICON && (p)->n_lval == 1)
532 
533 /*
534  * Move postfix operators to the next statement, unless they are
535  * within a function call or a branch.
536  */
537 static void
538 cvtree(NODE *p, struct interpass *ip2)
539 {
540 	struct interpass *ip;
541 	NODE *q;
542 
543 	if (callop(p->n_op) || p->n_op == CBRANCH)
544 		return;
545 
546 	if ((p->n_op == PLUS || p->n_op == MINUS) &&
547 	    IS1CON(p->n_right) && (q = p->n_left)->n_op == ASSIGN &&
548 	    treecmp(q->n_left, q->n_right->n_left) &&
549 	    IS1CON(q->n_right->n_right)) {
550 		if ((p->n_op == PLUS && q->n_right->n_op == MINUS) ||
551 		    (p->n_op == MINUS && q->n_right->n_op == PLUS)) {
552 			nfree(p->n_right);
553 			*p = *q->n_left;
554 			if (optype(p->n_op) != LTYPE)
555 				p->n_left = tcopy(p->n_left);
556 			ip = ipnode(q);
557 			DLIST_INSERT_AFTER(ip2, ip, qelem);
558 			return;
559 		}
560 	}
561 	if (optype(p->n_op) == BITYPE)
562 		cvtree(p->n_right, ip2);
563 	if (optype(p->n_op) != LTYPE)
564 		cvtree(p->n_left, ip2);
565 }
566 
567 /*
568  * Convert AND to BIC.
569  */
570 static void
571 fixops(NODE *p, void *arg)
572 {
573 	static int fltwritten;
574 
575 	if (!fltwritten && (p->n_type == FLOAT || p->n_type == DOUBLE)) {
576 		printf(".globl	fltused\n");
577 		fltwritten = 1;
578 	}
579 	switch (p->n_op) {
580 	case AND:
581 		if (p->n_right->n_op == ICON) {
582 			p->n_right->n_lval = ((~p->n_right->n_lval) & 0177777);
583 		} else if (p->n_right->n_op == COMPL) {
584 			NODE *q = p->n_right->n_left;
585 			nfree(p->n_right);
586 			p->n_right = q;
587 		} else
588 			p->n_right = mkunode(COMPL, p->n_right, 0, p->n_type);
589 		break;
590 	case RS:
591 		p->n_right = mkunode(UMINUS, p->n_right, 0, p->n_right->n_type);
592 		p->n_op = LS;
593 		break;
594 	case EQ:
595 	case NE: /* Hack not to clear bits if FORCC */
596 		if (p->n_left->n_op == AND)
597 			fixops(p->n_left, 0); /* Convert an extra time */
598 		break;
599 	}
600 }
601 
602 void
603 myreader(struct interpass *ipole)
604 {
605 	struct interpass *ip;
606 
607 #ifdef PCC_DEBUG
608 	if (x2debug) {
609 		printf("myreader before\n");
610 		printip(ipole);
611 	}
612 #endif
613 	DLIST_FOREACH(ip, ipole, qelem) {
614 		if (ip->type != IP_NODE)
615 			continue;
616 		walkf(ip->ip_node, fixops, 0);
617 		canon(ip->ip_node); /* call it early */
618 	}
619 #ifdef PCC_DEBUG
620 	if (x2debug) {
621 		printf("myreader middle\n");
622 		printip(ipole);
623 	}
624 #endif
625 	DLIST_FOREACH(ip, ipole, qelem) {
626 		if (ip->type == IP_NODE)
627 			cvtree(ip->ip_node, ip);
628 	}
629 #ifdef PCC_DEBUG
630 	if (x2debug) {
631 		printf("myreader after\n");
632 		printip(ipole);
633 	}
634 #endif
635 }
636 
637 /*
638  * Remove SCONVs where the left node is an OREG with a smaller type.
639  */
640 static void
641 delsconv(NODE *p, void *arg)
642 {
643 #if 0
644 	NODE *l;
645 
646 	if (p->n_op != SCONV || (l = p->n_left)->n_op != OREG)
647 		return;
648 	if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == LONG) {
649 		p->n_op = OREG;
650 		p->n_lval = l->n_lval; /* high word */
651 		p->n_rval = l->n_rval;
652 		nfree(l);
653 	}
654 #endif
655 	/* Could do this for char etc. also */
656 }
657 
658 void
659 mycanon(NODE *p)
660 {
661 	walkf(p, delsconv, 0);
662 }
663 
664 void
665 myoptim(struct interpass *ip)
666 {
667 }
668 
669 void
670 rmove(int s, int d, TWORD t)
671 {
672 	if (t < LONG || t > BTMASK) {
673 		printf("mov%s	%s,%s\n", t < SHORT ? "b" : "",
674 		    rnames[s],rnames[d]); /* XXX char should be full reg? */
675 	} else if (t == LONG || t == ULONG) {
676 		/* avoid trashing double regs */
677 		if (d > s)
678 			printf("mov     r%c,r%c\nmov    r%c,r%c\n",
679 			    rnames[s][2],rnames[d][2],
680 			    rnames[s][1],rnames[d][1]);
681 		else
682 			printf("mov	r%c,r%c\nmov	r%c,r%c\n",
683 			    rnames[s][1],rnames[d][1],
684 			    rnames[s][2],rnames[d][2]);
685 	} else if (t == FLOAT || t == DOUBLE) {
686 		printf("movf	%s,%s\n", rnames[s],rnames[d]);
687 	} else
688 		comperr("bad float rmove: %d %d %x", s, d, t);
689 
690 }
691 
692 /*
693  * For class c, find worst-case displacement of the number of
694  * registers in the array r[] indexed by class.
695  */
696 int
697 COLORMAP(int c, int *r)
698 {
699 	switch (c) {
700 	case CLASSA:
701 		return (r[CLASSB] * 2 + r[CLASSA]) < 5;
702 	case CLASSB:
703 		if (r[CLASSB] > 1) return 0;
704 		if (r[CLASSB] == 1 && r[CLASSA] > 0) return 0;
705 		if (r[CLASSA] > 2) return 0;
706 		return 1;
707 	case CLASSC:
708 		return r[CLASSC] < 8;
709 	}
710 	return 0;
711 }
712 
713 char *rnames[] = {
714 	"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc",
715 	"r01", "r12", "r23", "r34", "XXX", "XXX", "XXX", "XXX",
716 	"fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "XXX", "XXX",
717 };
718 
719 /*
720  * Return a class suitable for a specific type.
721  */
722 int
723 gclass(TWORD t)
724 {
725 	if (t < LONG || t > BTMASK)
726 		return CLASSA;
727 	if (t == LONG || t == ULONG)
728 		return CLASSB;
729 	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
730 		return CLASSC;
731 	comperr("gclass");
732 	return CLASSD;
733 }
734 
735 static int
736 argsiz(NODE *p)
737 {
738 	TWORD t = p->n_type;
739 
740 	if (t == LONG || t == ULONG || t == FLOAT)
741 		return 4;
742 	if (t == DOUBLE)
743 		return 8;
744 	if (t == STRTY || t == UNIONTY)
745 		return p->n_stsize;
746 	return 2;
747 }
748 
749 /*
750  * Argument specialties.
751  */
752 void
753 lastcall(NODE *p)
754 {
755 	NODE *op = p;
756 	int size = 0;
757 
758 	/*
759 	 * Calculate arg sizes.
760 	 * Mark first arg not to have - before it.
761 	 */
762 	p->n_qual = 0;
763 	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
764 		return;
765 	for (p = p->n_right; p->n_op == CM; p = p->n_left) {
766 		p->n_right->n_qual = 0;
767 		size += argsiz(p->n_right);
768 	}
769 	p->n_qual = 0;
770 	size += argsiz(p);
771 	p = op->n_right;
772 
773 	if (p->n_op == CM)
774 		p = p->n_right;
775 	if (p->n_type == FLOAT || p->n_type == DOUBLE ||
776 	    p->n_type == STRTY || p->n_type == UNIONTY)
777 		op->n_flags |= NLOCAL1;	/* Does not use stack slot */
778 	else
779 		op->n_flags &= ~NLOCAL1;
780 	op->n_qual = size; /* XXX */
781 }
782 
783 static int
784 is1con(NODE *p)
785 {
786 	if (p->n_op == ICON && p->n_lval == 1)
787 		return 1;
788 	return 0;
789 }
790 
791 /*
792  * Special shapes.
793  */
794 int
795 special(NODE *p, int shape)
796 {
797 	CONSZ s;
798 
799 	switch (shape) {
800 	case SANDSCON:
801 		s = ~p->n_lval;
802 		if (s < 65536 || s > -65537)
803 			return SRDIR;
804 		break;
805 	case SINCB: /* Check if subject for post-inc */
806 		if (p->n_op == ASSIGN && p->n_right->n_op == PLUS &&
807 		    treecmp(p->n_left, p->n_right->n_left) &&
808 		    is1con(p->n_right->n_right))
809 			return SRDIR;
810 		break;
811 	case SARGSUB:
812 		if (p->n_op == MINUS && p->n_right->n_op == ICON &&
813 		    p->n_left->n_op == REG)
814 			return SRDIR;
815 		break;
816 	case SARGINC:
817 		if (p->n_op == MINUS && is1con(p->n_right))
818 			return special(p->n_left, SINCB);
819 		break;
820 	}
821 	return SRNOPE;
822 }
823 
824 /*
825  * Target-dependent command-line options.
826  */
827 void
828 mflags(char *str)
829 {
830 }
831 
832 /*
833  * Do something target-dependent for xasm arguments.
834  */
835 int
836 myxasm(struct interpass *ip, NODE *p)
837 {
838 	return 0;
839 }
840 
841 int
842 fldexpand(NODE *p, int cookie, char **cp)
843 {
844 	return 0;
845 }
846 
847