1 /* $Id: reader.c,v 1.290 2014/10/11 09:50:21 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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /*
28 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 *
34 * Redistributions of source code and documentation must retain the above
35 * copyright notice, this list of conditions and the following disclaimer.
36 * Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditionsand the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed or owned by Caldera
42 * International, Inc.
43 * Neither the name of Caldera International, Inc. nor the names of other
44 * contributors may be used to endorse or promote products derived from
45 * this software without specific prior written permission.
46 *
47 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
48 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
50 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51 * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
52 * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
56 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
57 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 * POSSIBILITY OF SUCH DAMAGE.
59 */
60
61 /*
62 * Everything is entered via pass2_compile(). No functions are
63 * allowed to recurse back into pass2_compile().
64 */
65
66 # include "pass2.h"
67
68 #include <string.h>
69 #include <stdarg.h>
70 #include <stdlib.h>
71
72 /* some storage declarations */
73 int nrecur;
74 int thisline;
75 int fregs;
76 int p2autooff, p2maxautooff;
77
78 NODE *nodepole;
79 struct interpass prepole;
80
81 void saveip(struct interpass *ip);
82 void deltemp(NODE *p, void *);
83 static void cvtemps(struct interpass *ipole, int op, int off);
84 static void fixxasm(struct p2env *);
85
86 static void gencode(NODE *p, int cookie);
87 static void genxasm(NODE *p);
88 static void afree(void);
89
90 struct p2env p2env;
91
92 int
getlab2(void)93 getlab2(void)
94 {
95 extern int getlab(void);
96 int rv = getlab();
97 #ifdef PCC_DEBUG
98 if (p2env.epp->ip_lblnum != rv)
99 comperr("getlab2 error: %d != %d", p2env.epp->ip_lblnum, rv);
100 #endif
101 p2env.epp->ip_lblnum++;
102 return rv;
103 }
104
105 #ifdef PCC_DEBUG
106 static int *lbldef, *lbluse;
107 static void
cktree(NODE * p,void * arg)108 cktree(NODE *p, void *arg)
109 {
110 int i;
111
112 if (p->n_op > MAXOP)
113 cerror("%p) op %d slipped through", p, p->n_op);
114 #ifndef FIELDOPS
115 if (p->n_op == FLD)
116 cerror("%p) FLD slipped through", p);
117 #endif
118 if (BTYPE(p->n_type) > MAXTYPES)
119 cerror("%p) type %x slipped through", p, p->n_type);
120 if (p->n_op == CBRANCH) {
121 if (!logop(p->n_left->n_op))
122 cerror("%p) not logop branch", p);
123 i = (int)p->n_right->n_lval;
124 if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
125 cerror("%p) label %d outside boundaries %d-%d",
126 p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
127 lbluse[i-p2env.ipp->ip_lblnum] = 1;
128 }
129 if ((dope[p->n_op] & ASGOPFLG) && p->n_op != RETURN)
130 cerror("%p) asgop %d slipped through", p, p->n_op);
131 if (p->n_op == TEMP &&
132 (regno(p) < p2env.ipp->ip_tmpnum || regno(p) >= p2env.epp->ip_tmpnum))
133 cerror("%p) temporary %d outside boundaries %d-%d",
134 p, regno(p), p2env.ipp->ip_tmpnum, p2env.epp->ip_tmpnum);
135 if (p->n_op == GOTO && p->n_left->n_op == ICON) {
136 i = (int)p->n_left->n_lval;
137 if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
138 cerror("%p) label %d outside boundaries %d-%d",
139 p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
140 lbluse[i-p2env.ipp->ip_lblnum] = 1;
141 }
142 }
143
144 /*
145 * Check that the trees are in a suitable state for pass2.
146 */
147 static void
sanitychecks(struct p2env * p2e)148 sanitychecks(struct p2env *p2e)
149 {
150 struct interpass *ip;
151 int i;
152 #ifdef notyet
153 TMPMARK();
154 #endif
155 lbldef = tmpcalloc(sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum));
156 lbluse = tmpcalloc(sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum));
157
158 DLIST_FOREACH(ip, &p2env.ipole, qelem) {
159 if (ip->type == IP_DEFLAB) {
160 i = ip->ip_lbl;
161 if (i < p2e->ipp->ip_lblnum || i >= p2e->epp->ip_lblnum)
162 cerror("label %d outside boundaries %d-%d",
163 i, p2e->ipp->ip_lblnum, p2e->epp->ip_lblnum);
164 lbldef[i-p2e->ipp->ip_lblnum] = 1;
165 }
166 if (ip->type == IP_NODE)
167 walkf(ip->ip_node, cktree, 0);
168 }
169 for (i = 0; i < (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum); i++)
170 if (lbluse[i] != 0 && lbldef[i] == 0)
171 cerror("internal label %d not defined",
172 i + p2e->ipp->ip_lblnum);
173
174 #ifdef notyet
175 TMPFREE();
176 #endif
177 }
178 #endif
179
180 /*
181 * Look if a temporary comes from a on-stack argument, in that case
182 * use the already existing stack position instead of moving it to
183 * a new place, and remove the move-to-temp statement.
184 */
185 static int
stkarg(int tnr,int (* soff)[2])186 stkarg(int tnr, int (*soff)[2])
187 {
188 struct p2env *p2e = &p2env;
189 struct interpass *ip;
190 NODE *p;
191
192 ip = DLIST_NEXT((struct interpass *)p2e->ipp, qelem);
193 while (ip->type != IP_DEFLAB) /* search for first DEFLAB */
194 ip = DLIST_NEXT(ip, qelem);
195
196 ip = DLIST_NEXT(ip, qelem); /* first NODE */
197
198 for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
199 if (ip->type != IP_NODE)
200 continue;
201
202 p = ip->ip_node;
203 if (p->n_op == XASM)
204 continue; /* XXX - hack for x86 PIC */
205 #ifdef notdef
206 if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
207 comperr("temparg");
208 #endif
209 if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
210 continue; /* unknown tree */
211
212 if (p->n_right->n_op != OREG && p->n_right->n_op != UMUL)
213 continue; /* arg in register */
214 if (tnr != regno(p->n_left))
215 continue; /* wrong assign */
216 p = p->n_right;
217 if (p->n_op == UMUL &&
218 p->n_left->n_op == PLUS &&
219 p->n_left->n_left->n_op == REG &&
220 p->n_left->n_right->n_op == ICON) {
221 soff[0][0] = regno(p->n_left->n_left);
222 soff[0][1] = (int)p->n_left->n_right->n_lval;
223 } else if (p->n_op == OREG) {
224 soff[0][0] = regno(p);
225 soff[0][1] = (int)p->n_lval;
226 } else
227 comperr("stkarg: bad arg");
228 tfree(ip->ip_node);
229 DLIST_REMOVE(ip, qelem);
230 return 1;
231 }
232 return 0;
233 }
234
235 /*
236 * See if an ADDROF is somewhere inside the expression tree.
237 * If so, fill in the offset table.
238 */
239 static void
findaof(NODE * p,void * arg)240 findaof(NODE *p, void *arg)
241 {
242 int (*aof)[2] = arg;
243 int tnr;
244
245 if (p->n_op != ADDROF || p->n_left->n_op != TEMP)
246 return;
247 tnr = regno(p->n_left);
248 if (aof[tnr][0])
249 return; /* already gotten stack address */
250 if (stkarg(tnr, &aof[tnr]))
251 return; /* argument was on stack */
252 aof[tnr][0] = FPREG;
253 aof[tnr][1] = freetemp(szty(p->n_left->n_type));
254 }
255
256 /*
257 * Check if a node has side effects.
258 */
259 static int
isuseless(NODE * n)260 isuseless(NODE *n)
261 {
262 switch (n->n_op) {
263 case XASM:
264 case FUNARG:
265 case UCALL:
266 case UFORTCALL:
267 case FORCE:
268 case ASSIGN:
269 case CALL:
270 case FORTCALL:
271 case CBRANCH:
272 case RETURN:
273 case GOTO:
274 case STCALL:
275 case USTCALL:
276 case STASG:
277 case STARG:
278 return 0;
279 default:
280 return 1;
281 }
282 }
283
284 /*
285 * Delete statements with no meaning (like a+b; or 513.4;)
286 */
287 NODE *
deluseless(NODE * p)288 deluseless(NODE *p)
289 {
290 struct interpass *ip;
291 NODE *l, *r;
292
293 if (optype(p->n_op) == LTYPE) {
294 nfree(p);
295 return NULL;
296 }
297 if (isuseless(p) == 0)
298 return p;
299
300 if (optype(p->n_op) == UTYPE) {
301 l = p->n_left;
302 nfree(p);
303 return deluseless(l);
304 }
305
306 /* Be sure that both leaves may be valid */
307 l = deluseless(p->n_left);
308 r = deluseless(p->n_right);
309 nfree(p);
310 if (l && r) {
311 ip = ipnode(l);
312 DLIST_INSERT_AFTER(&prepole, ip, qelem);
313 return r;
314 } else if (l)
315 return l;
316 else if (r)
317 return r;
318 return NULL;
319 }
320
321 /*
322 * Receives interpass structs from pass1.
323 */
324 void
pass2_compile(struct interpass * ip)325 pass2_compile(struct interpass *ip)
326 {
327 void deljumps(struct p2env *);
328 struct p2env *p2e = &p2env;
329 int (*addrp)[2];
330 MARK mark;
331
332 if (ip->type == IP_PROLOG) {
333 memset(p2e, 0, sizeof(struct p2env));
334 p2e->ipp = (struct interpass_prolog *)ip;
335 DLIST_INIT(&p2e->ipole, qelem);
336 }
337 DLIST_INSERT_BEFORE(&p2e->ipole, ip, qelem);
338 if (ip->type != IP_EPILOG)
339 return;
340
341 #ifdef PCC_DEBUG
342 if (e2debug) {
343 printf("Entering pass2\n");
344 printip(&p2e->ipole);
345 }
346 #endif
347
348 afree();
349 p2e->epp = (struct interpass_prolog *)DLIST_PREV(&p2e->ipole, qelem);
350 p2maxautooff = p2autooff = p2e->epp->ipp_autos;
351
352 #ifdef PCC_DEBUG
353 sanitychecks(p2e);
354 #endif
355 myreader(&p2e->ipole); /* local massage of input */
356
357 /*
358 * Do initial modification of the trees. Two loops;
359 * - first, search for ADDROF of TEMPs, these must be
360 * converterd to OREGs on stack.
361 * - second, do the actual conversions, in case of not xtemps
362 * convert all temporaries to stack references.
363 */
364 markset(&mark);
365 if (p2e->epp->ip_tmpnum != p2e->ipp->ip_tmpnum) {
366 addrp = tmpcalloc(sizeof(*addrp) *
367 (p2e->epp->ip_tmpnum - p2e->ipp->ip_tmpnum));
368 addrp -= p2e->ipp->ip_tmpnum;
369 } else
370 addrp = NULL;
371 if (xtemps) {
372 DLIST_FOREACH(ip, &p2e->ipole, qelem) {
373 if (ip->type == IP_NODE)
374 walkf(ip->ip_node, findaof, addrp);
375 }
376 }
377 DLIST_FOREACH(ip, &p2e->ipole, qelem)
378 if (ip->type == IP_NODE)
379 walkf(ip->ip_node, deltemp, addrp);
380 markfree(&mark);
381
382 #ifdef PCC_DEBUG
383 if (e2debug) {
384 printf("Efter ADDROF/TEMP\n");
385 printip(&p2e->ipole);
386 }
387 #endif
388
389 DLIST_INIT(&prepole, qelem);
390 DLIST_FOREACH(ip, &p2e->ipole, qelem) {
391 if (ip->type != IP_NODE)
392 continue;
393 canon(ip->ip_node);
394 if ((ip->ip_node = deluseless(ip->ip_node)) == NULL) {
395 DLIST_REMOVE(ip, qelem);
396 } else while (!DLIST_ISEMPTY(&prepole, qelem)) {
397 struct interpass *tipp;
398
399 tipp = DLIST_NEXT(&prepole, qelem);
400 DLIST_REMOVE(tipp, qelem);
401 DLIST_INSERT_BEFORE(ip, tipp, qelem);
402 }
403 }
404
405 fixxasm(p2e); /* setup for extended asm */
406
407 optimize(p2e);
408 ngenregs(p2e);
409
410 if (xtemps && xdeljumps)
411 deljumps(p2e);
412
413 DLIST_FOREACH(ip, &p2e->ipole, qelem)
414 emit(ip);
415 }
416
417 void
emit(struct interpass * ip)418 emit(struct interpass *ip)
419 {
420 NODE *p, *r;
421 struct optab *op;
422 int o;
423
424 switch (ip->type) {
425 case IP_NODE:
426 p = ip->ip_node;
427
428 nodepole = p;
429 canon(p); /* may convert stuff after genregs */
430 #ifdef PCC_DEBUG
431 if (c2debug > 1) {
432 printf("emit IP_NODE:\n");
433 fwalk(p, e2print, 0);
434 }
435 #endif
436 switch (p->n_op) {
437 case CBRANCH:
438 /* Only emit branch insn if RESCC */
439 /* careful when an OPLOG has been elided */
440 if (p->n_left->n_su == 0 && p->n_left->n_left != NULL) {
441 op = &table[TBLIDX(p->n_left->n_left->n_su)];
442 r = p->n_left;
443 } else {
444 op = &table[TBLIDX(p->n_left->n_su)];
445 r = p;
446 }
447 if (op->rewrite & RESCC) {
448 o = p->n_left->n_op;
449 gencode(r, FORCC);
450 cbgen(o, p->n_right->n_lval);
451 } else {
452 gencode(r, FORCC);
453 }
454 break;
455 case FORCE:
456 gencode(p->n_left, INREGS);
457 break;
458 case XASM:
459 genxasm(p);
460 break;
461 default:
462 if (p->n_op != REG || p->n_type != VOID) /* XXX */
463 gencode(p, FOREFF); /* Emit instructions */
464 }
465
466 tfree(p);
467 break;
468 case IP_PROLOG:
469 prologue((struct interpass_prolog *)ip);
470 break;
471 case IP_EPILOG:
472 eoftn((struct interpass_prolog *)ip);
473 p2maxautooff = p2autooff = AUTOINIT/SZCHAR;
474 break;
475 case IP_DEFLAB:
476 deflab(ip->ip_lbl);
477 break;
478 case IP_ASM:
479 printf("%s", ip->ip_asm);
480 break;
481 default:
482 cerror("emit %d", ip->type);
483 }
484 }
485
486 #ifdef PCC_DEBUG
487 char *cnames[] = {
488 "SANY",
489 "SAREG",
490 "SBREG",
491 "SCREG",
492 "SDREG",
493 "SCC",
494 "SNAME",
495 "SCON",
496 "SFLD",
497 "SOREG",
498 "STARNM",
499 "STARREG",
500 "INTEMP",
501 "FORARG",
502 "SWADD",
503 0,
504 };
505
506 /*
507 * print a nice-looking description of cookie
508 */
509 char *
prcook(int cookie)510 prcook(int cookie)
511 {
512 static char buf[50];
513 int i, flag;
514
515 if (cookie & SPECIAL) {
516 switch (cookie) {
517 case SZERO:
518 return "SZERO";
519 case SONE:
520 return "SONE";
521 case SMONE:
522 return "SMONE";
523 default:
524 snprintf(buf, sizeof(buf), "SPECIAL+%d", cookie & ~SPECIAL);
525 return buf;
526 }
527 }
528
529 flag = 0;
530 buf[0] = 0;
531 for (i = 0; cnames[i]; ++i) {
532 if (cookie & (1<<i)) {
533 if (flag)
534 strlcat(buf, "|", sizeof(buf));
535 ++flag;
536 strlcat(buf, cnames[i], sizeof(buf));
537 }
538 }
539 return buf;
540 }
541 #endif
542
543 int
geninsn(NODE * p,int cookie)544 geninsn(NODE *p, int cookie)
545 {
546 NODE *p1, *p2;
547 int q, o, rv = 0;
548
549 #ifdef PCC_DEBUG
550 if (o2debug) {
551 printf("geninsn(%p, %s)\n", p, prcook(cookie));
552 fwalk(p, e2print, 0);
553 }
554 #endif
555
556 q = cookie & QUIET;
557 cookie &= ~QUIET; /* XXX - should not be necessary */
558
559 again: switch (o = p->n_op) {
560 case EQ:
561 case NE:
562 case LE:
563 case LT:
564 case GE:
565 case GT:
566 case ULE:
567 case ULT:
568 case UGE:
569 case UGT:
570 p1 = p->n_left;
571 p2 = p->n_right;
572 if (p2->n_op == ICON && p2->n_lval == 0 && *p2->n_name == 0 &&
573 (dope[p1->n_op] & (FLOFLG|DIVFLG|SIMPFLG|SHFFLG))) {
574 #ifdef mach_pdp11 /* XXX all targets? */
575 if ((rv = geninsn(p1, FORCC|QUIET)) != FFAIL)
576 break;
577 #else
578 if (findops(p1, FORCC) > 0)
579 break;
580 #endif
581 }
582 rv = relops(p);
583 break;
584
585 case PLUS:
586 case MINUS:
587 case MUL:
588 case DIV:
589 case MOD:
590 case AND:
591 case OR:
592 case ER:
593 case LS:
594 case RS:
595 rv = findops(p, cookie);
596 break;
597
598 case ASSIGN:
599 #ifdef FINDMOPS
600 if ((rv = findmops(p, cookie)) != FFAIL)
601 break;
602 /* FALLTHROUGH */
603 #endif
604 case STASG:
605 rv = findasg(p, cookie);
606 break;
607
608 case UMUL: /* May turn into an OREG */
609 rv = findumul(p, cookie);
610 break;
611
612 case REG:
613 case TEMP:
614 case NAME:
615 case ICON:
616 case FCON:
617 case OREG:
618 rv = findleaf(p, cookie);
619 break;
620
621 case STCALL:
622 case CALL:
623 /* CALL arguments are handled special */
624 for (p1 = p->n_right; p1->n_op == CM; p1 = p1->n_left)
625 (void)geninsn(p1->n_right, FOREFF);
626 (void)geninsn(p1, FOREFF);
627 /* FALLTHROUGH */
628 case FLD:
629 case COMPL:
630 case UMINUS:
631 case PCONV:
632 case SCONV:
633 /* case INIT: */
634 case GOTO:
635 case FUNARG:
636 case STARG:
637 case UCALL:
638 case USTCALL:
639 case ADDROF:
640 rv = finduni(p, cookie);
641 break;
642
643 case CBRANCH:
644 p1 = p->n_left;
645 p2 = p->n_right;
646 p1->n_label = (int)p2->n_lval;
647 (void)geninsn(p1, FORCC);
648 p->n_su = 0;
649 break;
650
651 case FORCE: /* XXX needed? */
652 (void)geninsn(p->n_left, INREGS);
653 p->n_su = 0; /* su calculations traverse left */
654 break;
655
656 case XASM:
657 for (p1 = p->n_left; p1->n_op == CM; p1 = p1->n_left)
658 (void)geninsn(p1->n_right, FOREFF);
659 (void)geninsn(p1, FOREFF);
660 break; /* all stuff already done? */
661
662 case XARG:
663 /* generate code for correct class here */
664 #if 0
665 geninsn(p->n_left, 1 << p->n_label);
666 #endif
667 break;
668
669 default:
670 comperr("geninsn: bad op %s, node %p", opst[o], p);
671 }
672 if (rv == FFAIL && !q)
673 comperr("Cannot generate code, node %p op %s", p,opst[p->n_op]);
674 if (rv == FRETRY)
675 goto again;
676 #ifdef PCC_DEBUG
677 if (o2debug) {
678 printf("geninsn(%p, %s) rv %d\n", p, prcook(cookie), rv);
679 fwalk(p, e2print, 0);
680 }
681 #endif
682 return rv;
683 }
684
685 #ifdef PCC_DEBUG
686 #define CDEBUG(x) if (c2debug) printf x
687 #else
688 #define CDEBUG(x)
689 #endif
690
691 /*
692 * Do a register-register move if necessary.
693 * Called if a RLEFT or RRIGHT is found.
694 */
695 static void
ckmove(NODE * p,NODE * q)696 ckmove(NODE *p, NODE *q)
697 {
698 struct optab *t = &table[TBLIDX(p->n_su)];
699 int reg;
700
701 if (q->n_op != REG || p->n_reg == -1)
702 return; /* no register */
703
704 /* do we have a need for special reg? */
705 if ((t->needs & NSPECIAL) &&
706 (reg = rspecial(t, p->n_left == q ? NLEFT : NRIGHT)) >= 0)
707 ;
708 else
709 reg = DECRA(p->n_reg, 0);
710
711 if (reg < 0 || reg == DECRA(q->n_reg, 0))
712 return; /* no move necessary */
713
714 CDEBUG(("rmove: node %p, %s -> %s\n", p, rnames[DECRA(q->n_reg, 0)],
715 rnames[reg]));
716 rmove(DECRA(q->n_reg, 0), reg, p->n_type);
717 q->n_reg = q->n_rval = reg;
718 }
719
720 /*
721 * Rewrite node to register after instruction emit.
722 */
723 static void
rewrite(NODE * p,int dorewrite,int cookie)724 rewrite(NODE *p, int dorewrite, int cookie)
725 {
726 NODE *l, *r;
727 int o;
728
729 l = getlr(p, 'L');
730 r = getlr(p, 'R');
731 o = p->n_op;
732 p->n_op = REG;
733 p->n_lval = 0;
734 p->n_name = "";
735
736 if (o == ASSIGN || o == STASG) {
737 /* special rewrite care */
738 int reg = DECRA(p->n_reg, 0);
739 #define TL(x) (TBLIDX(x->n_su) || x->n_op == REG)
740 if (p->n_reg == -1)
741 ;
742 else if (TL(l) && (DECRA(l->n_reg, 0) == reg))
743 ;
744 else if (TL(r) && (DECRA(r->n_reg, 0) == reg))
745 ;
746 else if (TL(l))
747 rmove(DECRA(l->n_reg, 0), reg, p->n_type);
748 else if (TL(r))
749 rmove(DECRA(r->n_reg, 0), reg, p->n_type);
750 #if 0
751 else
752 comperr("rewrite");
753 #endif
754 #undef TL
755 }
756 if (optype(o) != LTYPE)
757 tfree(l);
758 if (optype(o) == BITYPE)
759 tfree(r);
760 if (dorewrite == 0)
761 return;
762 CDEBUG(("rewrite: %p, reg %s\n", p,
763 p->n_reg == -1? "<none>" : rnames[DECRA(p->n_reg, 0)]));
764 p->n_rval = DECRA(p->n_reg, 0);
765 }
766
767 #ifndef XASM_TARGARG
768 #define XASM_TARGARG(x,y) 0
769 #endif
770
771 /*
772 * printout extended assembler.
773 */
774 void
genxasm(NODE * p)775 genxasm(NODE *p)
776 {
777 NODE *q, **nary;
778 int n = 1, o = 0, v = 0;
779 char *w;
780
781 if (p->n_left->n_op != ICON || p->n_left->n_type != STRTY) {
782 for (q = p->n_left; q->n_op == CM; q = q->n_left)
783 n++;
784 nary = tmpcalloc(sizeof(NODE *)*(n+1));
785 o = n;
786 for (q = p->n_left; q->n_op == CM; q = q->n_left) {
787 gencode(q->n_right->n_left, INREGS);
788 nary[--o] = q->n_right;
789 }
790 gencode(q->n_left, INREGS);
791 nary[--o] = q;
792 } else
793 nary = 0;
794
795 w = p->n_name;
796 putchar('\t');
797 while (*w != 0) {
798 if (*w == '%') {
799 if (w[1] == '%')
800 putchar('%');
801 else if (XASM_TARGARG(w, nary))
802 ; /* handled by target */
803 else if (w[1] == '=') {
804 if (v == 0) v = getlab2();
805 printf("%d", v);
806 } else if (w[1] == 'c') {
807 q = nary[(int)w[2]-'0'];
808 if (q->n_left->n_op != ICON)
809 uerror("impossible constraint");
810 printf(CONFMT, q->n_left->n_lval);
811 w++;
812 } else if (w[1] < '0' || w[1] > (n + '0'))
813 uerror("bad xasm arg number %c", w[1]);
814 else {
815 if (w[1] == (n + '0'))
816 q = nary[(int)w[1]-'0' - 1]; /* XXX */
817 else
818 q = nary[(int)w[1]-'0'];
819 adrput(stdout, q->n_left);
820 }
821 w++;
822 } else if (*w == '\\') { /* Always 3-digit octal */
823 int num = *++w - '0';
824 num = (num << 3) + *++w - '0';
825 num = (num << 3) + *++w - '0';
826 putchar(num);
827 } else
828 putchar(*w);
829 w++;
830 }
831 putchar('\n');
832 }
833
834 /*
835 * Allocate temporary registers for use while emitting this table entry.
836 */
837 static void
allo(NODE * p,struct optab * q)838 allo(NODE *p, struct optab *q)
839 {
840 extern int stktemp;
841 int i, n = ncnt(q->needs);
842
843 for (i = 0; i < NRESC; i++)
844 if (resc[i].n_op != FREE)
845 comperr("allo: used reg");
846 if (n == 0 && (q->needs & NTMASK) == 0)
847 return;
848 for (i = 0; i < n+1; i++) {
849 resc[i].n_op = REG;
850 resc[i].n_type = p->n_type; /* XXX should be correct type */
851 resc[i].n_rval = DECRA(p->n_reg, i);
852 resc[i].n_su = p->n_su; /* ??? */
853 }
854 if (i > NRESC)
855 comperr("allo: too many allocs");
856 if (q->needs & NTMASK) {
857 #ifdef MYALLOTEMP
858 MYALLOTEMP(resc[i], stktemp);
859 #else
860 resc[i].n_op = OREG;
861 resc[i].n_lval = stktemp;
862 resc[i].n_rval = FPREG;
863 resc[i].n_su = p->n_su; /* ??? */
864 resc[i].n_name = "";
865 #endif
866 }
867 }
868
869 static void
afree(void)870 afree(void)
871 {
872 int i;
873
874 for (i = 0; i < NRESC; i++)
875 resc[i].n_op = FREE;
876 }
877
878 void
gencode(NODE * p,int cookie)879 gencode(NODE *p, int cookie)
880 {
881 struct optab *q = &table[TBLIDX(p->n_su)];
882 NODE *p1, *l, *r;
883 int o = optype(p->n_op);
884 #ifdef FINDMOPS
885 int ismops = (p->n_op == ASSIGN && (p->n_flags & 1));
886 #endif
887
888 l = p->n_left;
889 r = p->n_right;
890
891 if (TBLIDX(p->n_su) == 0) {
892 if (o == BITYPE && (p->n_su & DORIGHT))
893 gencode(r, 0);
894 if (optype(p->n_op) != LTYPE)
895 gencode(l, 0);
896 if (o == BITYPE && !(p->n_su & DORIGHT))
897 gencode(r, 0);
898 return;
899 }
900
901 CDEBUG(("gencode: node %p\n", p));
902
903 if (p->n_op == REG && DECRA(p->n_reg, 0) == p->n_rval)
904 return; /* meaningless move to itself */
905
906 if (callop(p->n_op))
907 lastcall(p); /* last chance before function args */
908 if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL) {
909 /* Print out arguments first */
910 for (p1 = r; p1->n_op == CM; p1 = p1->n_left)
911 gencode(p1->n_right, FOREFF);
912 gencode(p1, FOREFF);
913 o = UTYPE; /* avoid going down again */
914 }
915
916 if (o == BITYPE && (p->n_su & DORIGHT)) {
917 gencode(r, INREGS);
918 if (q->rewrite & RRIGHT)
919 ckmove(p, r);
920 }
921 if (o != LTYPE) {
922 gencode(l, INREGS);
923 #ifdef FINDMOPS
924 if (ismops)
925 ;
926 else
927 #endif
928 if (q->rewrite & RLEFT)
929 ckmove(p, l);
930 }
931 if (o == BITYPE && !(p->n_su & DORIGHT)) {
932 gencode(r, INREGS);
933 if (q->rewrite & RRIGHT)
934 ckmove(p, r);
935 }
936
937 #ifdef FINDMOPS
938 if (ismops) {
939 /* reduce right tree to make expand() work */
940 if (optype(r->n_op) != LTYPE) {
941 p->n_op = r->n_op;
942 r = tcopy(r->n_right);
943 tfree(p->n_right);
944 p->n_right = r;
945 }
946 }
947 #endif
948
949 canon(p);
950
951 if (q->needs & NSPECIAL) {
952 int rr = rspecial(q, NRIGHT);
953 int lr = rspecial(q, NLEFT);
954
955 if (rr >= 0) {
956 #ifdef PCC_DEBUG
957 if (optype(p->n_op) != BITYPE)
958 comperr("gencode: rspecial borked");
959 #endif
960 if (r->n_op != REG)
961 comperr("gencode: rop != REG");
962 if (rr != r->n_rval)
963 rmove(r->n_rval, rr, r->n_type);
964 r->n_rval = r->n_reg = rr;
965 }
966 if (lr >= 0) {
967 if (l->n_op != REG)
968 comperr("gencode: %p lop != REG", p);
969 if (lr != l->n_rval)
970 rmove(l->n_rval, lr, l->n_type);
971 l->n_rval = l->n_reg = lr;
972 }
973 if (rr >= 0 && lr >= 0 && (l->n_reg == rr || r->n_reg == lr))
974 comperr("gencode: cross-reg-move");
975 }
976
977 if (p->n_op == ASSIGN &&
978 p->n_left->n_op == REG && p->n_right->n_op == REG &&
979 p->n_left->n_rval == p->n_right->n_rval &&
980 (p->n_su & RVCC) == 0) { /* XXX should check if necessary */
981 /* do not emit anything */
982 CDEBUG(("gencode(%p) assign nothing\n", p));
983 rewrite(p, q->rewrite, cookie);
984 return;
985 }
986
987 CDEBUG(("emitting node %p\n", p));
988 if (TBLIDX(p->n_su) == 0)
989 return;
990
991 allo(p, q);
992 expand(p, cookie, q->cstring);
993
994 #ifdef FINDMOPS
995 if (ismops && DECRA(p->n_reg, 0) != regno(l) && cookie != FOREFF) {
996 CDEBUG(("gencode(%p) rmove\n", p));
997 rmove(regno(l), DECRA(p->n_reg, 0), p->n_type);
998 } else
999 #endif
1000 if (callop(p->n_op) && cookie != FOREFF &&
1001 DECRA(p->n_reg, 0) != RETREG(p->n_type)) {
1002 CDEBUG(("gencode(%p) retreg\n", p));
1003 rmove(RETREG(p->n_type), DECRA(p->n_reg, 0), p->n_type);
1004 } else if (q->needs & NSPECIAL) {
1005 int rr = rspecial(q, NRES);
1006
1007 if (rr >= 0 && DECRA(p->n_reg, 0) != rr) {
1008 CDEBUG(("gencode(%p) nspec retreg\n", p));
1009 rmove(rr, DECRA(p->n_reg, 0), p->n_type);
1010 }
1011 } else if ((q->rewrite & RESC1) &&
1012 (DECRA(p->n_reg, 1) != DECRA(p->n_reg, 0))) {
1013 CDEBUG(("gencode(%p) RESC1 retreg\n", p));
1014 rmove(DECRA(p->n_reg, 1), DECRA(p->n_reg, 0), p->n_type);
1015 }
1016 #if 0
1017 /* XXX - kolla upp det h{r */
1018 else if (p->n_op == ASSIGN) {
1019 /* may need move added if RLEFT/RRIGHT */
1020 /* XXX should be handled in sucomp() */
1021 if ((q->rewrite & RLEFT) && (p->n_left->n_op == REG) &&
1022 (p->n_left->n_rval != DECRA(p->n_reg, 0)) &&
1023 TCLASS(p->n_su)) {
1024 rmove(p->n_left->n_rval, DECRA(p->n_reg, 0), p->n_type);
1025 } else if ((q->rewrite & RRIGHT) && (p->n_right->n_op == REG) &&
1026 (p->n_right->n_rval != DECRA(p->n_reg, 0)) &&
1027 TCLASS(p->n_su)) {
1028 rmove(p->n_right->n_rval, DECRA(p->n_reg, 0), p->n_type);
1029 }
1030 }
1031 #endif
1032 rewrite(p, q->rewrite, cookie);
1033 afree();
1034 }
1035
1036 int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ; /* negatives of relationals */
1037 size_t negrelsize = sizeof negrel / sizeof negrel[0];
1038
1039 #ifdef PCC_DEBUG
1040 #undef PRTABLE
1041 void
e2print(NODE * p,int down,int * a,int * b)1042 e2print(NODE *p, int down, int *a, int *b)
1043 {
1044 #ifdef PRTABLE
1045 extern int tablesize;
1046 #endif
1047
1048 *a = *b = down+1;
1049 while( down >= 2 ){
1050 printf("\t");
1051 down -= 2;
1052 }
1053 if( down-- ) printf(" " );
1054
1055
1056 printf("%p) %s", p, opst[p->n_op] );
1057 switch( p->n_op ) { /* special cases */
1058
1059 case FLD:
1060 printf(" sz=%d, shift=%d",
1061 UPKFSZ(p->n_rval), UPKFOFF(p->n_rval));
1062 break;
1063
1064 case REG:
1065 printf(" %s", rnames[p->n_rval] );
1066 break;
1067
1068 case TEMP:
1069 printf(" %d", regno(p));
1070 break;
1071
1072 case XASM:
1073 case XARG:
1074 printf(" '%s'", p->n_name);
1075 break;
1076
1077 case ICON:
1078 case NAME:
1079 case OREG:
1080 printf(" " );
1081 adrput(stdout, p );
1082 break;
1083
1084 case STCALL:
1085 case USTCALL:
1086 case STARG:
1087 case STASG:
1088 printf(" size=%d", p->n_stsize );
1089 printf(" align=%d", p->n_stalign );
1090 break;
1091 }
1092
1093 printf(", " );
1094 tprint(p->n_type, p->n_qual);
1095 printf(", " );
1096
1097 prtreg(p);
1098 printf(", SU= %d(%cREG,%s,%s,%s,%s,%s,%s)\n",
1099 TBLIDX(p->n_su),
1100 TCLASS(p->n_su)+'@',
1101 #ifdef PRTABLE
1102 TBLIDX(p->n_su) >= 0 && TBLIDX(p->n_su) <= tablesize ?
1103 table[TBLIDX(p->n_su)].cstring : "",
1104 #else
1105 "",
1106 #endif
1107 p->n_su & LREG ? "LREG" : "", p->n_su & RREG ? "RREG" : "",
1108 p->n_su & RVEFF ? "RVEFF" : "", p->n_su & RVCC ? "RVCC" : "",
1109 p->n_su & DORIGHT ? "DORIGHT" : "");
1110 }
1111 #endif
1112
1113 /*
1114 * change left TEMPs into OREGs
1115 */
1116 void
deltemp(NODE * p,void * arg)1117 deltemp(NODE *p, void *arg)
1118 {
1119 int (*aor)[2] = arg;
1120 NODE *l;
1121
1122 if (p->n_op == TEMP) {
1123 if (aor[regno(p)][0] == 0) {
1124 if (xtemps)
1125 return;
1126 aor[regno(p)][0] = FPREG;
1127 aor[regno(p)][1] = freetemp(szty(p->n_type));
1128 }
1129 storemod(p, aor[regno(p)][1], aor[regno(p)][0]);
1130 } else if (p->n_op == ADDROF && p->n_left->n_op == OREG) {
1131 p->n_op = PLUS;
1132 l = p->n_left;
1133 l->n_op = REG;
1134 l->n_type = INCREF(l->n_type);
1135 p->n_right = mklnode(ICON, l->n_lval, 0, INT);
1136 } else if (p->n_op == ADDROF && p->n_left->n_op == UMUL) {
1137 l = p->n_left;
1138 *p = *p->n_left->n_left;
1139 nfree(l->n_left);
1140 nfree(l);
1141 }
1142 }
1143
1144 /*
1145 * for pointer/integer arithmetic, set pointer at left node
1146 */
1147 static void
setleft(NODE * p,void * arg)1148 setleft(NODE *p, void *arg)
1149 {
1150 NODE *q;
1151
1152 /* only additions for now */
1153 if (p->n_op != PLUS)
1154 return;
1155 if (ISPTR(p->n_right->n_type) && !ISPTR(p->n_left->n_type)) {
1156 q = p->n_right;
1157 p->n_right = p->n_left;
1158 p->n_left = q;
1159 }
1160 }
1161
1162 /* It is OK to have these as externals */
1163 static int oregr;
1164 static CONSZ oregtemp;
1165 static char *oregcp;
1166 /*
1167 * look for situations where we can turn * into OREG
1168 * If sharp then do not allow temps.
1169 */
1170 int
oregok(NODE * p,int sharp)1171 oregok(NODE *p, int sharp)
1172 {
1173
1174 NODE *q;
1175 NODE *ql, *qr;
1176 int r;
1177 CONSZ temp;
1178 char *cp;
1179
1180 q = p->n_left;
1181 #if 0
1182 if ((q->n_op == REG || (q->n_op == TEMP && !sharp)) &&
1183 q->n_rval == DECRA(q->n_reg, 0)) {
1184 #endif
1185 if (q->n_op == REG || (q->n_op == TEMP && !sharp)) {
1186 temp = q->n_lval;
1187 r = q->n_rval;
1188 cp = q->n_name;
1189 goto ormake;
1190 }
1191
1192 if (q->n_op != PLUS && q->n_op != MINUS)
1193 return 0;
1194 ql = q->n_left;
1195 qr = q->n_right;
1196
1197 #ifdef R2REGS
1198
1199 /* look for doubly indexed expressions */
1200 /* XXX - fix checks */
1201
1202 if( q->n_op == PLUS) {
1203 int i;
1204 if( (r=base(ql))>=0 && (i=offset(qr, tlen(p)))>=0) {
1205 makeor2(p, ql, r, i);
1206 return 1;
1207 } else if((r=base(qr))>=0 && (i=offset(ql, tlen(p)))>=0) {
1208 makeor2(p, qr, r, i);
1209 return 1;
1210 }
1211 }
1212
1213
1214 #endif
1215
1216 #if 0
1217 if( (q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON &&
1218 (ql->n_op==REG || (ql->n_op==TEMP && !sharp)) &&
1219 szty(qr->n_type)==1 &&
1220 (ql->n_rval == DECRA(ql->n_reg, 0) ||
1221 /* XXX */
1222 ql->n_rval == FPREG || ql->n_rval == STKREG)) {
1223 #endif
1224 if ((q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON &&
1225 (ql->n_op==REG || (ql->n_op==TEMP && !sharp))) {
1226
1227 temp = qr->n_lval;
1228 if( q->n_op == MINUS ) temp = -temp;
1229 r = ql->n_rval;
1230 temp += ql->n_lval;
1231 cp = qr->n_name;
1232 if( *cp && ( q->n_op == MINUS || *ql->n_name ) )
1233 return 0;
1234 if( !*cp ) cp = ql->n_name;
1235
1236 ormake:
1237 if( notoff( p->n_type, r, temp, cp ))
1238 return 0;
1239 oregtemp = temp;
1240 oregr = r;
1241 oregcp = cp;
1242 return 1;
1243 }
1244 return 0;
1245 }
1246
1247 static void
1248 ormake(NODE *p)
1249 {
1250 NODE *q = p->n_left;
1251
1252 p->n_op = OREG;
1253 p->n_rval = oregr;
1254 p->n_lval = oregtemp;
1255 p->n_name = oregcp;
1256 tfree(q);
1257 }
1258
1259 /*
1260 * look for situations where we can turn * into OREG
1261 */
1262 void
1263 oreg2(NODE *p, void *arg)
1264 {
1265 if (p->n_op != UMUL)
1266 return;
1267 if (oregok(p, 1))
1268 ormake(p);
1269 if (p->n_op == UMUL)
1270 myormake(p);
1271 }
1272
1273 void
1274 canon(NODE *p)
1275 {
1276 /* put p in canonical form */
1277
1278 walkf(p, setleft, 0); /* ptrs at left node for arithmetic */
1279 walkf(p, oreg2, 0); /* look for and create OREG nodes */
1280 mycanon(p); /* your own canonicalization routine(s) */
1281 }
1282
1283 void
1284 comperr(char *str, ...)
1285 {
1286 extern char *ftitle;
1287 va_list ap;
1288
1289 if (nerrors) {
1290 fprintf(stderr,
1291 "cannot recover from earlier errors: goodbye!\n");
1292 exit(1);
1293 }
1294
1295 va_start(ap, str);
1296 fprintf(stderr, "%s, line %d: compiler error: ", ftitle, thisline);
1297 vfprintf(stderr, str, ap);
1298 fprintf(stderr, "\n");
1299 va_end(ap);
1300
1301 #ifdef PCC_DEBUG
1302 if (nodepole && nodepole->n_op != FREE)
1303 fwalk(nodepole, e2print, 0);
1304 #endif
1305 exit(1);
1306 }
1307
1308 /*
1309 * allocate k integers worth of temp space
1310 * we also make the convention that, if the number of words is
1311 * more than 1, it must be aligned for storing doubles...
1312 * Returns bytes offset from base register.
1313 */
1314 int
1315 freetemp(int k)
1316 {
1317 int t, al, sz;
1318
1319 al = (k > 1 ? ALDOUBLE/ALCHAR : ALINT/ALCHAR);
1320 sz = k * (SZINT/SZCHAR);
1321
1322 #ifndef BACKTEMP
1323 SETOFF(p2autooff, al);
1324 t = p2autooff;
1325 p2autooff += sz;
1326 #else
1327 p2autooff += sz;
1328 SETOFF(p2autooff, al);
1329 t = ( -p2autooff );
1330 #endif
1331 if (p2autooff > p2maxautooff)
1332 p2maxautooff = p2autooff;
1333 return (t);
1334 }
1335
1336 NODE *
1337 storenode(TWORD t, int off)
1338 {
1339 NODE *p;
1340
1341 p = talloc();
1342 p->n_type = t;
1343 storemod(p, off, FPREG); /* XXX */
1344 return p;
1345 }
1346
1347 #ifndef MYSTOREMOD
1348 void
1349 storemod(NODE *q, int off, int reg)
1350 {
1351 NODE *l, *r, *p;
1352
1353 l = mklnode(REG, 0, reg, INCREF(q->n_type));
1354 r = mklnode(ICON, off, 0, INT);
1355 p = mkbinode(PLUS, l, r, INCREF(q->n_type));
1356 q->n_op = UMUL;
1357 q->n_left = p;
1358 q->n_rval = q->n_su = 0;
1359 }
1360 #endif
1361
1362 NODE *
1363 mklnode(int op, CONSZ lval, int rval, TWORD type)
1364 {
1365 NODE *p = talloc();
1366
1367 p->n_name = "";
1368 p->n_qual = 0;
1369 p->n_op = op;
1370 p->n_label = 0;
1371 p->n_lval = lval;
1372 p->n_rval = rval;
1373 p->n_type = type;
1374 p->n_regw = NULL;
1375 p->n_su = 0;
1376 return p;
1377 }
1378
1379 NODE *
1380 mkbinode(int op, NODE *left, NODE *right, TWORD type)
1381 {
1382 NODE *p = talloc();
1383
1384 p->n_name = "";
1385 p->n_qual = 0;
1386 p->n_op = op;
1387 p->n_label = 0;
1388 p->n_left = left;
1389 p->n_right = right;
1390 p->n_type = type;
1391 p->n_regw = NULL;
1392 p->n_su = 0;
1393 return p;
1394 }
1395
1396 NODE *
1397 mkunode(int op, NODE *left, int rval, TWORD type)
1398 {
1399 NODE *p = talloc();
1400
1401 p->n_name = "";
1402 p->n_qual = 0;
1403 p->n_op = op;
1404 p->n_label = 0;
1405 p->n_left = left;
1406 p->n_rval = rval;
1407 p->n_type = type;
1408 p->n_regw = NULL;
1409 p->n_su = 0;
1410 return p;
1411 }
1412
1413 struct interpass *
1414 ipnode(NODE *p)
1415 {
1416 struct interpass *ip = tmpalloc(sizeof(struct interpass));
1417
1418 ip->ip_node = p;
1419 ip->type = IP_NODE;
1420 ip->lineno = thisline;
1421 return ip;
1422 }
1423
1424 int
1425 rspecial(struct optab *q, int what)
1426 {
1427 struct rspecial *r = nspecial(q);
1428 while (r->op) {
1429 if (r->op == what)
1430 return r->num;
1431 r++;
1432 }
1433 return -1;
1434 }
1435
1436 #ifndef XASM_NUMCONV
1437 #define XASM_NUMCONV(x,y,z) 0
1438 #endif
1439
1440 /*
1441 * change numeric argument redirections to the correct node type after
1442 * cleaning up the other nodes.
1443 * be careful about input operands that may have different value than output.
1444 */
1445 static void
1446 delnums(NODE *p, void *arg)
1447 {
1448 struct interpass *ip = arg, *ip2;
1449 NODE *r = ip->ip_node->n_left;
1450 NODE *q;
1451 TWORD t;
1452 int cnt, num;
1453
1454 /* gcc allows % in constraints, but we ignore it */
1455 if (p->n_name[0] == '%' && p->n_name[1] >= '0' && p->n_name[1] <= '9')
1456 p->n_name++;
1457
1458 if (p->n_name[0] < '0' || p->n_name[0] > '9')
1459 return; /* not numeric */
1460 if ((q = listarg(r, p->n_name[0] - '0', &cnt)) == NIL)
1461 comperr("bad delnums");
1462
1463 /* target may have opinions whether to do this conversion */
1464 if (XASM_NUMCONV(ip, p, q))
1465 return;
1466
1467 /* Delete number by adding move-to/from-temp. Later on */
1468 /* the temps may be rewritten to other LTYPEs */
1469 num = p2env.epp->ip_tmpnum++;
1470
1471 /* pre node */
1472 t = p->n_left->n_type;
1473 r = mklnode(TEMP, 0, num, t);
1474 ip2 = ipnode(mkbinode(ASSIGN, tcopy(r), p->n_left, t));
1475 DLIST_INSERT_BEFORE(ip, ip2, qelem);
1476 p->n_left = r;
1477
1478 /* post node */
1479 t = q->n_left->n_type;
1480 r = mklnode(TEMP, 0, num, t);
1481 ip2 = ipnode(mkbinode(ASSIGN, q->n_left, tcopy(r), t));
1482 DLIST_INSERT_AFTER(ip, ip2, qelem);
1483 q->n_left = r;
1484
1485 p->n_name = tmpstrdup(q->n_name);
1486 if (*p->n_name == '=')
1487 p->n_name++;
1488 }
1489
1490 /*
1491 * Ensure that a node is correct for the destination.
1492 */
1493 static void
1494 ltypify(NODE *p, void *arg)
1495 {
1496 struct interpass *ip = arg;
1497 struct interpass *ip2;
1498 TWORD t = p->n_left->n_type;
1499 NODE *q, *r;
1500 int cw, ooff, ww;
1501 char *c;
1502
1503 again:
1504 if (myxasm(ip, p))
1505 return; /* handled by target-specific code */
1506
1507 cw = xasmcode(p->n_name);
1508 switch (ww = XASMVAL(cw)) {
1509 case 'p':
1510 /* pointer */
1511 /* just make register of it */
1512 p->n_name = tmpstrdup(p->n_name);
1513 c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
1514 *c = 'r';
1515 /* FALLTHROUGH */
1516 case 'g': /* general; any operand */
1517 if (ww == 'g' && p->n_left->n_op == ICON) {
1518 /* should only be input */
1519 p->n_name = "i";
1520 break;
1521 }
1522 /* FALLTHROUGH */
1523 case 'r': /* general reg */
1524 /* set register class */
1525 p->n_label = gclass(p->n_left->n_type);
1526 if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
1527 break;
1528 q = p->n_left;
1529 r = (cw & XASMINOUT ? tcopy(q) : q);
1530 p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
1531 if ((cw & XASMASG) == 0) {
1532 ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), r, t));
1533 DLIST_INSERT_BEFORE(ip, ip2, qelem);
1534 }
1535 if (cw & (XASMASG|XASMINOUT)) {
1536 /* output parameter */
1537 ip2 = ipnode(mkbinode(ASSIGN, q, tcopy(p->n_left), t));
1538 DLIST_INSERT_AFTER(ip, ip2, qelem);
1539 }
1540 break;
1541
1542 case '0': case '1': case '2': case '3': case '4':
1543 case '5': case '6': case '7': case '8': case '9':
1544 break;
1545
1546 case 'm': /* memory operand */
1547 /* store and reload value */
1548 q = p->n_left;
1549 if (optype(q->n_op) == LTYPE) {
1550 if (q->n_op == TEMP) {
1551 ooff = freetemp(szty(t));
1552 cvtemps(ip, q->n_rval, ooff);
1553 } else if (q->n_op == REG)
1554 comperr("xasm m and reg");
1555 } else if (q->n_op == UMUL &&
1556 (q->n_left->n_op != TEMP && q->n_left->n_op != REG)) {
1557 t = q->n_left->n_type;
1558 ooff = p2env.epp->ip_tmpnum++;
1559 ip2 = ipnode(mkbinode(ASSIGN,
1560 mklnode(TEMP, 0, ooff, t), q->n_left, t));
1561 q->n_left = mklnode(TEMP, 0, ooff, t);
1562 DLIST_INSERT_BEFORE(ip, ip2, qelem);
1563 }
1564 break;
1565
1566 case 'i': /* immediate constant */
1567 case 'n': /* numeric constant */
1568 if (p->n_left->n_op == ICON)
1569 break;
1570 p->n_name = tmpstrdup(p->n_name);
1571 c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
1572 if (c[1]) {
1573 c[0] = c[1], c[1] = 0;
1574 goto again;
1575 } else
1576 uerror("constant required");
1577 break;
1578
1579 default:
1580 uerror("unsupported xasm option string '%s'", p->n_name);
1581 }
1582 }
1583
1584 /* Extended assembler hacks */
1585 static void
1586 fixxasm(struct p2env *p2e)
1587 {
1588 struct interpass *pole = &p2e->ipole;
1589 struct interpass *ip;
1590 NODE *p;
1591
1592 DLIST_FOREACH(ip, pole, qelem) {
1593 if (ip->type != IP_NODE || ip->ip_node->n_op != XASM)
1594 continue;
1595 thisline = ip->lineno;
1596 p = ip->ip_node->n_left;
1597
1598 if (p->n_op == ICON && p->n_type == STRTY)
1599 continue;
1600
1601 /* replace numeric redirections with its underlying type */
1602 flist(p, delnums, ip);
1603
1604 /*
1605 * Ensure that the arg nodes can be directly addressable
1606 * We decide that everything shall be LTYPE here.
1607 */
1608 flist(p, ltypify, ip);
1609 }
1610 }
1611
1612 /*
1613 * Extract codeword from xasm string */
1614 int
1615 xasmcode(char *s)
1616 {
1617 int cw = 0, nm = 0;
1618
1619 while (*s) {
1620 switch ((int)*s) {
1621 case '=': cw |= XASMASG; break;
1622 case '&': cw |= XASMCONSTR; break;
1623 case '+': cw |= XASMINOUT; break;
1624 case '%': break;
1625 default:
1626 if ((*s >= 'a' && *s <= 'z') ||
1627 (*s >= 'A' && *s <= 'Z') ||
1628 (*s >= '0' && *s <= '9')) {
1629 if (nm == 0)
1630 cw |= *s;
1631 else
1632 cw |= (*s << ((nm + 1) * 8));
1633 nm++;
1634 break;
1635 }
1636 uerror("bad xasm constraint %c", *s);
1637 }
1638 s++;
1639 }
1640 return cw;
1641 }
1642
1643 static int xasnum, xoffnum;
1644
1645 static void
1646 xconv(NODE *p, void *arg)
1647 {
1648 if (p->n_op != TEMP || p->n_rval != xasnum)
1649 return;
1650 storemod(p, xoffnum, FPREG); /* XXX */
1651 }
1652
1653 /*
1654 * Convert nodes of type TEMP to op with lval off.
1655 */
1656 static void
1657 cvtemps(struct interpass *ipl, int tnum, int off)
1658 {
1659 struct interpass *ip;
1660
1661 xasnum = tnum;
1662 xoffnum = off;
1663
1664 DLIST_FOREACH(ip, ipl, qelem)
1665 if (ip->type == IP_NODE)
1666 walkf(ip->ip_node, xconv, 0);
1667 walkf(ipl->ip_node, xconv, 0);
1668 }
1669