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