source: mainline/uspace/app/pcc/mip/reader.c@ 12831ed7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 12831ed7 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

  • Property mode set to 100644
File size: 36.0 KB
Line 
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.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 *
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.
48 *
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.
61 */
62
63/*
64 * Everything is entered via pass2_compile(). No functions are
65 * allowed to recurse back into pass2_compile().
66 */
67
68# include "pass2.h"
69
70#include <string.h>
71#include <stdarg.h>
72#include <stdlib.h>
73
74/* some storage declarations */
75int nrecur;
76int lflag;
77int x2debug, udebug, odebug;
78int thisline;
79int fregs;
80int p2autooff, p2maxautooff;
81
82NODE *nodepole;
83FILE *prfil;
84struct interpass prepole;
85
86void saveip(struct interpass *ip);
87void deltemp(NODE *p, void *);
88static void cvtemps(struct interpass *ipole, int op, int off);
89NODE *store(NODE *);
90static void fixxasm(struct p2env *);
91
92static void gencode(NODE *p, int cookie);
93static void genxasm(NODE *p);
94
95struct p2env p2env;
96
97int
98getlab2(void)
99{
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;
108}
109
110#ifdef PCC_DEBUG
111static int *lbldef, *lbluse;
112static void
113cktree(NODE *p, void *arg)
114{
115 int i;
116
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;
129 }
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;
142 }
143}
144
145/*
146 * Check that the trees are in a suitable state for pass2.
147 */
148static void
149sanitychecks(struct p2env *p2e)
150{
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));
158
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;
166 }
167 if (ip->type == IP_NODE)
168 walkf(ip->ip_node, cktree, 0);
169 }
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);
174
175#ifdef notyet
176 TMPFREE();
177#endif
178}
179#endif
180
181/*
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.
185 */
186static int
187stkarg(int tnr, int *soff)
188{
189 struct p2env *p2e = &p2env;
190 struct interpass *ip;
191 NODE *p;
192
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);
196
197 ip = DLIST_NEXT(ip, qelem); /* first NODE */
198
199 for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
200 if (ip->type != IP_NODE)
201 continue;
202
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 */
212
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;
230 }
231 return 0;
232}
233
234/*
235 * See if an ADDROF is somewhere inside the expression tree.
236 * If so, fill in the offset table.
237 */
238static void
239findaof(NODE *p, void *arg)
240{
241 int *aof = arg;
242 int tnr;
243
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)));
252}
253
254/*
255 * Check if a node has side effects.
256 */
257static int
258isuseless(NODE *n)
259{
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;
279 }
280}
281
282/*
283 * Delete statements with no meaning (like a+b; or 513.4;)
284 */
285NODE *
286deluseless(NODE *p)
287{
288 struct interpass *ip;
289 NODE *l, *r;
290
291 if (optype(p->n_op) == LTYPE) {
292 nfree(p);
293 return NULL;
294 }
295 if (isuseless(p) == 0)
296 return p;
297
298 if (optype(p->n_op) == UTYPE) {
299 l = p->n_left;
300 nfree(p);
301 return deluseless(l);
302 }
303
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;
317}
318
319/*
320 * Receives interpass structs from pass1.
321 */
322void
323pass2_compile(struct interpass *ip)
324{
325 void deljumps(struct p2env *);
326 struct p2env *p2e = &p2env;
327 int *addrp;
328 MARK mark;
329
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);
334 }
335 DLIST_INSERT_BEFORE(&p2e->ipole, ip, qelem);
336 if (ip->type != IP_EPILOG)
337 return;
338
339#ifdef PCC_DEBUG
340 if (e2debug) {
341 printf("Entering pass2\n");
342 printip(&p2e->ipole);
343 }
344#endif
345
346 p2e->epp = (struct interpass_prolog *)DLIST_PREV(&p2e->ipole, qelem);
347 p2maxautooff = p2autooff = p2e->epp->ipp_autos;
348
349#ifdef PCC_DEBUG
350 sanitychecks(p2e);
351#endif
352 myreader(&p2e->ipole); /* local massage of input */
353
354 /*
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.
360 */
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);
372 }
373 }
374 DLIST_FOREACH(ip, &p2e->ipole, qelem)
375 if (ip->type == IP_NODE)
376 walkf(ip->ip_node, deltemp, addrp);
377 markfree(&mark);
378
379#ifdef PCC_DEBUG
380 if (e2debug) {
381 printf("Efter ADDROF/TEMP\n");
382 printip(&p2e->ipole);
383 }
384#endif
385
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;
395
396 tipp = DLIST_NEXT(&prepole, qelem);
397 DLIST_REMOVE(tipp, qelem);
398 DLIST_INSERT_BEFORE(ip, tipp, qelem);
399 }
400 }
401
402 fixxasm(p2e); /* setup for extended asm */
403
404 optimize(p2e);
405 ngenregs(p2e);
406
407 if (xssaflag && xtemps && xdeljumps)
408 deljumps(p2e);
409
410 DLIST_FOREACH(ip, &p2e->ipole, qelem)
411 emit(ip);
412}
413
414void
415emit(struct interpass *ip)
416{
417 NODE *p, *r;
418 struct optab *op;
419 int o;
420
421 switch (ip->type) {
422 case IP_NODE:
423 p = ip->ip_node;
424
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);
430 }
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;
441 }
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);
448 }
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 */
459 }
460
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);
478 }
479}
480
481#ifdef PCC_DEBUG
482char *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",
498 0,
499};
500
501/*
502 * print a nice-looking description of cookie
503 */
504char *
505prcook(int cookie)
506{
507 static char buf[50];
508 int i, flag;
509
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;
521 }
522 }
523
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));
532 }
533 }
534 return buf;
535}
536#endif
537
538int
539geninsn(NODE *p, int cookie)
540{
541 NODE *p1, *p2;
542 int q, o, rv = 0;
543
544#ifdef PCC_DEBUG
545 if (odebug) {
546 printf("geninsn(%p, %s)\n", p, prcook(cookie));
547 fwalk(p, e2print, 0);
548 }
549#endif
550
551 q = cookie & QUIET;
552 cookie &= ~QUIET; /* XXX - should not be necessary */
553
554again: 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
576 }
577 rv = relops(p);
578 break;
579
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;
592
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;
602
603 case UMUL: /* May turn into an OREG */
604 rv = findumul(p, cookie);
605 break;
606
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;
615
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;
637
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;
645
646 case FORCE: /* XXX needed? */
647 (void)geninsn(p->n_left, INREGS);
648 p->n_su = 0; /* su calculations traverse left */
649 break;
650
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? */
656
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;
663
664 default:
665 comperr("geninsn: bad op %s, node %p", opst[o], p);
666 }
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);
675 }
676#endif
677 return rv;
678}
679
680/*
681 * Store a given subtree in a temporary location.
682 * Return an OREG node where it is located.
683 */
684NODE *
685store(NODE *p)
686{
687 extern struct interpass *storesave;
688 struct interpass *ip;
689 NODE *q, *r;
690 int s;
691
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));
696
697 storesave = ip;
698 return r;
699}
700
701#ifdef PCC_DEBUG
702#define CDEBUG(x) if (c2debug) printf x
703#else
704#define CDEBUG(x)
705#endif
706
707/*
708 * Do a register-register move if necessary.
709 */
710static void
711ckmove(NODE *p, NODE *q)
712{
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);
721}
722
723/*
724 * Rewrite node to register after instruction emit.
725 */
726static void
727rewrite(NODE *p, int dorewrite, int cookie)
728{
729 NODE *l, *r;
730 int o;
731
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 = "";
738
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)
744 ;
745 else if (TL(l) && (DECRA(l->n_reg, 0) == reg))
746 ;
747 else if (TL(r) && (DECRA(r->n_reg, 0) == reg))
748 ;
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
758 }
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);
768}
769
770#ifndef XASM_TARGARG
771#define XASM_TARGARG(x,y) 0
772#endif
773
774/*
775 * printout extended assembler.
776 */
777void
778genxasm(NODE *p)
779{
780 NODE *q, **nary;
781 int n = 1, o = 0;
782 char *w;
783
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;
792 }
793 gencode(q->n_left, INREGS);
794 nary[--o] = q;
795 } else
796 nary = 0;
797
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);
814 }
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++;
824 }
825 putchar('\n');
826}
827
828void
829gencode(NODE *p, int cookie)
830{
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
837
838 l = p->n_left;
839 r = p->n_right;
840
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;
849 }
850
851 CDEBUG(("gencode: node %p\n", p));
852
853 if (p->n_op == REG && DECRA(p->n_reg, 0) == p->n_rval)
854 return; /* meaningless move to itself */
855
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 */
864 }
865
866 if (o == BITYPE && (p->n_su & DORIGHT)) {
867 gencode(r, INREGS);
868 if (q->rewrite & RRIGHT)
869 ckmove(p, r);
870 }
871 if (o != LTYPE) {
872 gencode(l, INREGS);
873#ifdef FINDMOPS
874 if (ismops)
875 ;
876 else
877#endif
878 if (q->rewrite & RLEFT)
879 ckmove(p, l);
880 }
881 if (o == BITYPE && !(p->n_su & DORIGHT)) {
882 gencode(r, INREGS);
883 if (q->rewrite & RRIGHT)
884 ckmove(p, r);
885 }
886
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;
895 }
896 }
897#endif
898
899 canon(p);
900
901 if (q->needs & NSPECIAL) {
902 int rr = rspecial(q, NRIGHT);
903 int lr = rspecial(q, NLEFT);
904
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;
915 }
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;
922 }
923 if (rr >= 0 && lr >= 0 && (l->n_reg == rr || r->n_reg == lr))
924 comperr("gencode: cross-reg-move");
925 }
926
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;
935 }
936
937 CDEBUG(("emitting node %p\n", p));
938 if (TBLIDX(p->n_su) == 0)
939 return;
940
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);
954
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);
958 }
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);
963 }
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);
977 }
978 }
979#endif
980 rewrite(p, q->rewrite, cookie);
981}
982
983int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ; /* negatives of relationals */
984size_t negrelsize = sizeof negrel / sizeof negrel[0];
985
986#ifdef PCC_DEBUG
987#undef PRTABLE
988void
989e2print(NODE *p, int down, int *a, int *b)
990{
991#ifdef PRTABLE
992 extern int tablesize;
993#endif
994
995 prfil = stdout;
996 *a = *b = down+1;
997 while( down >= 2 ){
998 fprintf(prfil, "\t");
999 down -= 2;
1000 }
1001 if( down-- ) fprintf(prfil, " " );
1002
1003
1004 fprintf(prfil, "%p) %s", p, opst[p->n_op] );
1005 switch( p->n_op ) { /* special cases */
1006
1007 case FLD:
1008 fprintf(prfil, " sz=%d, shift=%d",
1009 UPKFSZ(p->n_rval), UPKFOFF(p->n_rval));
1010 break;
1011
1012 case REG:
1013 fprintf(prfil, " %s", rnames[p->n_rval] );
1014 break;
1015
1016 case TEMP:
1017 fprintf(prfil, " %d", regno(p));
1018 break;
1019
1020 case XASM:
1021 case XARG:
1022 fprintf(prfil, " '%s'", p->n_name);
1023 break;
1024
1025 case ICON:
1026 case NAME:
1027 case OREG:
1028 fprintf(prfil, " " );
1029 adrput(prfil, p );
1030 break;
1031
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;
1039 }
1040
1041 fprintf(prfil, ", " );
1042 tprint(prfil, p->n_type, p->n_qual);
1043 fprintf(prfil, ", " );
1044
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
1053 "",
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" : "");
1058}
1059#endif
1060
1061#ifndef FIELDOPS
1062/*
1063 * do this if there is no special hardware support for fields
1064 */
1065static void
1066ffld(NODE *p, int down, int *down1, int *down2 )
1067{
1068 /*
1069 * look for fields that are not in an lvalue context,
1070 * and rewrite them...
1071 */
1072 NODE *shp;
1073 int s, o, v, ty;
1074
1075 *down1 = asgop( p->n_op );
1076 *down2 = 0;
1077
1078 if( !down && p->n_op == FLD ){ /* rewrite the node */
1079
1080 if( !rewfld(p) ) return;
1081
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 */
1091
1092 if (ISUNSIGNED(ty)) {
1093
1094 p->n_left->n_type = ty;
1095 p->n_op = AND;
1096 p->n_right = mklnode(ICON, ((CONSZ)1 << s)-1, 0, ty);
1097
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! */
1104 }
1105 } else {
1106 int mz;
1107
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)
1113 }
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);
1121 }
1122 }
1123}
1124#endif
1125
1126/*
1127 * change left TEMPs into OREGs
1128 */
1129void
1130deltemp(NODE *p, void *arg)
1131{
1132 int *aor = arg;
1133 NODE *l, *r;
1134
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)));
1140 }
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);
1156 }
1157}
1158
1159/*
1160 * for pointer/integer arithmetic, set pointer at left node
1161 */
1162static void
1163setleft(NODE *p, void *arg)
1164{
1165 NODE *q;
1166
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;
1174 }
1175}
1176
1177/* It is OK to have these as externals */
1178static int oregr;
1179static CONSZ oregtemp;
1180static char *oregcp;
1181/*
1182 * look for situations where we can turn * into OREG
1183 * If sharp then do not allow temps.
1184 */
1185int
1186oregok(NODE *p, int sharp)
1187{
1188
1189 NODE *q;
1190 NODE *ql, *qr;
1191 int r;
1192 CONSZ temp;
1193 char *cp;
1194
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;
1205 }
1206
1207 if (q->n_op != PLUS && q->n_op != MINUS)
1208 return 0;
1209 ql = q->n_left;
1210 qr = q->n_right;
1211
1212#ifdef R2REGS
1213
1214 /* look for doubly indexed expressions */
1215 /* XXX - fix checks */
1216
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;
1225 }
1226 }
1227
1228
1229#endif
1230
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))) {
1241
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;
1250
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;
1258 }
1259 return 0;
1260}
1261
1262static void
1263ormake(NODE *p)
1264{
1265 NODE *q = p->n_left;
1266
1267 p->n_op = OREG;
1268 p->n_rval = oregr;
1269 p->n_lval = oregtemp;
1270 p->n_name = oregcp;
1271 tfree(q);
1272}
1273
1274/*
1275 * look for situations where we can turn * into OREG
1276 */
1277void
1278oreg2(NODE *p, void *arg)
1279{
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);
1286}
1287
1288void
1289canon(p) NODE *p; {
1290 /* put p in canonical form */
1291
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) */
1298
1299}
1300
1301void
1302comperr(char *str, ...)
1303{
1304 extern char *ftitle;
1305 va_list ap;
1306
1307 if (nerrors) {
1308 fprintf(stderr,
1309 "cannot recover from earlier errors: goodbye!\n");
1310 exit(1);
1311 }
1312
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;
1319
1320#ifdef PCC_DEBUG
1321 if (nodepole && nodepole->n_op != FREE)
1322 fwalk(nodepole, e2print, 0);
1323#endif
1324 exit(1);
1325}
1326
1327/*
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.
1333 */
1334int
1335freetemp(int k)
1336{
1337#ifndef BACKTEMP
1338 int t;
1339
1340 if (k > 1)
1341 SETOFF(p2autooff, ALDOUBLE/ALCHAR);
1342
1343 t = p2autooff;
1344 p2autooff += k*(SZINT/SZCHAR);
1345 if (p2autooff > p2maxautooff)
1346 p2maxautooff = p2autooff;
1347 return (t);
1348
1349#else
1350 p2autooff += k*(SZINT/SZCHAR);
1351 if (k > 1)
1352 SETOFF(p2autooff, ALDOUBLE/ALCHAR);
1353
1354 if (p2autooff > p2maxautooff)
1355 p2maxautooff = p2autooff;
1356 return( -p2autooff );
1357#endif
1358 }
1359
1360NODE *
1361mklnode(int op, CONSZ lval, int rval, TWORD type)
1362{
1363 NODE *p = talloc();
1364
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;
1375}
1376
1377NODE *
1378mkbinode(int op, NODE *left, NODE *right, TWORD type)
1379{
1380 NODE *p = talloc();
1381
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;
1392}
1393
1394NODE *
1395mkunode(int op, NODE *left, int rval, TWORD type)
1396{
1397 NODE *p = talloc();
1398
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;
1409}
1410
1411struct interpass *
1412ipnode(NODE *p)
1413{
1414 struct interpass *ip = tmpalloc(sizeof(struct interpass));
1415
1416 ip->ip_node = p;
1417 ip->type = IP_NODE;
1418 ip->lineno = thisline;
1419 return ip;
1420}
1421
1422int
1423rspecial(struct optab *q, int what)
1424{
1425 struct rspecial *r = nspecial(q);
1426 while (r->op) {
1427 if (r->op == what)
1428 return r->num;
1429 r++;
1430 }
1431 return -1;
1432}
1433
1434#ifndef XASM_NUMCONV
1435#define XASM_NUMCONV(x,y,z) 0
1436#endif
1437
1438/*
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.
1442 */
1443static void
1444delnums(NODE *p, void *arg)
1445{
1446 struct interpass *ip = arg, *ip2;
1447 NODE *r = ip->ip_node->n_left;
1448 NODE *q;
1449 TWORD t;
1450 int cnt, num;
1451
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");
1456
1457 /* target may have opinions whether to do this conversion */
1458 if (XASM_NUMCONV(ip, p, q))
1459 return;
1460
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++;
1464
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;
1471
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;
1478
1479 p->n_name = tmpstrdup(q->n_name);
1480 if (*p->n_name == '=')
1481 p->n_name++;
1482}
1483
1484/*
1485 * Ensure that a node is correct for the destination.
1486 */
1487static void
1488ltypify(NODE *p, void *arg)
1489{
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;
1496
1497again:
1498 if (myxasm(ip, p))
1499 return; /* handled by target-specific code */
1500
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;
1515 }
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);
1527 }
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);
1532 }
1533 break;
1534
1535 case '0': case '1': case '2': case '3': case '4':
1536 case '5': case '6': case '7': case '8': case '9':
1537 break;
1538
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);
1556 }
1557 break;
1558
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;
1571
1572 default:
1573 uerror("unsupported xasm option string '%s'", p->n_name);
1574 }
1575}
1576
1577/* Extended assembler hacks */
1578static void
1579fixxasm(struct p2env *p2e)
1580{
1581 struct interpass *pole = &p2e->ipole;
1582 struct interpass *ip;
1583 NODE *p;
1584
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;
1590
1591 if (p->n_op == ICON && p->n_type == STRTY)
1592 continue;
1593
1594 /* replace numeric redirections with its underlying type */
1595 flist(p, delnums, ip);
1596
1597 /*
1598 * Ensure that the arg nodes can be directly addressable
1599 * We decide that everything shall be LTYPE here.
1600 */
1601 flist(p, ltypify, ip);
1602 }
1603}
1604
1605/*
1606 * Extract codeword from xasm string */
1607int
1608xasmcode(char *s)
1609{
1610 int cw = 0, nm = 0;
1611
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;
1628 }
1629 uerror("bad xasm constraint %c", *s);
1630 }
1631 s++;
1632 }
1633 return cw;
1634}
1635
1636static int xasnum, xoffnum;
1637
1638static void
1639xconv(NODE *p, void *arg)
1640{
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;
1646}
1647
1648/*
1649 * Convert nodes of type TEMP to op with lval off.
1650 */
1651static void
1652cvtemps(struct interpass *ipl, int tnum, int off)
1653{
1654 struct interpass *ip;
1655
1656 xasnum = tnum;
1657 xoffnum = off;
1658
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);
1663}
Note: See TracBrowser for help on using the repository browser.