1 /*        Id: regs.c,v 1.247 2015/11/17 19:19:40 ragge Exp  */
2 /*        $NetBSD: regs.c,v 1.1.1.7 2016/02/09 20:29:19 plunky Exp $  */
3 /*
4  * Copyright (c) 2005 Anders Magnusson (ragge@ludd.luth.se).
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "pass2.h"
31 #include <string.h>
32 #ifdef HAVE_STRINGS_H
33 #include <strings.h>
34 #endif
35 #ifdef HAVE_STDINT_H
36 #include <stdint.h>
37 #endif
38 #include <stdlib.h>
39 
40 #define   MAXLOOP   20 /* Max number of allocation loops XXX 3 should be enough */
41 
42 #ifndef MAX
43 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
44 #endif
45 
46 /*
47  * New-style register allocator using graph coloring.
48  * The design is based on the George and Appel paper
49  * "Iterated Register Coalescing", ACM Transactions, No 3, May 1996.
50  */
51 
52 #define   BITALLOC(ptr,all,sz) { \
53           int sz__s = BIT2BYTE(sz); ptr = all(sz__s); memset(ptr, 0, sz__s); }
54 
55 #undef COMPERR_PERM_MOVE
56 #ifdef PCC_DEBUG
57 #define   RDEBUG(x) if (r2debug) printf x
58 #define   RRDEBUG(x)          if (r2debug > 1) printf x
59 #define   RPRINTIP(x)         if (r2debug) printip(x)
60 #define   RDEBUGX(x)                    x
61 #define   UDEBUG(x) if (u2debug) printf x
62 #define BDEBUG(x)   if (b2debug) printf x
63 #define BBDEBUG(x)  if (b2debug > 1) printf x
64 #else
65 #define   RDEBUG(x)
66 #define   RRDEBUG(x)
67 #define   RPRINTIP(x)
68 #define   RDEBUGX(x)
69 #define UDEBUG(x)
70 #define BDEBUG(x)
71 #define BBDEBUG(x)
72 #endif
73 
74 #define   VALIDREG(p)         (p->n_op == REG && TESTBIT(validregs, regno(p)))
75 
76 /*
77  * Data structure overview for this implementation of graph coloring:
78  *
79  * Each temporary (called "node") is described by the type REGW.
80  * Space for all nodes is allocated initially as an array, so
81  * the nodes can be can be referenced both by the node number and
82  * by pointer.
83  *
84  * All moves are represented by the type REGM, allocated when needed.
85  *
86  * The "live" set used during graph building is represented by a bitset.
87  *
88  * Interference edges are represented by struct AdjSet, hashed and linked
89  * from index into the edgehash array.
90  *
91  * A mapping from each node to the moves it is assiciated with is
92  * maintained by an array moveList which for each node number has a linked
93  * list of MOVL types, each pointing to a REGM.
94  *
95  * Adjacency list is maintained by the adjList array, indexed by the
96  * node number. Each adjList entry points to an ADJL type, and is a
97  * single-linked list for all adjacent nodes.
98  *
99  * degree, alias and color are integer arrays indexed by node number.
100  */
101 
102 /*
103  * linked list of adjacent nodes.
104  */
105 typedef struct regw3 {
106           struct regw3 *r_next;
107           struct regw *a_temp;
108 } ADJL;
109 
110 /*
111  * Structure describing a move.
112  */
113 typedef struct regm {
114           DLIST_ENTRY(regm) link;
115           struct regw *src, *dst;
116           int queue;
117 } REGM;
118 
119 typedef struct movlink {
120           struct movlink *next;
121           REGM *regm;
122 } MOVL;
123 
124 /*
125  * Structure describing a temporary.
126  */
127 typedef struct regw {
128           DLIST_ENTRY(regw) link;
129           ADJL *r_adjList;    /* linked list of adjacent nodes */
130           int r_class;                  /* this nodes class */
131           int r_nclass[NUMCLASS+1];     /* count of adjacent classes */
132           struct regw *r_alias;                   /* aliased temporary */
133           int r_color;                  /* final node color */
134           struct regw *r_onlist;        /* which work list this node belongs to */
135           MOVL *r_moveList;   /* moves associated with this node */
136           int nodnum;                   /* Human-readable node number */
137 } REGW;
138 
139 /*
140  * Worklists, a node is always on exactly one of these lists.
141  */
142 static REGW precolored, simplifyWorklist, freezeWorklist, spillWorklist,
143           spilledNodes, coalescedNodes, coloredNodes, selectStack;
144 static REGW initial, *nblock;
145 static void insnwalk(NODE *p);
146 #ifdef PCC_DEBUG
147 int use_regw;
148 #endif
149 int nodnum = 100;
150 int ntsz, stktemp;
151 #define   SETNUM(x) (x)->nodnum = nodnum++
152 #define   ASGNUM(x) (x)->nodnum
153 
154 #define   ALLNEEDS (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT)
155 
156 /* XXX */
157 REGW *ablock;
158 
159 static int tempmin, tempmax, basetemp, xbits;
160 /*
161  * nsavregs is an array that matches the permregs array.
162  * Each entry in the array may have the values:
163  * 0      : register coalesced, just ignore.
164  * 1      : save register on stack
165  * If the entry is 0 but the resulting color differs from the
166  * corresponding permregs index, add moves.
167  * XXX - should be a bitfield!
168  */
169 static int *nsavregs, *ndontregs;
170 
171 /*
172  * Return the REGW struct for a temporary.
173  * If first time touched, enter into list for existing vars.
174  * Only called from sucomp().
175  */
176 static REGW *
newblock(NODE * p)177 newblock(NODE *p)
178 {
179           REGW *nb;
180 
181 #ifdef PCC_DEBUG
182           if (regno(p) < tempmin || regno(p) >= tempmax)
183                     comperr("temp %p(%d) outside limits (%d-%d)",
184                         p, regno(p), tempmin, tempmax);
185 #endif
186           nb = &nblock[regno(p)];
187           if (nb->link.q_forw == 0) {
188                     DLIST_INSERT_AFTER(&initial, nb, link);
189 #ifdef PCC_DEBUG
190                     ASGNUM(nb) = regno(p);
191                     RDEBUG(("Adding longtime %d for tmp %d\n",
192                         nb->nodnum, regno(p)));
193 #endif
194           }
195           if (nb->r_class == 0)
196                     nb->r_class = gclass(p->n_type);
197 #ifdef PCC_DEBUG
198           RDEBUG(("newblock: p %p, node %d class %d\n",
199               p, nb->nodnum, nb->r_class));
200 #endif
201           return nb;
202 }
203 
204 /*
205  * Count the number of registers needed to evaluate a tree.
206  * This is only done to find the evaluation order of the tree.
207  * While here, assign temp numbers to the registers that will
208  * be needed when the tree is evaluated.
209  *
210  * While traversing the tree, assign REGW nodes to the registers
211  * used by all instructions:
212  *        - n_regw[0] is always set to the outgoing node. If the
213  *          instruction is 2-op (addl r0,r1) then an implicit move
214  *          is inserted just before the left (clobbered) operand.
215  *        - if the instruction has needs then REGW nodes are
216  *          allocated as n_regw[1] etc.
217  */
218 int
nsucomp(NODE * p)219 nsucomp(NODE *p)
220 {
221           struct optab *q;
222           int left, right;
223           int nreg, need, i, nxreg, o;
224           int nareg, nbreg, ncreg, ndreg, nereg, nfreg, ngreg;
225           REGW *w;
226 
227           o = optype(p->n_op);
228 
229           UDEBUG(("entering nsucomp, node %p\n", p));
230 
231           if (TBLIDX(p->n_su) == 0) {
232                     int a = 0, b;
233 
234                     p->n_regw = NULL;
235                     if (o == LTYPE ) {
236                               if (p->n_op == TEMP) {
237                                         p->n_regw = newblock(p);
238                                         a = 1;
239                               } else if (p->n_op == REG)
240                                         p->n_regw = &ablock[regno(p)];
241                     } else
242                               a = nsucomp(p->n_left);
243                     if (o == BITYPE) {
244                               b = nsucomp(p->n_right);
245                               if (b > a)
246                                         p->n_su |= DORIGHT;
247                               a = MAX(a, b);
248                     }
249                     return a;
250           }
251 
252           q = &table[TBLIDX(p->n_su)];
253 
254 #define   NNEEDS(a,b) ((q->needs & a)/b)
255           for (i = (q->needs & NACOUNT), nareg = 0; i; i -= NAREG)
256                     nareg++;
257           for (i = (q->needs & NBCOUNT), nbreg = 0; i; i -= NBREG)
258                     nbreg++;
259           for (i = (q->needs & NCCOUNT), ncreg = 0; i; i -= NCREG)
260                     ncreg++;
261           for (i = (q->needs & NDCOUNT), ndreg = 0; i; i -= NDREG)
262                     ndreg++;
263           for (i = (q->needs & NECOUNT), nereg = 0; i; i -= NEREG)
264                     nereg++;
265           for (i = (q->needs & NFCOUNT), nfreg = 0; i; i -= NFREG)
266                     nfreg++;
267           for (i = (q->needs & NGCOUNT), ngreg = 0; i; i -= NGREG)
268                     ngreg++;
269 
270           if (ntsz < NNEEDS(NTMASK, NTEMP) * szty(p->n_type))
271                     ntsz = NNEEDS(NTMASK, NTEMP) * szty(p->n_type);
272 
273           nxreg = nareg + nbreg + ncreg + ndreg + nereg + nfreg + ngreg;
274           nreg = nxreg;
275           if (callop(p->n_op))
276                     nreg = MAX(fregs, nreg);
277 
278           if (o == BITYPE) {
279                     right = nsucomp(p->n_right);
280           } else
281                     right = 0;
282 
283           if (o != LTYPE)
284                     left = nsucomp(p->n_left);
285           else
286                     left = 0;
287 
288           UDEBUG(("node %p left %d right %d\n", p, left, right));
289 
290           if (o == BITYPE) {
291                     /* Two children */
292                     if (right == left) {
293                               need = left + MAX(nreg, 1);
294                     } else {
295                               need = MAX(right, left);
296                               need = MAX(need, nreg);
297                     }
298                     if (setorder(p) == 0) {
299                               /* XXX - should take care of overlapping needs */
300                               if (right > left) {
301                                         p->n_su |= DORIGHT;
302                               } else if (right == left) {
303 #if 0
304           /* XXX - need something more clever when large left trees */
305                                         /* A favor to 2-operand architectures */
306                                         if ((q->rewrite & RRIGHT) == 0)
307                                                   p->n_su |= DORIGHT;
308 #endif
309                               }
310                     }
311           } else if (o != LTYPE) {
312                     /* One child */
313                     need = MAX(right, left) + nreg;
314           } else
315                     need = nreg;
316 
317           if (p->n_op == TEMP)
318                     (void)newblock(p);
319 
320           if (TCLASS(p->n_su) == 0 && nxreg == 0) {
321                     UDEBUG(("node %p no class\n", p));
322                     p->n_regw = NULL; /* may be set earlier */
323                     return need;
324           }
325 
326 #ifdef PCC_DEBUG
327 #define   ADCL(n, cl)         \
328           for (i = 0; i < n; i++, w++) {          w->r_class = cl; \
329                     DLIST_INSERT_BEFORE(&initial, w, link);  SETNUM(w); \
330                     UDEBUG(("Adding " #n " %d\n", w->nodnum)); \
331           }
332 #else
333 #define   ADCL(n, cl)         \
334           for (i = 0; i < n; i++, w++) {          w->r_class = cl; \
335                     DLIST_INSERT_BEFORE(&initial, w, link);  SETNUM(w); \
336           }
337 #endif
338 
339           UDEBUG(("node %p numregs %d\n", p, nxreg+1));
340           w = p->n_regw = tmpalloc(sizeof(REGW) * (nxreg+1));
341           memset(w, 0, sizeof(REGW) * (nxreg+1));
342 
343           w->r_class = TCLASS(p->n_su);
344           if (w->r_class == 0)
345                     w->r_class = gclass(p->n_type);
346           w->r_nclass[0] = o == LTYPE; /* XXX store leaf info here */
347           SETNUM(w);
348           if (w->r_class)
349                     DLIST_INSERT_BEFORE(&initial, w, link);
350 #ifdef PCC_DEBUG
351           UDEBUG(("Adding short %d class %d\n", w->nodnum, w->r_class));
352 #endif
353           w++;
354           ADCL(nareg, CLASSA);
355           ADCL(nbreg, CLASSB);
356           ADCL(ncreg, CLASSC);
357           ADCL(ndreg, CLASSD);
358           ADCL(nereg, CLASSE);
359           ADCL(nfreg, CLASSF);
360           ADCL(ngreg, CLASSG);
361 
362           if (q->rewrite & RESC1) {
363                     w = p->n_regw + 1;
364                     w->r_class = -1;
365                     DLIST_REMOVE(w,link);
366           } else if (q->rewrite & RESC2) {
367                     w = p->n_regw + 2;
368                     w->r_class = -1;
369                     DLIST_REMOVE(w,link);
370           } else if (q->rewrite & RESC3) {
371                     w = p->n_regw + 3;
372                     w->r_class = -1;
373                     DLIST_REMOVE(w,link);
374           }
375 
376           UDEBUG(("node %p return regs %d\n", p, need));
377 
378           return need;
379 }
380 
381 #define   CLASS(x)  (x)->r_class
382 #define   NCLASS(x,c)         (x)->r_nclass[c]
383 #define   ADJLIST(x)          (x)->r_adjList
384 #define   ALIAS(x)  (x)->r_alias
385 #define   ONLIST(x) (x)->r_onlist
386 #define   MOVELIST(x)         (x)->r_moveList
387 #define   COLOR(x)  (x)->r_color
388 
389 static bittype *live;
390 
391 #define   PUSHWLIST(w, l)     DLIST_INSERT_AFTER(&l, w, link); w->r_onlist = &l
392 #define   POPWLIST(l)         popwlist(&l);
393 #define   DELWLIST(w)         DLIST_REMOVE(w, link)
394 #define WLISTEMPTY(h)         DLIST_ISEMPTY(&h,link)
395 #define   PUSHMLIST(w, l, q)  DLIST_INSERT_AFTER(&l, w, link); w->queue = q
396 #define   POPMLIST(l)         popmlist(&l);
397 
398 #define   trivially_colorable(x) \
399           trivially_colorable_p((x)->r_class, (x)->r_nclass)
400 /*
401  * Determine if a node is trivially colorable ("degree < K").
402  * This implementation is a dumb one, without considering speed.
403  */
404 static int
trivially_colorable_p(int c,int * n)405 trivially_colorable_p(int c, int *n)
406 {
407           int r[NUMCLASS+1];
408           int i;
409 
410           for (i = 1; i < NUMCLASS+1; i++)
411                     r[i] = n[i] < regK[i] ? n[i] : regK[i];
412 
413 #if 0
414           /* add the exclusion nodes. */
415           /* XXX can we do someything smart here? */
416           /* worst-case for exclusion nodes are better than the `worst-case' */
417           for (; excl; excl >>= 1)
418                     if (excl & 1)
419                               r[c]++;
420 #endif
421 
422           i = COLORMAP(c, r);
423           if (i < 0 || i > 1)
424                     comperr("trivially_colorable_p");
425           RRDEBUG(("trivially_colorable_p: n[1] %d n[2] %d n[3] %d n[4] "
426               "%d for class %d, triv %d\n", n[1], n[2], n[3], n[4], c, i));
427           return i;
428 }
429 
430 int
ncnt(int needs)431 ncnt(int needs)
432 {
433           int i = 0;
434 
435           while (needs & NACOUNT)
436                     needs -= NAREG, i++;
437           while (needs & NBCOUNT)
438                     needs -= NBREG, i++;
439           while (needs & NCCOUNT)
440                     needs -= NCREG, i++;
441           while (needs & NDCOUNT)
442                     needs -= NDREG, i++;
443           while (needs & NECOUNT)
444                     needs -= NEREG, i++;
445           while (needs & NFCOUNT)
446                     needs -= NFREG, i++;
447           while (needs & NGCOUNT)
448                     needs -= NGREG, i++;
449           return i;
450 }
451 
452 static REGW *
popwlist(REGW * l)453 popwlist(REGW *l)
454 {
455           REGW *w = DLIST_NEXT(l, link);
456 
457           DLIST_REMOVE(w, link);
458           w->r_onlist = NULL;
459           return w;
460 }
461 
462 /*
463  * Move lists, a move node is always on only one list.
464  */
465 static REGM coalescedMoves, constrainedMoves, frozenMoves,
466           worklistMoves, activeMoves;
467 enum { COAL, CONSTR, FROZEN, WLIST, ACTIVE };
468 
469 static REGM *
popmlist(REGM * l)470 popmlist(REGM *l)
471 {
472           REGM *w = DLIST_NEXT(l, link);
473 
474           DLIST_REMOVE(w, link);
475           return w;
476 }
477 
478 /*
479  * About data structures used in liveness analysis:
480  *
481  * The temporaries generated in pass1 are numbered between tempmin and
482  * tempmax.  Temporaries generated in pass2 are numbered above tempmax,
483  * so they are sequentially numbered.
484  *
485  * Bitfields are used for liveness.  Bit arrays are allocated on the
486  * heap for the "live" variable and on the stack for the in, out, gen
487  * and killed variables. Therefore, for a temp number, the bit number must
488  * be biased with tempmin.
489  *
490  * There may be an idea to use a different data structure to store
491  * pass2 allocated temporaries, because they are very sparse.
492  */
493 
494 #ifdef PCC_DEBUG
495 static void
LIVEADD(int x)496 LIVEADD(int x)
497 {
498           RDEBUG(("Liveadd: %d\n", x));
499           if (x >= MAXREGS && (x < tempmin || x >= tempmax))
500                     comperr("LIVEADD: out of range");
501           if (x < MAXREGS) {
502                     BITSET(live, x);
503           } else
504                     BITSET(live, (x-tempmin+MAXREGS));
505 }
506 
507 static void
LIVEDEL(int x)508 LIVEDEL(int x)
509 {
510           RDEBUG(("Livedel: %d\n", x));
511 
512           if (x >= MAXREGS && (x < tempmin || x >= tempmax))
513                     comperr("LIVEDEL: out of range");
514           if (x < MAXREGS) {
515                     BITCLEAR(live, x);
516           } else
517                     BITCLEAR(live, (x-tempmin+MAXREGS));
518 }
519 #else
520 #define LIVEADD(x) \
521           (x >= MAXREGS ? BITSET(live, (x-tempmin+MAXREGS)) : BITSET(live, x))
522 #define LIVEDEL(x) \
523           (x >= MAXREGS ? BITCLEAR(live, (x-tempmin+MAXREGS)) : BITCLEAR(live, x))
524 #endif
525 
526 static struct lives {
527           DLIST_ENTRY(lives) link;
528           REGW *var;
529 } lused, lunused;
530 
531 static void
LIVEADDR(REGW * x)532 LIVEADDR(REGW *x)
533 {
534           struct lives *l;
535 
536 #ifdef PCC_DEBUG
537           RDEBUG(("LIVEADDR: %d\n", x->nodnum));
538           DLIST_FOREACH(l, &lused, link)
539                     if (l->var == x)
540                               return;
541 #if 0
542                               comperr("LIVEADDR: multiple %d", ASGNUM(x));
543 #endif
544 #endif
545           if (!DLIST_ISEMPTY(&lunused, link)) {
546                     l = DLIST_NEXT(&lunused, link);
547                     DLIST_REMOVE(l, link);
548           } else
549                     l = tmpalloc(sizeof(struct lives));
550 
551           l->var = x;
552           DLIST_INSERT_AFTER(&lused, l, link);
553 }
554 
555 static void
LIVEDELR(REGW * x)556 LIVEDELR(REGW *x)
557 {
558           struct lives *l;
559 
560 #ifdef PCC_DEBUG
561           RDEBUG(("LIVEDELR: %d\n", x->nodnum));
562 #endif
563           DLIST_FOREACH(l, &lused, link) {
564                     if (l->var != x)
565                               continue;
566                     DLIST_REMOVE(l, link);
567                     DLIST_INSERT_AFTER(&lunused, l, link);
568                     return;
569           }
570 #if 0
571           comperr("LIVEDELR: %p not found", x);
572 #endif
573 }
574 
575 #define   MOVELISTADD(t, p) movelistadd(t, p)
576 #define WORKLISTMOVEADD(s,d) worklistmoveadd(s,d)
577 
578 static void
movelistadd(REGW * t,REGM * p)579 movelistadd(REGW *t, REGM *p)
580 {
581           MOVL *w = tmpalloc(sizeof(MOVL));
582 
583           w->regm = p;
584           w->next = t->r_moveList;
585           t->r_moveList = w;
586 }
587 
588 static REGM *
worklistmoveadd(REGW * src,REGW * dst)589 worklistmoveadd(REGW *src, REGW *dst)
590 {
591           REGM *w = tmpalloc(sizeof(REGM));
592 
593           DLIST_INSERT_AFTER(&worklistMoves, w, link);
594           w->src = src;
595           w->dst = dst;
596           w->queue = WLIST;
597           return w;
598 }
599 
600 #define   HASHSZ    16384
601 struct AdjSet {
602           struct AdjSet *next;
603           REGW *u, *v;
604 } *edgehash[HASHSZ];
605 
606 /* Check if a node pair is adjacent */
607 static int
adjSet(REGW * u,REGW * v)608 adjSet(REGW *u, REGW *v)
609 {
610           struct AdjSet *w;
611           REGW *t;
612 
613           if (ONLIST(u) == &precolored) {
614                     ADJL *a = ADJLIST(v);
615                     /*
616                      * Check if any of the registers that have edges against v
617                      * alias to u.
618                      */
619                     for (; a; a = a->r_next) {
620                               if (ONLIST(a->a_temp) != &precolored)
621                                         continue;
622                               t = a->a_temp;
623                               if (interferes(t - ablock, u - ablock))
624                                         return 1;
625                     }
626           }
627 
628           w = edgehash[(u->nodnum+v->nodnum)& (HASHSZ-1)];
629 
630           for (; w; w = w->next) {
631                     if ((u == w->u && v == w->v) || (u == w->v && v == w->u))
632                               return 1;
633           }
634           return 0;
635 }
636 
637 /* Add a pair to adjset.  No check for dups */
638 static int
adjSetadd(REGW * u,REGW * v)639 adjSetadd(REGW *u, REGW *v)
640 {
641           struct AdjSet *w;
642           int x;
643 
644           x = (u->nodnum+v->nodnum)& (HASHSZ-1);
645           for (w = edgehash[x]; w; w = w->next)
646                     if ((u == w->u && v == w->v) || (u == w->v && v == w->u))
647                               return 1;
648 
649           w = tmpalloc(sizeof(struct AdjSet));
650           w->u = u, w->v = v;
651           w->next = edgehash[x];
652           edgehash[x] = w;
653           return 0;
654 }
655 
656 /*
657  * Add an interference edge between two nodes.
658  */
659 static void
AddEdge(REGW * u,REGW * v)660 AddEdge(REGW *u, REGW *v)
661 {
662           ADJL *x;
663 
664 #ifdef PCC_DEBUG
665           RRDEBUG(("AddEdge: u %d v %d\n", ASGNUM(u), ASGNUM(v)));
666 
667 #if 0
668           if (ASGNUM(u) == 0)
669                     comperr("AddEdge 0");
670 #endif
671           if (CLASS(u) == 0 || CLASS(v) == 0)
672                     comperr("AddEdge class == 0 (%d=%d, %d=%d)",
673                         CLASS(u), ASGNUM(u), CLASS(v), ASGNUM(v));
674 #endif
675 
676           if (u == v)
677                     return;
678           if (adjSetadd(u, v))
679                     return;
680 
681 #if 0
682           if (ONLIST(u) == &precolored || ONLIST(v) == &precolored)
683                     comperr("precolored node in AddEdge");
684 #endif
685 
686           if (ONLIST(u) != &precolored) {
687                     x = tmpalloc(sizeof(ADJL));
688                     x->a_temp = v;
689                     x->r_next = u->r_adjList;
690                     u->r_adjList = x;
691                     NCLASS(u, CLASS(v))++;
692           }
693 
694           if (ONLIST(v) != &precolored) {
695                     x = tmpalloc(sizeof(ADJL));
696                     x->a_temp = u;
697                     x->r_next = v->r_adjList;
698                     v->r_adjList = x;
699                     NCLASS(v, CLASS(u))++;
700           }
701 
702 #if 0
703           RDEBUG(("AddEdge: u %d(d %d) v %d(d %d)\n", u, DEGREE(u), v, DEGREE(v)));
704 #endif
705 }
706 
707 static int
MoveRelated(REGW * n)708 MoveRelated(REGW *n)
709 {
710           MOVL *l;
711           REGM *w;
712 
713           for (l = MOVELIST(n); l; l = l->next) {
714                     w = l->regm;
715                     if (w->queue == ACTIVE || w->queue == WLIST)
716                               return 1;
717           }
718           return 0;
719 }
720 
721 static void
MkWorklist(void)722 MkWorklist(void)
723 {
724           REGW *w;
725 
726           RDEBUGX(int s=0);
727           RDEBUGX(int f=0);
728           RDEBUGX(int d=0);
729 
730           DLIST_INIT(&precolored, link);
731           DLIST_INIT(&simplifyWorklist, link);
732           DLIST_INIT(&freezeWorklist, link);
733           DLIST_INIT(&spillWorklist, link);
734           DLIST_INIT(&spilledNodes, link);
735           DLIST_INIT(&coalescedNodes, link);
736           DLIST_INIT(&coloredNodes, link);
737           DLIST_INIT(&selectStack, link);
738 
739           /*
740            * Remove all nodes from the initial list and put them on
741            * one of the worklists.
742            */
743           while (!DLIST_ISEMPTY(&initial, link)) {
744                     w = DLIST_NEXT(&initial, link);
745                     DLIST_REMOVE(w, link);
746                     if (!trivially_colorable(w)) {
747                               PUSHWLIST(w, spillWorklist);
748                               RDEBUGX(s++);
749                     } else if (MoveRelated(w)) {
750                               PUSHWLIST(w, freezeWorklist);
751                               RDEBUGX(f++);
752                     } else {
753                               PUSHWLIST(w, simplifyWorklist);
754                               RDEBUGX(d++);
755                     }
756           }
757           RDEBUG(("MkWorklist: spill %d freeze %d simplify %d\n", s,f,d));
758 }
759 
760 static void
addalledges(REGW * e)761 addalledges(REGW *e)
762 {
763           int i, j, k;
764           struct lives *l;
765 
766 #ifdef PCC_DEBUG
767           RDEBUG(("addalledges for %d\n", e->nodnum));
768 #endif
769 
770           if (e->r_class == -1)
771                     return; /* unused */
772 
773           if (ONLIST(e) != &precolored) {
774                     for (i = 0; ndontregs[i] >= 0; i++)
775                               AddEdge(e, &ablock[ndontregs[i]]);
776           }
777 
778           /* First add to long-lived temps and hard regs */
779           RDEBUG(("addalledges longlived "));
780           for (i = 0; i < xbits; i += NUMBITS) {
781                     if ((k = live[i/NUMBITS])) {
782                               while (k) {
783                                         j = ffs(k)-1;
784                                         if (i+j < MAXREGS)
785                                                   AddEdge(&ablock[i+j], e);
786                                         else
787                                                   AddEdge(&nblock[i+j+tempmin-MAXREGS],e);
788                                         RRDEBUG(("%d ", i+j+tempmin));
789                                         k &= ~(1 << j);
790                               }
791                     }
792 #if NUMBITS > 32 /* XXX hack for LP64 */
793                     k = (live[i/NUMBITS] >> 32);
794                     while (k) {
795                               j = ffs(k)-1;
796                               if (i+j+32 < MAXREGS)
797                                         AddEdge(&ablock[i+j+32], e);
798                               else
799                                         AddEdge(&nblock[i+j+tempmin-MAXREGS+32], e);
800                               RRDEBUG(("%d ", i+j+tempmin+32));
801                               k &= ~(1 << j);
802                     }
803 #endif
804           }
805           RDEBUG(("done\n"));
806           /* short-lived temps */
807           RDEBUG(("addalledges shortlived "));
808           DLIST_FOREACH(l, &lused, link) {
809 #ifdef PCC_DEBUG
810                     RRDEBUG(("%d ", ASGNUM(l->var)));
811 #endif
812                     AddEdge(l->var, e);
813           }
814           RDEBUG(("done\n"));
815 }
816 
817 /*
818  * Add a move edge between def and use.
819  */
820 static void
moveadd(REGW * def,REGW * use)821 moveadd(REGW *def, REGW *use)
822 {
823           REGM *r;
824           MOVL *w;
825 
826           if (def == use)
827                     return; /* no move to itself XXX - ``shouldn't happen'' */
828 #ifdef PCC_DEBUG
829           RDEBUG(("moveadd: def %d use %d\n", ASGNUM(def), ASGNUM(use)));
830 #endif
831 
832           /*
833            * Check if we are already on move list.
834            * XXX How can that happen ???
835            */
836           for (w = MOVELIST(def); w; w = w->next) {
837                     if ((w->regm->src == def && w->regm->dst == use) ||
838                         (w->regm->src == use && w->regm->dst == def))
839                               return; /* already there XXX reverse? */
840           }
841 
842           r = WORKLISTMOVEADD(use, def);
843           MOVELISTADD(def, r);
844           MOVELISTADD(use, r);
845 }
846 
847 /*
848  * Traverse arguments backwards.
849  * XXX - can this be tricked in some other way?
850  */
851 static void
argswalk(NODE * p)852 argswalk(NODE *p)
853 {
854 
855           if (p->n_op == CM) {
856                     argswalk(p->n_left);
857                     insnwalk(p->n_right);
858           } else
859                     insnwalk(p);
860 }
861 
862 /*
863  * Add to (or remove from) live set variables that must not
864  * be clobbered when traversing down on the other leg for
865  * a BITYPE node.
866  */
867 static void
setlive(NODE * p,int set,REGW * rv)868 setlive(NODE *p, int set, REGW *rv)
869 {
870           if (rv != NULL) {
871                     if (rv->nodnum < MAXREGS &&
872                         TESTBIT(validregs, rv->nodnum) == 0)
873                               return;
874                     set ? LIVEADDR(rv) : LIVEDELR(rv);
875                     return;
876           }
877 
878           if (p->n_regw != NULL) {
879                     if (p->n_regw->nodnum < MAXREGS &&
880                         TESTBIT(validregs, p->n_regw->nodnum) == 0)
881                               return;
882                     set ? LIVEADDR(p->n_regw) : LIVEDELR(p->n_regw);
883                     return;
884           }
885 
886           switch (optype(p->n_op)) {
887           case LTYPE:
888                     if (p->n_op == TEMP || VALIDREG(p))
889                               set ? LIVEADD(regno(p)) : LIVEDEL(regno(p));
890                     break;
891           case BITYPE:
892                     setlive(p->n_right, set, rv);
893                     /* FALLTHROUGH */
894           case UTYPE:
895                     setlive(p->n_left, set, rv);
896                     break;
897           }
898 }
899 
900 /*
901  * Add edges for temporary w against all temporaries that may be
902  * used simultaneously (like index registers).
903  */
904 static void
addedge_r(NODE * p,REGW * w)905 addedge_r(NODE *p, REGW *w)
906 {
907           RRDEBUG(("addedge_r: node %p regw %p\n", p, w));
908 
909           if (p->n_regw != NULL) {
910                     if (p->n_regw->nodnum < MAXREGS &&
911                         TESTBIT(validregs, p->n_regw->nodnum) == 0)
912                               return;
913                     AddEdge(p->n_regw, w);
914                     return;
915           }
916 
917           if (optype(p->n_op) == BITYPE)
918                     addedge_r(p->n_right, w);
919           if (optype(p->n_op) != LTYPE)
920                     addedge_r(p->n_left, w);
921 }
922 
923 /*
924  * delete early clobber liveness. Only interesting on regs.
925  */
926 static void
delcl(NODE * p)927 delcl(NODE *p)
928 {
929           int cw;
930 
931           if (p->n_op == ICON && p->n_type == STRTY)
932                     return;
933           cw = xasmcode(p->n_name);
934           if ((cw & XASMCONSTR) == 0 || !XASMISOUT(cw))
935                     return;
936           if (XASMVAL(cw) != 'r')
937                     return;
938           LIVEDEL(regno(p->n_left));
939 }
940 
941 /*
942  * add/del parameter from live set.
943  */
944 static void
setxarg(NODE * p)945 setxarg(NODE *p)
946 {
947           int i, ut = 0, in = 0;
948           REGW *rw;
949           int c, cw;
950 
951           if (p->n_op == ICON && p->n_type == STRTY)
952                     return;
953 
954           RDEBUG(("setxarg %p %s\n", p, p->n_name));
955           cw = xasmcode(p->n_name);
956           if (XASMISINP(cw))
957                     in = 1;
958           if (XASMISOUT(cw) && !(cw & XASMCONSTR))
959                     ut = 1;
960 
961           c = XASMVAL(cw);
962 
963 #ifdef MYSETXARG
964           MYSETXARG;
965 #endif
966 
967           switch (c) {
968           case 'm':
969           case 'g':
970                     /* must find all TEMPs/REGs and set them live */
971                     if (p->n_left->n_op != REG && p->n_left->n_op != TEMP) {
972                               insnwalk(p->n_left);
973                               break;
974                     }
975                     /* FALLTHROUGH */
976           case 'r':
977                     i = regno(p->n_left);
978                     rw = p->n_left->n_op == REG ? ablock : nblock;
979                     if (ut) {
980                               LIVEDEL(i);
981                     }
982                     if (in) {
983                               LIVEADD(i);
984                     }
985                     addalledges(&rw[i]);
986                     break;
987 
988           case 'i':
989           case 'n':
990                     break;
991           default:
992                     comperr("bad ixarg %s", p->n_name);
993           }
994 #ifdef MYSETXARG
995           MYSETXARG;
996 #endif
997 }
998 
999 /*
1000  * Do the in-tree part of liveness analysis. (the difficult part)
1001  *
1002  * Walk down the tree in reversed-evaluation order (backwards).
1003  * The moves and edges inserted and evaluation order for
1004  * instructions when code is emitted is described here, hence
1005  * this code runs the same but backwards.
1006  *
1007  * 2-op reclaim LEFT: eval L, move to DEST, eval R.
1008  *        moveadd L,DEST; addedge DEST,R
1009  * 2-op reclaim LEFT DORIGHT: eval R, eval L, move to DEST.
1010  *        moveadd L,DEST; addedge DEST,R; addedge L,R
1011  * 2-op reclaim RIGHT; eval L, eval R, move to DEST.
1012  *        moveadd R,DEST; addedge DEST,L; addedge L,R
1013  * 2-op reclaim RIGHT DORIGHT: eval R, move to DEST, eval L.
1014  *        moveadd R,DEST; addedge DEST,L
1015  * 3-op: eval L, eval R
1016  *        addedge L,R
1017  * 3-op DORIGHT: eval R, eval L
1018  *        addedge L,R
1019  *
1020  * Instructions with special needs are handled just like these variants,
1021  * with the exception of extra added moves and edges.
1022  * Moves to special regs are scheduled after the evaluation of both legs.
1023  */
1024 
1025 static void
insnwalk(NODE * p)1026 insnwalk(NODE *p)
1027 {
1028           int o = p->n_op;
1029           struct optab *q = &table[TBLIDX(p->n_su)];
1030           REGW *lr, *rr, *rv, *r, *rrv, *lrv;
1031           NODE *lp, *rp;
1032           int i, n;
1033 
1034           RDEBUG(("insnwalk %p\n", p));
1035 
1036           rv = p->n_regw;
1037 
1038           rrv = lrv = NULL;
1039           if (p->n_op == ASSIGN &&
1040               (p->n_left->n_op == TEMP || VALIDREG(p->n_left))) {
1041                     lr = p->n_left->n_op == TEMP ? nblock : ablock;
1042                     i = regno(p->n_left);
1043                     LIVEDEL(i);         /* remove assigned temp from live set */
1044                     addalledges(&lr[i]);
1045           }
1046 
1047           /* Add edges for the result of this node */
1048           if (rv && (q->visit & INREGS || o == TEMP || VALIDREG(p)))
1049                     addalledges(rv);
1050 
1051           /* special handling of CALL operators */
1052           if (callop(o)) {
1053                     if (rv)
1054                               moveadd(rv, &ablock[RETREG(p->n_type)]);
1055                     for (i = 0; tempregs[i] >= 0; i++)
1056                               addalledges(&ablock[tempregs[i]]);
1057           }
1058 
1059           /* for special return value registers add moves */
1060           if ((q->needs & NSPECIAL) && (n = rspecial(q, NRES)) >= 0 &&
1061               p->n_regw != NULL) {
1062                     rv = &ablock[n];
1063                     moveadd(p->n_regw, rv);
1064           }
1065 
1066           /* Check leaves for results in registers */
1067           lr = optype(o) != LTYPE ? p->n_left->n_regw : NULL;
1068           lp = optype(o) != LTYPE ? p->n_left : NULL;
1069           rr = optype(o) == BITYPE ? p->n_right->n_regw : NULL;
1070           rp = optype(o) == BITYPE ? p->n_right : NULL;
1071 
1072           /* simple needs */
1073           n = ncnt(q->needs);
1074           for (i = 0; i < n; i++) {
1075 #if 1
1076                     static int ncl[] =
1077                         { 0, NASL, NBSL, NCSL, NDSL, NESL, NFSL, NGSL };
1078                     static int ncr[] =
1079                         { 0, NASR, NBSR, NCSR, NDSR, NESR, NFSR, NGSR };
1080                     int j;
1081 
1082                     /* edges are already added */
1083                     if ((r = &p->n_regw[1+i])->r_class == -1) {
1084                               r = p->n_regw;
1085                     } else {
1086                               AddEdge(r, p->n_regw);
1087                               addalledges(r);
1088                               if (q->needs & NSPECIAL) {
1089                                         struct rspecial *rc;
1090                                         for (rc = nspecial(q); rc->op; rc++) {
1091                                                   if (rc->op != NEVER)
1092                                                             continue;
1093                                                   AddEdge(r, &ablock[rc->num]);
1094                                         }
1095                               }
1096                     }
1097                     if (optype(o) != LTYPE && (q->needs & ncl[CLASS(r)]) == 0)
1098                               addedge_r(p->n_left, r);
1099                     if (optype(o) == BITYPE && (q->needs & ncr[CLASS(r)]) == 0)
1100                               addedge_r(p->n_right, r);
1101                     for (j = i + 1; j < n; j++) {
1102                               if (p->n_regw[j+1].r_class == -1)
1103                                         continue;
1104                               AddEdge(r, &p->n_regw[j+1]);
1105                     }
1106 #else
1107                     if ((r = &p->n_regw[1+i])->r_class == -1)
1108                               continue;
1109                     addalledges(r);
1110                     if (optype(o) != LTYPE && (q->needs & NASL) == 0)
1111                               addedge_r(p->n_left, r);
1112                     if (optype(o) == BITYPE && (q->needs & NASR) == 0)
1113                               addedge_r(p->n_right, r);
1114 #endif
1115           }
1116 
1117           /* special needs */
1118           if (q->needs & NSPECIAL) {
1119                     struct rspecial *rc;
1120                     for (rc = nspecial(q); rc->op; rc++) {
1121                               switch (rc->op) {
1122 #define   ONLY(c,s) if (c) s(c, &ablock[rc->num])
1123                               case NLEFT:
1124                                         addalledges(&ablock[rc->num]);
1125                                         ONLY(lr, moveadd);
1126                                         if (optype(o) != BITYPE)
1127                                                   break;
1128                                         /* FALLTHROUGH */
1129                               case NORIGHT:
1130                                         addedge_r(p->n_right, &ablock[rc->num]);
1131                                         break;
1132                               case NRIGHT:
1133                                         addalledges(&ablock[rc->num]);
1134                                         ONLY(rr, moveadd);
1135                                         /* FALLTHROUGH */
1136                               case NOLEFT:
1137                                         addedge_r(p->n_left, &ablock[rc->num]);
1138                                         break;
1139                               case NEVER:
1140                                         addalledges(&ablock[rc->num]);
1141                                         break;
1142 #undef ONLY
1143                               }
1144                     }
1145           }
1146 
1147           if (o == ASSIGN) {
1148                     /* avoid use of unhandled registers */
1149                     if (p->n_left->n_op == REG &&
1150                         !TESTBIT(validregs, regno(p->n_left)))
1151                               lr = NULL;
1152                     if (p->n_right->n_op == REG &&
1153                         !TESTBIT(validregs, regno(p->n_right)))
1154                               rr = NULL;
1155                     /* needs special treatment */
1156                     if (lr && rr)
1157                               moveadd(lr, rr);
1158                     if (lr && rv)
1159                               moveadd(lr, rv);
1160                     if (rr && rv)
1161                               moveadd(rr, rv);
1162           } else if (callop(o)) {
1163                     int *c;
1164 
1165                     for (c = livecall(p); *c != -1; c++) {
1166                               addalledges(ablock + *c);
1167                               LIVEADD(*c);
1168                     }
1169           } else if (q->rewrite & (RESC1|RESC2|RESC3)) {
1170                     if (lr && rr)
1171                               AddEdge(lr, rr);
1172           } else if (q->rewrite & RLEFT) {
1173                     if (lr && rv)
1174                               moveadd(rv, lr), lrv = rv;
1175                     if (rv && rp)
1176                               addedge_r(rp, rv);
1177           } else if (q->rewrite & RRIGHT) {
1178                     if (rr && rv)
1179                               moveadd(rv, rr), rrv = rv;
1180                     if (rv && lp)
1181                               addedge_r(lp, rv);
1182           }
1183 
1184           switch (optype(o)) {
1185           case BITYPE:
1186                     if (p->n_op == ASSIGN &&
1187                         (p->n_left->n_op == TEMP || p->n_left->n_op == REG)) {
1188                               /* only go down right node */
1189                               insnwalk(p->n_right);
1190                     } else if (callop(o)) {
1191                               insnwalk(p->n_left);
1192                               /* Do liveness analysis on arguments (backwards) */
1193                               argswalk(p->n_right);
1194                     } else if ((p->n_su & DORIGHT) == 0) {
1195                               setlive(p->n_left, 1, lrv);
1196                               insnwalk(p->n_right);
1197                               setlive(p->n_left, 0, lrv);
1198                               insnwalk(p->n_left);
1199                     } else {
1200                               setlive(p->n_right, 1, rrv);
1201                               insnwalk(p->n_left);
1202                               setlive(p->n_right, 0, rrv);
1203                               insnwalk(p->n_right);
1204                     }
1205                     break;
1206 
1207           case UTYPE:
1208                     insnwalk(p->n_left);
1209                     break;
1210 
1211           case LTYPE:
1212                     switch (o) {
1213                     case REG:
1214                               if (!TESTBIT(validregs, regno(p)))
1215                                         break; /* never add moves */
1216                               /* FALLTHROUGH */
1217                     case TEMP:
1218                               i = regno(p);
1219                               rr = (o == TEMP ? &nblock[i] :  &ablock[i]);
1220                               if (rv != rr) {
1221                                         addalledges(rr);
1222                                         moveadd(rv, rr);
1223                               }
1224                               LIVEADD(i);
1225                               break;
1226 
1227                     case OREG: /* XXX - not yet */
1228                               break;
1229 
1230                     default:
1231                               break;
1232                     }
1233                     break;
1234           }
1235 }
1236 
1237 static bittype **gen, **killed, **in, **out;
1238 
1239 struct notspill {
1240           SLIST_ENTRY(notspill) link;
1241           int spnum;
1242 };
1243 SLIST_HEAD(, notspill) nothead;
1244 
1245 static int
innotspill(int n)1246 innotspill(int n)
1247 {
1248           struct notspill *nsp;
1249 
1250           SLIST_FOREACH(nsp, &nothead, link)
1251                     if (nsp->spnum == n)
1252                               return 1;
1253           return 0;
1254 }
1255 
1256 static void
addnotspill(int n)1257 addnotspill(int n)
1258 {
1259           struct notspill *nsp;
1260 
1261           if (innotspill(n))
1262                     return;
1263           nsp = tmpalloc(sizeof(struct notspill));
1264           nsp->spnum = n;
1265           SLIST_INSERT_LAST(&nothead, nsp, link);
1266 }
1267 
1268 /*
1269  * Found an extended assembler node, so growel out gen/killed nodes.
1270  */
1271 static void
xasmionize(NODE * p,void * arg)1272 xasmionize(NODE *p, void *arg)
1273 {
1274           int bb = *(int *)arg;
1275           int cw, b;
1276 
1277           if (p->n_op == ICON && p->n_type == STRTY)
1278                     return; /* dummy end marker */
1279 
1280           cw = xasmcode(p->n_name);
1281           if (XASMVAL(cw) == 'n' /* || XASMVAL(cw) == 'm' */)
1282                     return; /* no flow analysis */
1283           p = p->n_left;
1284 
1285           if (XASMVAL(cw) == 'g' && p->n_op != TEMP && p->n_op != REG)
1286                     return; /* no flow analysis */
1287 
1288           b = regno(p);
1289           if (XASMVAL(cw) == 'r' && p->n_op == TEMP)
1290                     addnotspill(b);
1291           if (XASMVAL(cw) == 'm') {
1292                     if (p->n_op == UMUL && p->n_left->n_op == TEMP) {
1293                               p = p->n_left;
1294                               b = regno(p);
1295                               addnotspill(b);
1296                               cw &= ~(XASMASG|XASMINOUT);
1297                     } else
1298                               return;
1299           }
1300 #define   MKTOFF(r) ((r) - tempmin + MAXREGS)
1301           if (XASMISOUT(cw)) {
1302                     if (p->n_op == TEMP) {
1303                               BITCLEAR(gen[bb], MKTOFF(b));
1304                               BITSET(killed[bb], MKTOFF(b));
1305                     } else if (p->n_op == REG) {
1306                               BITCLEAR(gen[bb], b);
1307                               BITSET(killed[bb], b);
1308                     } else
1309                               uerror("bad xasm node type %d", p->n_op);
1310           }
1311           if (XASMISINP(cw)) {
1312                     if (p->n_op == TEMP) {
1313                               BITSET(gen[bb], MKTOFF(b));
1314                     } else if (p->n_op == REG) {
1315                               BITSET(gen[bb], b);
1316                     } else if (optype(p->n_op) != LTYPE) {
1317                               if (XASMVAL(cw) == 'r')
1318                                         uerror("couldn't find available register");
1319                               else
1320                                         uerror("bad xasm node type2");
1321                     }
1322           }
1323 }
1324 
1325 #ifndef XASMCONSTREGS
1326 #define   XASMCONSTREGS(x) (-1)
1327 #endif
1328 
1329 /*
1330  * Check that given constraints are valid.
1331  */
1332 static void
xasmconstr(NODE * p,void * arg)1333 xasmconstr(NODE *p, void *arg)
1334 {
1335           int i;
1336 
1337           if (p->n_op == ICON && p->n_type == STRTY)
1338                     return; /* no constraints */
1339 
1340           if (strcmp(p->n_name, "cc") == 0 || strcmp(p->n_name, "memory") == 0)
1341                     return;
1342 
1343           for (i = 0; i < MAXREGS; i++)
1344                     if (strcmp(rnames[i], p->n_name) == 0) {
1345                               addalledges(&ablock[i]);
1346                               return;
1347                     }
1348           if ((i = XASMCONSTREGS(p->n_name)) < 0)
1349                     comperr("unsupported xasm constraint %s", p->n_name);
1350           addalledges(&ablock[i]);
1351 }
1352 
1353 #define   RUP(x) (((x)+NUMBITS-1)/NUMBITS)
1354 #define   SETCOPY(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] = f[i]
1355 #define   SETSET(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] |= f[i]
1356 #define   SETCLEAR(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] &= ~f[i]
1357 #define   SETCMP(v,t,f,i,n) for (i = 0; i < RUP(n); i++) \
1358           if (t[i] != f[i]) v = 1
1359 #define   SETEMPTY(t,sz)      memset(t, 0, BIT2BYTE(sz))
1360 
1361 static int
deldead(NODE * p,bittype * lvar)1362 deldead(NODE *p, bittype *lvar)
1363 {
1364           NODE *q;
1365           int ty, rv = 0;
1366 
1367 #define   BNO(p) (regno(p) - tempmin+MAXREGS)
1368           if (p->n_op == TEMP)
1369                     BITSET(lvar, BNO(p));
1370           if (asgop(p->n_op) && p->n_left->n_op == TEMP &&
1371               TESTBIT(lvar, BNO(p->n_left)) == 0) {
1372                     /*
1373                      * Not live, must delete the right tree at least
1374                      * down to next statement with side effects.
1375                      */
1376                     BDEBUG(("DCE deleting temp %d\n", regno(p->n_left)));
1377                     nfree(p->n_left);
1378                     q = p->n_right;
1379                     *p = *q;
1380                     nfree(q);
1381                     rv = 1;
1382           }
1383           ty = optype(p->n_op);
1384           if (ty != LTYPE)
1385                     rv |= deldead(p->n_left, lvar);
1386           if (ty == BITYPE)
1387                     rv |= deldead(p->n_right, lvar);
1388           return rv;
1389 }
1390 
1391 /*
1392  * Ensure that the su field is empty before generating instructions.
1393  */
1394 static void
clrsu(NODE * p)1395 clrsu(NODE *p)
1396 {
1397           int o = optype(p->n_op);
1398 
1399           p->n_su = 0;
1400           if (o != LTYPE)
1401                     clrsu(p->n_left);
1402           if (o == BITYPE)
1403                     clrsu(p->n_right);
1404 }
1405 
1406 /*
1407  * Do dead code elimination.
1408  */
1409 static int
dce(struct p2env * p2e)1410 dce(struct p2env *p2e)
1411 {
1412           extern struct interpass prepole;
1413           struct basicblock *bb;
1414           struct interpass *ip;
1415           NODE *p;
1416           bittype *lvar;
1417           int i, bbnum, fix = 0;
1418 
1419 #ifdef mach_vax
1420           return 0; /* XXX may need to recalc tree structure */
1421                               /* eliminating assignments may create more OREGs */
1422                               /* Fix by or/either break out ASSIGN or do this earlier */
1423 #endif
1424 
1425           BDEBUG(("Entering DCE\n"));
1426           /*
1427            * Traverse over the basic blocks.
1428            * if an assignment is found that writes to a temporary
1429            * that is not live out, remove that assignment and its legs.
1430            */
1431           DLIST_INIT(&prepole, qelem);
1432           BITALLOC(lvar, tmpalloc, xbits);
1433           DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
1434                     bbnum = bb->bbnum;
1435                     BBDEBUG(("DCE bblock %d, start %p last %p\n",
1436                         bbnum, bb->first, bb->last));
1437                     SETCOPY(lvar, out[bbnum], i, xbits);
1438                     for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
1439                               if (ip->type == IP_NODE && deldead(ip->ip_node, lvar)) {
1440                                         if ((p = deluseless(ip->ip_node)) == NULL) {
1441                                                   struct interpass *previp;
1442                                                   struct basicblock *prevbb;
1443 
1444                                                   if (ip == bb->first && ip == bb->last) {
1445                                                             /* Remove basic block */
1446                                                             previp = DLIST_PREV(ip, qelem);
1447                                                             DLIST_REMOVE(ip, qelem);
1448                                                             prevbb = DLIST_PREV(bb, bbelem);
1449                                                             DLIST_REMOVE(bb, bbelem);
1450                                                             bb = prevbb;
1451                                                   } else if (ip == bb->first) {
1452                                                             bb->first =
1453                                                                 DLIST_NEXT(ip, qelem);
1454                                                             DLIST_REMOVE(ip, qelem);
1455                                                   } else if (ip == bb->last) {
1456                                                             previp = DLIST_PREV(ip, qelem);
1457                                                             DLIST_REMOVE(ip, qelem);
1458                                                             bb->last = previp;
1459                                                             bb = DLIST_PREV(bb, bbelem);
1460                                                   } else {
1461                                                             previp = DLIST_NEXT(ip, qelem);
1462                                                             DLIST_REMOVE(ip, qelem);
1463                                                             ip = previp;
1464                                                             fix++;
1465                                                             continue;
1466                                                   }
1467                                                   fix++;
1468                                                   BDEBUG(("bb %d: DCE ip %p deleted\n",
1469                                                       bbnum, ip));
1470                                                   break;
1471                                         } else while (!DLIST_ISEMPTY(&prepole, qelem)) {
1472                                                   struct interpass *tipp;
1473 
1474                                                   BDEBUG(("bb %d: DCE doing ip prepend\n", bbnum));
1475                                                   tipp = DLIST_NEXT(&prepole, qelem);
1476                                                   DLIST_REMOVE(tipp, qelem);
1477                                                   DLIST_INSERT_BEFORE(ip, tipp, qelem);
1478                                                   if (ip == bb->first)
1479                                                             bb->first = tipp;
1480                                                   fix++;
1481                                                   BDEBUG(("DCE ip prepended\n"));
1482                                         }
1483                                         if (ip->type == IP_NODE) {
1484                                                   clrsu(p);
1485                                                   geninsn(p, FOREFF);
1486                                                   nsucomp(p);
1487                                                   ip->ip_node = p;
1488                                         }
1489                               }
1490                               if (ip == bb->first)
1491                                         break;
1492                     }
1493           }
1494           BDEBUG(("DCE fix %d\n", fix));
1495           return fix;
1496 }
1497 
1498 /*
1499  * Set/clear long term liveness for regs and temps.
1500  */
1501 static void
unionize(NODE * p,int bb)1502 unionize(NODE *p, int bb)
1503 {
1504           int i, o, ty;
1505 
1506           if ((o = p->n_op) == TEMP) {
1507 #ifdef notyet
1508                     for (i = 0; i < szty(p->n_type); i++) {
1509                               BITSET(gen[bb], (regno(p) - tempmin+i+MAXREGS));
1510                     }
1511 #else
1512                     i = 0;
1513                     BITSET(gen[bb], (regno(p) - tempmin+i+MAXREGS));
1514 #endif
1515           } else if (VALIDREG(p)) {
1516                     BITSET(gen[bb], regno(p));
1517           }
1518           if (asgop(o)) {
1519                     if (p->n_left->n_op == TEMP) {
1520                               int b = regno(p->n_left) - tempmin+MAXREGS;
1521 #ifdef notyet
1522                               for (i = 0; i < szty(p->n_type); i++) {
1523                                         BITCLEAR(gen[bb], (b+i));
1524                                         BITSET(killed[bb], (b+i));
1525                               }
1526 #else
1527                               i = 0;
1528                               BITCLEAR(gen[bb], (b+i));
1529                               BITSET(killed[bb], (b+i));
1530 #endif
1531                               unionize(p->n_right, bb);
1532                               return;
1533                     } else if (VALIDREG(p->n_left)) {
1534                               int b = regno(p->n_left);
1535                               BITCLEAR(gen[bb], b);
1536                               BITSET(killed[bb], b);
1537                               unionize(p->n_right, bb);
1538                               return;
1539                     }
1540           }
1541           ty = optype(o);
1542           if (ty != LTYPE)
1543                     unionize(p->n_left, bb);
1544           if (ty == BITYPE)
1545                     unionize(p->n_right, bb);
1546 }
1547 
1548 /*
1549  * Do variable liveness analysis.  Only analyze the long-lived
1550  * variables, and save the live-on-exit temporaries in a bit-field
1551  * at the end of each basic block. This bit-field is later used
1552  * when doing short-range liveness analysis in Build().
1553  */
1554 static void
LivenessAnalysis(struct p2env * p2e)1555 LivenessAnalysis(struct p2env *p2e)
1556 {
1557           struct basicblock *bb;
1558           struct interpass *ip;
1559           int bbnum;
1560 
1561           /*
1562            * generate the gen-killed sets for all basic blocks.
1563            */
1564           DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
1565                     bbnum = bb->bbnum;
1566                     for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
1567                               /* gen/killed is 'p', this node is 'n' */
1568                               if (ip->type == IP_NODE) {
1569                                         if (ip->ip_node->n_op == XASM)
1570                                                   flist(ip->ip_node->n_left,
1571                                                       xasmionize, &bbnum);
1572                                         else
1573                                                   unionize(ip->ip_node, bbnum);
1574                               }
1575                               if (ip == bb->first)
1576                                         break;
1577                     }
1578                     memcpy(in[bbnum], gen[bbnum], BIT2BYTE(xbits));
1579 #ifdef PCC_DEBUG
1580 #define   PRTRG(x) printf("%d ", x < MAXREGS ? x : x + tempmin-MAXREGS)
1581                     if (r2debug) {
1582                               int i;
1583 
1584                               printf("basic block %d\ngen: ", bbnum);
1585                               for (i = 0; i < xbits; i++)
1586                                         if (TESTBIT(gen[bbnum], i))
1587                                                   PRTRG(i);
1588                               printf("\nkilled: ");
1589                               for (i = 0; i < xbits; i++)
1590                                         if (TESTBIT(killed[bbnum], i))
1591                                                   PRTRG(i);
1592                               printf("\n");
1593                     }
1594 #endif
1595           }
1596 }
1597 
1598 
1599 /*
1600  * Build the set of interference edges and adjacency list.
1601  */
1602 static void
Build(struct p2env * p2e)1603 Build(struct p2env *p2e)
1604 {
1605           struct interpass *ipole = &p2e->ipole;
1606           struct basicblock bbfake;
1607           struct interpass *ip;
1608           struct basicblock *bb;
1609           bittype *saved;
1610           int i, j, again;
1611 
1612           if (xtemps == 0) {
1613                     /*
1614                      * No basic block splitup is done if not optimizing,
1615                      * so fake one basic block to keep the liveness analysis
1616                      * happy.
1617                      */
1618                     p2e->nbblocks = 1;
1619                     bbfake.bbnum = 0;
1620                     bbfake.last = DLIST_PREV(ipole, qelem);
1621                     bbfake.first = DLIST_NEXT(ipole, qelem);
1622                     DLIST_INIT(&p2e->bblocks, bbelem);
1623                     DLIST_INSERT_AFTER(&p2e->bblocks, &bbfake, bbelem);
1624                     SLIST_INIT(&bbfake.child);
1625           }
1626 
1627           /* Just fetch space for the temporaries from stack */
1628           gen = tmpalloc(p2e->nbblocks*sizeof(bittype*));
1629           killed = tmpalloc(p2e->nbblocks*sizeof(bittype*));
1630           in = tmpalloc(p2e->nbblocks*sizeof(bittype*));
1631           out = tmpalloc(p2e->nbblocks*sizeof(bittype*));
1632           for (i = 0; i < p2e->nbblocks; i++) {
1633                     BITALLOC(gen[i],tmpalloc,xbits);
1634                     BITALLOC(killed[i],tmpalloc,xbits);
1635                     BITALLOC(in[i],tmpalloc,xbits);
1636                     BITALLOC(out[i],tmpalloc,xbits);
1637           }
1638           BITALLOC(saved,tmpalloc,xbits);
1639 
1640           SLIST_INIT(&nothead);
1641 livagain:
1642           LivenessAnalysis(p2e);
1643 
1644           /* register variable temporaries are live */
1645           for (i = 0; i < NPERMREG-1; i++) {
1646                     if (nsavregs[i])
1647                               continue;
1648                     BITSET(out[p2e->nbblocks-1], (i+MAXREGS));
1649                     for (j = i+1; j < NPERMREG-1; j++) {
1650                               if (nsavregs[j])
1651                                         continue;
1652                               AddEdge(&nblock[i+tempmin], &nblock[j+tempmin]);
1653                     }
1654           }
1655 
1656           /* do liveness analysis on basic block level */
1657           do {
1658                     struct cfgnode *cn;
1659                     again = 0;
1660                     /* XXX - loop should be in reversed execution-order */
1661                     DLIST_FOREACH_REVERSE(bb, &p2e->bblocks, bbelem) {
1662                               i = bb->bbnum;
1663                               SETCOPY(saved, out[i], j, xbits);
1664                               SLIST_FOREACH(cn, &bb->child, chld) {
1665                                         SETSET(out[i], in[cn->bblock->bbnum], j, xbits);
1666                               }
1667                               SETCMP(again, saved, out[i], j, xbits);
1668                               SETCOPY(saved, in[i], j, xbits);
1669                               SETCOPY(in[i], out[i], j, xbits);
1670                               SETCLEAR(in[i], killed[i], j, xbits);
1671                               SETSET(in[i], gen[i], j, xbits);
1672                               SETCMP(again, saved, in[i], j, xbits);
1673                     }
1674           } while (again);
1675 
1676 #ifdef PCC_DEBUG
1677           if (r2debug) {
1678                     DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
1679                               printf("basic block %d\nin: ", bb->bbnum);
1680                               for (i = 0; i < xbits; i++)
1681                                         if (TESTBIT(in[bb->bbnum], i))
1682                                                   PRTRG(i);
1683                               printf("\nout: ");
1684                               for (i = 0; i < xbits; i++)
1685                                         if (TESTBIT(out[bb->bbnum], i))
1686                                                   PRTRG(i);
1687                               printf("\n");
1688                     }
1689           }
1690 #endif
1691           if (xtemps && xdce) {
1692                     /*
1693                      * Do dead code elimination by using live out.
1694                      * Ignores if any variable read from is marked volatile,
1695                      * but what it should do is unspecified anyway.
1696                      * Liveness Analysis should be done in optim2 instead.
1697                      *
1698                      * This should recalculate the basic block structure.
1699                      */
1700                     if (dce(p2e)) {
1701                               /* Clear bitfields */
1702                               for (i = 0; i < p2e->nbblocks; i++) {
1703                                         SETEMPTY(gen[i],xbits);
1704                                         SETEMPTY(killed[i],xbits);
1705                                         SETEMPTY(in[i],xbits);
1706                                         SETEMPTY(out[i],xbits);
1707                               }
1708                               SETEMPTY(saved,xbits);
1709                               goto livagain;
1710                     }
1711           }
1712 
1713           DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
1714                     RDEBUG(("liveadd bb %d\n", bb->bbnum));
1715                     i = bb->bbnum;
1716                     for (j = 0; j < xbits; j += NUMBITS)
1717                               live[j/NUMBITS] = 0;
1718                     SETCOPY(live, out[i], j, xbits);
1719                     for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
1720                               if (ip->type == IP_NODE) {
1721                                         if (ip->ip_node->n_op == XASM) {
1722                                                   flist(ip->ip_node->n_right,
1723                                                       xasmconstr, 0);
1724                                                   listf(ip->ip_node->n_left, setxarg);
1725                                                   listf(ip->ip_node->n_left, delcl);
1726                                         } else
1727                                                   insnwalk(ip->ip_node);
1728                               }
1729                               if (ip == bb->first)
1730                                         break;
1731                     }
1732           }
1733 
1734 #ifdef PCC_DEBUG
1735           if (r2debug) {
1736                     struct AdjSet *w;
1737                     ADJL *x;
1738                     REGW *y;
1739                     MOVL *m;
1740 
1741                     printf("Interference edges\n");
1742                     for (i = 0; i < HASHSZ; i++) {
1743                               if ((w = edgehash[i]) == NULL)
1744                                         continue;
1745                               for (; w; w = w->next)
1746                                         printf("%d <-> %d\n", ASGNUM(w->u), ASGNUM(w->v));
1747                     }
1748                     printf("Degrees\n");
1749                     DLIST_FOREACH(y, &initial, link) {
1750                               printf("%d (%c): trivial [%d] ", ASGNUM(y),
1751                                   CLASS(y)+'@', trivially_colorable(y));
1752                               i = 0;
1753                               for (x = ADJLIST(y); x; x = x->r_next) {
1754                                         if (ONLIST(x->a_temp) != &selectStack &&
1755                                             ONLIST(x->a_temp) != &coalescedNodes)
1756                                                   printf("%d ", ASGNUM(x->a_temp));
1757                                         else
1758                                                   printf("(%d) ", ASGNUM(x->a_temp));
1759                                         i++;
1760                               }
1761                               printf(": n=%d\n", i);
1762                     }
1763                     printf("Move nodes\n");
1764                     DLIST_FOREACH(y, &initial, link) {
1765                               if (MOVELIST(y) == NULL)
1766                                         continue;
1767                               printf("%d: ", ASGNUM(y));
1768                               for (m = MOVELIST(y); m; m = m->next) {
1769                                         REGW *yy = m->regm->src == y ?
1770                                             m->regm->dst : m->regm->src;
1771                                         printf("%d ", ASGNUM(yy));
1772                               }
1773                               printf("\n");
1774                     }
1775           }
1776 #endif
1777 
1778 }
1779 
1780 static void
EnableMoves(REGW * n)1781 EnableMoves(REGW *n)
1782 {
1783           MOVL *l;
1784           REGM *m;
1785 
1786           for (l = MOVELIST(n); l; l = l->next) {
1787                     m = l->regm;
1788                     if (m->queue != ACTIVE)
1789                               continue;
1790                     DLIST_REMOVE(m, link);
1791                     PUSHMLIST(m, worklistMoves, WLIST);
1792           }
1793 }
1794 
1795 static void
EnableAdjMoves(REGW * nodes)1796 EnableAdjMoves(REGW *nodes)
1797 {
1798           ADJL *w;
1799           REGW *n;
1800 
1801           EnableMoves(nodes);
1802           for (w = ADJLIST(nodes); w; w = w->r_next) {
1803                     n = w->a_temp;
1804                     if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
1805                               continue;
1806                     EnableMoves(w->a_temp);
1807           }
1808 }
1809 
1810 /*
1811  * Decrement the degree of node w for class c.
1812  */
1813 static void
DecrementDegree(REGW * w,int c)1814 DecrementDegree(REGW *w, int c)
1815 {
1816           int wast;
1817 
1818 #ifdef PCC_DEBUG
1819           RRDEBUG(("DecrementDegree: w %d, c %d\n", ASGNUM(w), c));
1820 #endif
1821 
1822           wast = trivially_colorable(w);
1823           if (NCLASS(w, c) > 0)
1824                     NCLASS(w, c)--;
1825           if (wast == trivially_colorable(w))
1826                     return;
1827 
1828           EnableAdjMoves(w);
1829           DELWLIST(w);
1830           ONLIST(w) = 0;
1831           if (MoveRelated(w)) {
1832                     PUSHWLIST(w, freezeWorklist);
1833           } else {
1834                     PUSHWLIST(w, simplifyWorklist);
1835           }
1836 }
1837 
1838 static void
Simplify(void)1839 Simplify(void)
1840 {
1841           REGW *w;
1842           ADJL *l;
1843 
1844           w = POPWLIST(simplifyWorklist);
1845           PUSHWLIST(w, selectStack);
1846 #ifdef PCC_DEBUG
1847           RDEBUG(("Simplify: node %d class %d\n", ASGNUM(w), w->r_class));
1848 #endif
1849 
1850           l = w->r_adjList;
1851           for (; l; l = l->r_next) {
1852                     if (ONLIST(l->a_temp) == &selectStack ||
1853                         ONLIST(l->a_temp) == &coalescedNodes)
1854                               continue;
1855                     DecrementDegree(l->a_temp, w->r_class);
1856           }
1857 }
1858 
1859 static REGW *
GetAlias(REGW * n)1860 GetAlias(REGW *n)
1861 {
1862           if (ONLIST(n) == &coalescedNodes)
1863                     return GetAlias(ALIAS(n));
1864           return n;
1865 }
1866 
1867 static int
OK(REGW * t,REGW * r)1868 OK(REGW *t, REGW *r)
1869 {
1870 #ifdef PCC_DEBUG
1871           RDEBUG(("OK: t %d CLASS(t) %d adjSet(%d,%d)=%d\n",
1872               ASGNUM(t), CLASS(t), ASGNUM(t), ASGNUM(r), adjSet(t, r)));
1873 
1874           if (r2debug > 1) {
1875                     ADJL *w;
1876                     int ndeg = 0;
1877                     printf("OK degree: ");
1878                     for (w = ADJLIST(t); w; w = w->r_next) {
1879                               if (ONLIST(w->a_temp) != &selectStack &&
1880                                   ONLIST(w->a_temp) != &coalescedNodes)
1881                                         printf("%c%d ", CLASS(w->a_temp)+'@',
1882                                             ASGNUM(w->a_temp)), ndeg++;
1883                               else
1884                                         printf("(%d) ", ASGNUM(w->a_temp));
1885                     }
1886                     printf("\n");
1887 #if 0
1888                     if (ndeg != DEGREE(t) && DEGREE(t) >= 0)
1889                               printf("!!!ndeg %d != DEGREE(t) %d\n", ndeg, DEGREE(t));
1890 #endif
1891           }
1892 #endif
1893 
1894           if (trivially_colorable(t) || ONLIST(t) == &precolored ||
1895               (adjSet(t, r) || !aliasmap(CLASS(t), COLOR(r))))/* XXX - check aliasmap */
1896                     return 1;
1897           return 0;
1898 }
1899 
1900 static int
adjok(REGW * v,REGW * u)1901 adjok(REGW *v, REGW *u)
1902 {
1903           ADJL *w;
1904           REGW *t;
1905 
1906           RDEBUG(("adjok\n"));
1907           for (w = ADJLIST(v); w; w = w->r_next) {
1908                     t = w->a_temp;
1909                     if (ONLIST(t) == &selectStack || ONLIST(t) == &coalescedNodes)
1910                               continue;
1911                     if (OK(t, u) == 0)
1912                               return 0;
1913           }
1914           RDEBUG(("adjok returns OK\n"));
1915           return 1;
1916 }
1917 
1918 /*
1919  * Do a conservative estimation of whether two temporaries can
1920  * be coalesced.  This is "Briggs-style" check.
1921  * Neither u nor v is precolored when called.
1922  */
1923 static int
Conservative(REGW * u,REGW * v)1924 Conservative(REGW *u, REGW *v)
1925 {
1926           ADJL *w, *ww;
1927           REGW *n;
1928           int xncl[NUMCLASS+1], mcl = 0, j;
1929 
1930           for (j = 0; j < NUMCLASS+1; j++)
1931                     xncl[j] = 0;
1932           /*
1933            * Increment xncl[class] up to K for each class.
1934            * If all classes has reached K then check colorability and return.
1935            */
1936           for (w = ADJLIST(u); w; w = w->r_next) {
1937                     n = w->a_temp;
1938                     if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
1939                               continue;
1940                     if (xncl[CLASS(n)] == regK[CLASS(n)])
1941                               continue;
1942                     if (!trivially_colorable(n) || ONLIST(n) == &precolored)
1943                               xncl[CLASS(n)]++;
1944                     if (xncl[CLASS(n)] < regK[CLASS(n)])
1945                               continue;
1946                     if (++mcl == NUMCLASS)
1947                               goto out; /* cannot get more out of it */
1948           }
1949           for (w = ADJLIST(v); w; w = w->r_next) {
1950                     n = w->a_temp;
1951                     if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
1952                               continue;
1953                     if (xncl[CLASS(n)] == regK[CLASS(n)])
1954                               continue;
1955                     /* ugly: have we been here already? */
1956                     for (ww = ADJLIST(u); ww; ww = ww->r_next)
1957                               if (ww->a_temp == n)
1958                                         break;
1959                     if (ww)
1960                               continue;
1961                     if (!trivially_colorable(n) || ONLIST(n) == &precolored)
1962                               xncl[CLASS(n)]++;
1963                     if (xncl[CLASS(n)] < regK[CLASS(n)])
1964                               continue;
1965                     if (++mcl == NUMCLASS)
1966                               break;
1967           }
1968 out:      j = trivially_colorable_p(CLASS(u), xncl);
1969           return j;
1970 }
1971 
1972 static void
AddWorkList(REGW * w)1973 AddWorkList(REGW *w)
1974 {
1975 
1976           if (ONLIST(w) != &precolored && !MoveRelated(w) &&
1977               trivially_colorable(w)) {
1978                     DELWLIST(w);
1979                     PUSHWLIST(w, simplifyWorklist);
1980           }
1981 }
1982 
1983 static void
Combine(REGW * u,REGW * v)1984 Combine(REGW *u, REGW *v)
1985 {
1986           MOVL *m;
1987           ADJL *l;
1988           REGW *t;
1989 
1990 #ifdef PCC_DEBUG
1991           RDEBUG(("Combine (%d,%d)\n", ASGNUM(u), ASGNUM(v)));
1992 #endif
1993 
1994           if (ONLIST(v) == &freezeWorklist) {
1995                     DELWLIST(v);
1996           } else {
1997                     DELWLIST(v);
1998           }
1999           PUSHWLIST(v, coalescedNodes);
2000           ALIAS(v) = u;
2001 #ifdef PCC_DEBUG
2002           if (r2debug) {
2003                     printf("adjlist(%d): ", ASGNUM(v));
2004                     for (l = ADJLIST(v); l; l = l->r_next)
2005                               printf("%d ", l->a_temp->nodnum);
2006                     printf("\n");
2007           }
2008 #endif
2009 #if 1
2010 {
2011           MOVL *m0 = MOVELIST(v);
2012 
2013           for (m0 = MOVELIST(v); m0; m0 = m0->next) {
2014                     for (m = MOVELIST(u); m; m = m->next)
2015                               if (m->regm == m0->regm)
2016                                         break; /* Already on list */
2017                     if (m)
2018                               continue; /* already on list */
2019                     MOVELISTADD(u, m0->regm);
2020           }
2021 }
2022 #else
2023 
2024           if ((m = MOVELIST(u))) {
2025                     while (m->next)
2026                               m = m->next;
2027                     m->next = MOVELIST(v);
2028           } else
2029                     MOVELIST(u) = MOVELIST(v);
2030 #endif
2031           EnableMoves(v);
2032           for (l = ADJLIST(v); l; l = l->r_next) {
2033                     t = l->a_temp;
2034                     if (ONLIST(t) == &selectStack || ONLIST(t) == &coalescedNodes)
2035                               continue;
2036                     /* Do not add edge if u cannot affect the colorability of t */
2037                     /* XXX - check aliasmap */
2038                     if (ONLIST(u) != &precolored || aliasmap(CLASS(t), COLOR(u)))
2039                               AddEdge(t, u);
2040                     DecrementDegree(t, CLASS(v));
2041           }
2042           if (!trivially_colorable(u) && ONLIST(u) == &freezeWorklist) {
2043                     DELWLIST(u);
2044                     PUSHWLIST(u, spillWorklist);
2045           }
2046 #ifdef PCC_DEBUG
2047           if (r2debug) {
2048                     ADJL *w;
2049                     printf("Combine %d class (%d): ", ASGNUM(u), CLASS(u));
2050                     for (w = ADJLIST(u); w; w = w->r_next) {
2051                               if (ONLIST(w->a_temp) != &selectStack &&
2052                                   ONLIST(w->a_temp) != &coalescedNodes)
2053                                         printf("%d ", ASGNUM(w->a_temp));
2054                               else
2055                                         printf("(%d) ", ASGNUM(w->a_temp));
2056                     }
2057                     printf("\n");
2058           }
2059 #endif
2060 }
2061 
2062 static void
Coalesce(void)2063 Coalesce(void)
2064 {
2065           REGM *m;
2066           REGW *x, *y, *u, *v;
2067 
2068           m = POPMLIST(worklistMoves);
2069           x = GetAlias(m->src);
2070           y = GetAlias(m->dst);
2071 
2072           if (ONLIST(y) == &precolored)
2073                     u = y, v = x;
2074           else
2075                     u = x, v = y;
2076 
2077 #ifdef PCC_DEBUG
2078           RDEBUG(("Coalesce: src %d dst %d u %d v %d x %d y %d\n",
2079               ASGNUM(m->src), ASGNUM(m->dst), ASGNUM(u), ASGNUM(v),
2080               ASGNUM(x), ASGNUM(y)));
2081 #endif
2082 
2083           if (CLASS(m->src) != CLASS(m->dst))
2084                     comperr("Coalesce: src class %d, dst class %d",
2085                         CLASS(m->src), CLASS(m->dst));
2086 
2087           if (u == v) {
2088                     RDEBUG(("Coalesce: u == v\n"));
2089                     PUSHMLIST(m, coalescedMoves, COAL);
2090                     AddWorkList(u);
2091           } else if (ONLIST(v) == &precolored || adjSet(u, v)) {
2092                     RDEBUG(("Coalesce: constrainedMoves\n"));
2093                     PUSHMLIST(m, constrainedMoves, CONSTR);
2094                     AddWorkList(u);
2095                     AddWorkList(v);
2096           } else if ((ONLIST(u) == &precolored && adjok(v, u)) ||
2097               (ONLIST(u) != &precolored && Conservative(u, v))) {
2098                     RDEBUG(("Coalesce: Conservative\n"));
2099                     PUSHMLIST(m, coalescedMoves, COAL);
2100                     Combine(u, v);
2101                     AddWorkList(u);
2102           } else {
2103                     RDEBUG(("Coalesce: activeMoves\n"));
2104                     PUSHMLIST(m, activeMoves, ACTIVE);
2105           }
2106 }
2107 
2108 static void
coalasg(NODE * p,void * arg)2109 coalasg(NODE *p, void *arg)
2110 {
2111           NODE *l;
2112           REGW *u;
2113 
2114           if (p->n_op != ASSIGN || p->n_regw == NULL)
2115                     return;
2116           l = p->n_left;
2117           if (l->n_op == TEMP)
2118                     u = &nblock[regno(l)];
2119           else if (l->n_op == REG)
2120                     u = &ablock[regno(l)];
2121           else
2122                     return;
2123 
2124           Combine(u, p->n_regw);
2125           AddWorkList(u);
2126 }
2127 
2128 /*
2129  * Coalesce assign to a left reg with the assign temp node itself.
2130  * This has to be done before anything else.
2131  */
2132 static void
Coalassign(struct p2env * p2e)2133 Coalassign(struct p2env *p2e)
2134 {
2135           struct interpass *ip;
2136 
2137           DLIST_FOREACH(ip, &p2env.ipole, qelem) {
2138                     if (ip->type == IP_NODE)
2139                               walkf(ip->ip_node, coalasg, 0);
2140           }
2141 }
2142 
2143 static void
FreezeMoves(REGW * u)2144 FreezeMoves(REGW *u)
2145 {
2146           MOVL *w, *o;
2147           REGM *m;
2148           REGW *z;
2149           REGW *x, *y, *v;
2150 
2151           for (w = MOVELIST(u); w; w = w->next) {
2152                     m = w->regm;
2153                     if (m->queue != WLIST && m->queue != ACTIVE)
2154                               continue;
2155                     x = m->src;
2156                     y = m->dst;
2157                     if (GetAlias(y) == GetAlias(u))
2158                               v = GetAlias(x);
2159                     else
2160                               v = GetAlias(y);
2161 #ifdef PCC_DEBUG
2162                     RDEBUG(("FreezeMoves: u %d (%d,%d) v %d\n",
2163                         ASGNUM(u),ASGNUM(x),ASGNUM(y),ASGNUM(v)));
2164 #endif
2165                     DLIST_REMOVE(m, link);
2166                     PUSHMLIST(m, frozenMoves, FROZEN);
2167                     if (ONLIST(v) != &freezeWorklist)
2168                               continue;
2169                     for (o = MOVELIST(v); o; o = o->next)
2170                               if (o->regm->queue == WLIST || o->regm->queue == ACTIVE)
2171                                         break;
2172                     if (o == NULL) {
2173                               z = v;
2174                               DELWLIST(z);
2175                               PUSHWLIST(z, simplifyWorklist);
2176                     }
2177           }
2178 }
2179 
2180 static void
Freeze(void)2181 Freeze(void)
2182 {
2183           REGW *u;
2184 
2185           /*
2186            * To find out:
2187            * Check if the moves to freeze have exactly the same
2188            * interference edges.  If they do, coalesce them instead, it
2189            * may free up other nodes that they interfere with.
2190            */
2191 
2192           /*
2193            * Select nodes to freeze first by using following criteria:
2194            * - Trivially colorable
2195            * - Single or few moves to less trivial nodes.
2196            */
2197           DLIST_FOREACH(u, &freezeWorklist, link) {
2198                     if (u >= &nblock[tempmax] || u < &nblock[tempmin])
2199                               continue; /* No short range temps */
2200                     if (!trivially_colorable(u))
2201                               continue; /* Prefer colorable nodes */
2202                     /* Check for at most two move-related nodes */
2203                     if (u->r_moveList->next && u->r_moveList->next->next)
2204                               continue;
2205                     /* Ok, remove node */
2206                     DLIST_REMOVE(u, link);
2207                     u->r_onlist = 0;
2208                     break;
2209           }
2210           if (u == &freezeWorklist) /* Nothing matched criteria, just take one */
2211                     u = POPWLIST(freezeWorklist);
2212           PUSHWLIST(u, simplifyWorklist);
2213 #ifdef PCC_DEBUG
2214           RDEBUG(("Freeze %d\n", ASGNUM(u)));
2215 #endif
2216           FreezeMoves(u);
2217 }
2218 
2219 static void
SelectSpill(void)2220 SelectSpill(void)
2221 {
2222           REGW *w;
2223 
2224           RDEBUG(("SelectSpill\n"));
2225 #ifdef PCC_DEBUG
2226           if (r2debug)
2227                     DLIST_FOREACH(w, &spillWorklist, link)
2228                               printf("SelectSpill: %d\n", ASGNUM(w));
2229 #endif
2230 
2231           /* First check if we can spill register variables */
2232           DLIST_FOREACH(w, &spillWorklist, link) {
2233                     if (w >= &nblock[tempmin] && w < &nblock[basetemp])
2234                               break;
2235           }
2236 
2237           RRDEBUG(("SelectSpill: trying longrange\n"));
2238           if (w == &spillWorklist) {
2239                     /* try to find another long-range variable */
2240                     DLIST_FOREACH(w, &spillWorklist, link) {
2241                               if (innotspill(w - nblock))
2242                                         continue;
2243                               if (w >= &nblock[tempmin] && w < &nblock[tempmax])
2244                                         break;
2245                     }
2246           }
2247 
2248           if (w == &spillWorklist) {
2249                     RRDEBUG(("SelectSpill: trying not leaf\n"));
2250                     /* no heuristics, just fetch first element */
2251                     /* but not if leaf */
2252                     DLIST_FOREACH(w, &spillWorklist, link) {
2253                               if (w->r_nclass[0] == 0)
2254                                         break;
2255                     }
2256           }
2257 
2258           if (w == &spillWorklist) {
2259                     /* Eh, only leaves :-/ Try anyway */
2260                     /* May not be useable */
2261                     w = DLIST_NEXT(&spillWorklist, link);
2262                     RRDEBUG(("SelectSpill: need leaf\n"));
2263           }
2264 
2265         DLIST_REMOVE(w, link);
2266 
2267           PUSHWLIST(w, simplifyWorklist);
2268 #ifdef PCC_DEBUG
2269           RDEBUG(("Freezing node %d\n", ASGNUM(w)));
2270 #endif
2271           FreezeMoves(w);
2272 }
2273 
2274 /*
2275  * Set class on long-lived temporaries based on its type.
2276  */
2277 static void
traclass(NODE * p,void * arg)2278 traclass(NODE *p, void *arg)
2279 {
2280           REGW *nb;
2281 
2282           if (p->n_op != TEMP)
2283                     return;
2284 
2285           nb = &nblock[regno(p)];
2286           if (CLASS(nb) == 0)
2287                     CLASS(nb) = gclass(p->n_type);
2288 }
2289 
2290 static void
paint(NODE * p,void * arg)2291 paint(NODE *p, void *arg)
2292 {
2293           struct optab *q;
2294           REGW *w, *ww;
2295           int i;
2296 
2297 #ifdef notyet
2298           /* XXX - trashes rewrite of trees (short) */
2299           if (!DLIST_ISEMPTY(&spilledNodes, link)) {
2300                     p->n_reg = 0;
2301                     return;
2302           }
2303 #endif
2304           if (p->n_regw != NULL) {
2305                     /* Must color all allocated regs also */
2306                     ww = w = p->n_regw;
2307                     q = &table[TBLIDX(p->n_su)];
2308                     p->n_reg = COLOR(w);
2309                     w++;
2310                     if (q->needs & ALLNEEDS)
2311                               for (i = 0; i < ncnt(q->needs); i++) {
2312                                         if (w->r_class == -1)
2313                                                   p->n_reg |= ENCRA(COLOR(ww), i);
2314                                         else
2315                                                   p->n_reg |= ENCRA(COLOR(w), i);
2316                                         w++;
2317                               }
2318 #ifdef notdef
2319                     if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
2320                         DECRA(p->n_reg, 0) != regno(p->n_left))
2321                               comperr("paint: %p clashing ASSIGN moves; %d != %d", p,
2322                                   DECRA(p->n_reg, 0), regno(p->n_left));
2323 #endif
2324           } else
2325                     p->n_reg = -1;
2326           if (p->n_op == TEMP) {
2327                     REGW *nb = &nblock[regno(p)];
2328                     regno(p) = COLOR(nb);
2329                     if (TCLASS(p->n_su) == 0)
2330                               SCLASS(p->n_su, CLASS(nb));
2331                     p->n_op = REG;
2332                     setlval(p, 0);
2333           }
2334 }
2335 
2336 /*
2337  * See if this node have a move that has been removed in Freeze
2338  * but as we can make use of anyway.
2339  */
2340 static int
colfind(int okColors,REGW * r)2341 colfind(int okColors, REGW *r)
2342 {
2343           REGW *w;
2344           MOVL *m;
2345           int c;
2346 
2347           for (m = MOVELIST(r); m; m = m->next) {
2348                     if ((w = m->regm->src) == r)
2349                               w = m->regm->dst;
2350                     w = GetAlias(w);
2351                     if (ONLIST(w) != &coloredNodes && ONLIST(w) != &precolored)
2352                               continue; /* Not yet colored */
2353                     if (CLASS(w) != CLASS(r))
2354                               comperr("colfind: move between classes");
2355 
2356                     for (c = 0; c < regK[CLASS(w)]; c++)
2357                               if (color2reg(c, CLASS(w)) == COLOR(w))
2358                                         break;
2359                     if (c == regK[CLASS(w)])
2360                               comperr("colfind: out of reg number");
2361 
2362                     if (((1 << c) & okColors) == 0) {
2363                               RDEBUG(("colfind: Failed coloring as %d\n", ASGNUM(w)));
2364                               continue;
2365                     }
2366                     RDEBUG(("colfind: Recommend color from %d\n", ASGNUM(w)));
2367                     return COLOR(w);
2368           }
2369           return color2reg(ffs(okColors)-1, CLASS(r));
2370 }
2371 
2372 static void
AssignColors(struct interpass * ip)2373 AssignColors(struct interpass *ip)
2374 {
2375           struct interpass *ip2;
2376           int okColors, c;
2377           REGW *o, *w;
2378           ADJL *x;
2379 
2380           RDEBUG(("AssignColors\n"));
2381           while (!WLISTEMPTY(selectStack)) {
2382                     w = POPWLIST(selectStack);
2383                     okColors = classmask(CLASS(w));
2384 #ifdef PCC_DEBUG
2385                     RDEBUG(("classmask av %d, class %d: %x\n",
2386                         w->nodnum, CLASS(w), okColors));
2387 #endif
2388 
2389                     for (x = ADJLIST(w); x; x = x->r_next) {
2390                               o = GetAlias(x->a_temp);
2391 #ifdef PCC_DEBUG
2392                               RRDEBUG(("Adj(%d): %d (%d)\n",
2393                                   ASGNUM(w), ASGNUM(o), ASGNUM(x->a_temp)));
2394 #endif
2395 
2396                               if (ONLIST(o) == &coloredNodes ||
2397                                   ONLIST(o) == &precolored) {
2398                                         c = aliasmap(CLASS(w), COLOR(o));
2399                                         RRDEBUG(("aliasmap in class %d by color %d: "
2400                                             "%x, okColors %x\n",
2401                                             CLASS(w), COLOR(o), c, okColors));
2402 
2403                                         okColors &= ~c;
2404                               }
2405                     }
2406                     if (okColors == 0) {
2407                               PUSHWLIST(w, spilledNodes);
2408 #ifdef PCC_DEBUG
2409                               RDEBUG(("Spilling node %d\n", ASGNUM(w)));
2410 #endif
2411                     } else {
2412                               COLOR(w) = colfind(okColors, w);
2413                               PUSHWLIST(w, coloredNodes);
2414 #ifdef PCC_DEBUG
2415                               RDEBUG(("Coloring %d with %s, free %x\n",
2416                                   ASGNUM(w), rnames[COLOR(w)], okColors));
2417 #endif
2418                     }
2419           }
2420           DLIST_FOREACH(w, &coalescedNodes, link) {
2421                     REGW *ww = GetAlias(w);
2422                     COLOR(w) = COLOR(ww);
2423                     if (ONLIST(ww) == &spilledNodes) {
2424 #ifdef PCC_DEBUG
2425                               RDEBUG(("coalesced node %d spilled\n", w->nodnum));
2426 #endif
2427                               ww = DLIST_PREV(w, link);
2428                               DLIST_REMOVE(w, link);
2429                               PUSHWLIST(w, spilledNodes);
2430                               w = ww;
2431                     } else {
2432 #ifdef PCC_DEBUG
2433                               RDEBUG(("Giving coalesced node %d color %s\n",
2434                                   w->nodnum, rnames[COLOR(w)]));
2435 #endif
2436                     }
2437           }
2438 
2439 #ifdef PCC_DEBUG
2440           if (r2debug)
2441                     DLIST_FOREACH(w, &coloredNodes, link)
2442                               printf("%d: color %s\n", ASGNUM(w), rnames[COLOR(w)]);
2443 #endif
2444           if (DLIST_ISEMPTY(&spilledNodes, link)) {
2445                     DLIST_FOREACH(ip2, ip, qelem)
2446                               if (ip2->type == IP_NODE)
2447                                         walkf(ip2->ip_node, paint, 0);
2448           }
2449 }
2450 
2451 static REGW *spole, *longsp;
2452 /*
2453  * Store all spilled nodes in memory by fetching a temporary on the stack.
2454  * Will never end up here if not optimizing.
2455  */
2456 static void
longtemp(NODE * p,void * arg)2457 longtemp(NODE *p, void *arg)
2458 {
2459           REGW *w;
2460 
2461           if (p->n_op != TEMP)
2462                     return;
2463           /* XXX - should have a bitmask to find temps to convert */
2464           DLIST_FOREACH(w, spole, link) {
2465                     if (w != &nblock[regno(p)])
2466                               continue;
2467 #ifdef MYLONGTEMP
2468                     MYLONGTEMP(p, w);
2469 #endif
2470                     if (w->r_class == 0) {
2471                               w->r_color = freetemp(szty(p->n_type));
2472                               w->r_class = FPREG; /* XXX - assumption? */
2473                     }
2474                     storemod(p, w->r_color, w->r_class);
2475                     break;
2476           }
2477 }
2478 
2479 /*
2480  * Check if this node is just something directly addressable.
2481  * XXX - should use target canaddr() when we knows that it is OK
2482  * for all targets. Can currently be a little too optimistic.
2483  */
2484 static int
regcanaddr(NODE * p)2485 regcanaddr(NODE *p)
2486 {
2487           int o = p->n_op;
2488 
2489           if (o==NAME || o==ICON || o==OREG )
2490                     return 1;
2491           if (o == UMUL) {
2492                     if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
2493                               return 1;
2494                     if ((p->n_left->n_op == PLUS || p->n_left->n_op == MINUS) &&
2495                         (p->n_left->n_left->n_op == REG ||
2496                          p->n_left->n_left->n_op == TEMP) &&
2497                         p->n_left->n_right->n_op == ICON)
2498                               return 1;
2499           }
2500           return 0;
2501 }
2502 
2503 static struct interpass *cip;
2504 
2505 static NODE *
shstore(NODE * p,struct interpass * ipp,REGW * w)2506 shstore(NODE *p, struct interpass *ipp, REGW *w)
2507 {
2508           struct interpass *ip;
2509           int off;
2510           NODE *l;
2511 
2512           off = freetemp(szty(p->n_type));
2513           l = storenode(p->n_type, off);
2514 
2515           ip = ipnode(mkbinode(ASSIGN, storenode(p->n_type, off), p, p->n_type));
2516           DLIST_INSERT_BEFORE(ipp, ip, qelem);
2517           DLIST_REMOVE(w, link);
2518           return l;
2519 }
2520 
2521 /*
2522  * Rewrite a tree by storing a variable in memory.
2523  * This code would work better if the SU computations were smarter.
2524  * XXX - must check if basic block structure is destroyed!
2525  *
2526  * 1) Ensure that both left & right are directly addressable.
2527  * 2) Save interfering long-term temporaries.
2528  * 3) If node itself not addressable, store the node itself.
2529  * 4) Store the parent.
2530  * 5) ...HELP!!??!!
2531  *
2532  * It might be a better idea to start with 3) or 4) first, but that will
2533  * make the code more complicated and I'm not sure it's worth it.
2534  */
2535 static int
shorttemp(NODE * p,NODE * parent,REGW * w)2536 shorttemp(NODE *p, NODE *parent, REGW *w)
2537 {
2538           struct interpass *nip;
2539           ADJL *ll;
2540           NODE *l, *r;
2541           int off, i, nc;
2542 
2543           if (p->n_regw == NULL)
2544                     goto down;
2545 
2546           /* Check if this the correct node. */
2547           nc = p->n_su == -1 ? 0 : ncnt(table[TBLIDX(p->n_su)].needs);
2548           for (i = 0; i < nc + 1; i++)
2549                     if ((p->n_regw + i) == w)
2550                               break;
2551 
2552           if (i == nc + 1) {
2553 down:               switch (optype(p->n_op)) {
2554                     case BITYPE:
2555                               if (shorttemp(p->n_left, p, w) == 0)
2556                                         return shorttemp(p->n_right, p, w);
2557                               return 1;
2558                     case UTYPE:
2559                               return shorttemp(p->n_left, p, w);
2560                     case LTYPE:
2561                               return 0;
2562                     }
2563           }
2564 
2565           RDEBUG(("Node %d (%p) to store\n", ASGNUM(w), p));
2566           /* ensure that both left and right are addressable */
2567           if (!regcanaddr(p) && !callop(p->n_op)) {
2568                     /* this is neither leaf nor addressable */
2569                     if (p->n_op != ASSIGN && !regcanaddr(p->n_left)) {
2570                               /* store left */
2571                               p->n_left = shstore(p->n_left, cip, w);
2572                               RDEBUG(("Node %d stored left\n", ASGNUM(w)));
2573                               return 1;
2574                     } else if (optype(p->n_op) == BITYPE &&
2575                         !regcanaddr(p->n_right)) {
2576                               /* store right */
2577                               p->n_right = shstore(p->n_right, cip, w);
2578                               RDEBUG(("Node %d stored right\n", ASGNUM(w)));
2579                               return 1;
2580                     }
2581           }
2582           /* Store long-term temps that interferes */
2583           ll = w->r_adjList;
2584           for (; ll; ll = ll->r_next) {
2585                     if (ll->a_temp < &nblock[tempmax] &&
2586                         ll->a_temp >= &nblock[tempmin]) {
2587                               longsp = ll->a_temp;
2588                               RDEBUG(("Stored long %d\n", ASGNUM(longsp)));
2589                               return 1; /* try again */
2590                     }
2591           }
2592 
2593           if (regcanaddr(p)) {
2594                     /* The node to spill is addressable, spill parent */
2595                     if (parent == NULL)
2596                               comperr("cannot spill TOP node!");
2597                     p = parent;
2598           }
2599           off = freetemp(szty(p->n_type));
2600           l = storenode(p->n_type, off);
2601           r = talloc();
2602           *r = *p;
2603           nip = ipnode(mkbinode(ASSIGN, l, r, p->n_type));
2604           storemod(p, off, FPREG); /* XXX */
2605           DLIST_INSERT_BEFORE(cip, nip, qelem);
2606           DLIST_REMOVE(w, link);
2607           RDEBUG(("Stored parent node %d (%p)\n", ASGNUM(w), p));
2608           return 1;
2609 }
2610 
2611 static void
dlr(REGW * w)2612 dlr(REGW *w)
2613 {
2614           if (w == 0)
2615                     return;
2616           DLIST_REMOVE(w, link);
2617           RDEBUG(("Removing %d\n", ASGNUM(w)));
2618 }
2619 
2620 /*
2621  * Return the number of the topmost temporary that should be spilled.
2622  * If temps below found, remove them from the spill list.
2623  * If two temps at the same level are found, remove one.
2624  * If both left & right have temps, store right and leave left.
2625  */
2626 static REGW *
toptemp(NODE * p,REGW * rw)2627 toptemp(NODE *p, REGW *rw)
2628 {
2629           REGW *r, *l, *rv, *w;
2630           int nc, i;
2631 
2632           l = r = rv = NULL;
2633           if (optype(p->n_op) != LTYPE)
2634                     l = toptemp(p->n_left, rw);
2635           if (optype(p->n_op) == BITYPE)
2636                     r = toptemp(p->n_right, rw);
2637           DLIST_FOREACH(w, rw, link) {
2638                     nc = p->n_su == -1 ? 0 : ncnt(table[TBLIDX(p->n_su)].needs);
2639                     for (i = 0; i < nc + 1; i++) {
2640                               if ((p->n_regw + i) != w)
2641                                         continue;
2642                               RDEBUG(("Found %d \n", ASGNUM(w)));
2643                               dlr(rv);
2644                               rv = w;
2645                     }
2646           }
2647           if (rv != NULL) {
2648                     dlr(l);
2649                     dlr(r);
2650           } else if (r != NULL) {
2651                     /* pick right, not left */
2652                     rv = r;
2653                     dlr(l);
2654           } else {
2655                     rv = l;
2656           }
2657           return rv;
2658 }
2659 
2660 static void leafrewrite(struct interpass *ipole, REGW *rpole);
2661 /*
2662  * Change the TEMPs in the ipole list to stack variables.
2663  */
2664 static void
treerewrite(struct interpass * ipole,REGW * rpole)2665 treerewrite(struct interpass *ipole, REGW *rpole)
2666 {
2667           struct interpass *ip;
2668           REGW *w, longregs;
2669 
2670           spole = rpole;
2671 
2672           DLIST_FOREACH(ip, ipole, qelem) {
2673                     if (ip->type != IP_NODE)
2674                               continue;
2675                     if ((w = toptemp(ip->ip_node, rpole)) == 0)
2676                               continue;
2677                     cip = ip;
2678                     shorttemp(ip->ip_node, NULL, w); /* convert temps to oregs */
2679           }
2680         if (longsp) {
2681 #ifdef PCC_DEBUG
2682                     RDEBUG(("Storing node %d to save short\n", ASGNUM(longsp)));
2683 #endif
2684                     if (longsp >= &nblock[tempmin] && longsp < &nblock[basetemp]) {
2685                               int num = longsp - nblock - tempmin;
2686                               nsavregs[num] = 1;
2687                     } else {
2688                               DLIST_INIT(&longregs, link);
2689                               DLIST_INSERT_AFTER(&longregs, longsp, link);
2690                               leafrewrite(ipole, &longregs);
2691                     }
2692           } else if (!DLIST_ISEMPTY(spole, link))
2693                     comperr("treerewrite not empty");
2694 }
2695 
2696 /*
2697  * Change the TEMPs in the ipole list to stack variables.
2698  */
2699 static void
leafrewrite(struct interpass * ipole,REGW * rpole)2700 leafrewrite(struct interpass *ipole, REGW *rpole)
2701 {
2702           extern NODE *nodepole;
2703           extern int thisline;
2704           struct interpass *ip;
2705 
2706           spole = rpole;
2707           DLIST_FOREACH(ip, ipole, qelem) {
2708                     if (ip->type != IP_NODE)
2709                               continue;
2710                     nodepole = ip->ip_node;
2711                     thisline = ip->lineno;
2712                     walkf(ip->ip_node, longtemp, 0); /* convert temps to oregs */
2713           }
2714           nodepole = NIL;
2715 }
2716 
2717 /*
2718  * Avoid copying spilled argument to new position on stack.
2719  */
2720 static int
temparg(struct interpass * ipole,REGW * w)2721 temparg(struct interpass *ipole, REGW *w)
2722 {
2723           struct interpass *ip;
2724           NODE *p;
2725           int reg;
2726 
2727           ip = DLIST_NEXT(ipole, qelem); /* PROLOG */
2728           while (ip->type != IP_DEFLAB)
2729                     ip = DLIST_NEXT(ip, qelem);
2730           ip = DLIST_NEXT(ip, qelem); /* first NODE */
2731           for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
2732                     if (ip->type == IP_ASM)
2733                               continue;
2734                     p = ip->ip_node;
2735 #ifdef notdef
2736                     /* register args may already have been put on stack */
2737                     if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
2738                               comperr("temparg");
2739 #endif
2740                     if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
2741                               continue; /* unknown tree */
2742 
2743                     if (p->n_right->n_op != OREG)
2744                               continue; /* arg in register */
2745                     if (w != &nblock[regno(p->n_left)])
2746                               continue;
2747                     w->r_color = (int)getlval(p->n_right);
2748                     reg = regno(p->n_right);
2749                     tfree(p);
2750                     /* Cannot DLIST_REMOVE here, would break basic blocks */
2751                     /* Make it a nothing instead */
2752                     ip->type = IP_ASM;
2753                     ip->ip_asm = "";
2754                     return reg;
2755           }
2756           return 0;
2757 }
2758 
2759 #define   ONLYPERM 1
2760 #define   LEAVES     2
2761 #define   SMALL      3
2762 
2763 /*
2764  * Scan the whole function and search for temporaries to be stored
2765  * on-stack.
2766  *
2767  * Be careful to not destroy the basic block structure in the first scan.
2768  */
2769 static int
RewriteProgram(struct interpass * ip)2770 RewriteProgram(struct interpass *ip)
2771 {
2772           REGW shortregs, longregs, saveregs, *q;
2773           REGW *w;
2774           int rwtyp;
2775 
2776           RDEBUG(("RewriteProgram\n"));
2777           DLIST_INIT(&shortregs, link);
2778           DLIST_INIT(&longregs, link);
2779           DLIST_INIT(&saveregs, link);
2780 
2781           /* sort the temporaries in three queues, short, long and perm */
2782           while (!DLIST_ISEMPTY(&spilledNodes, link)) {
2783                     w = DLIST_NEXT(&spilledNodes, link);
2784                     DLIST_REMOVE(w, link);
2785 
2786                     if (w >= &nblock[tempmin] && w < &nblock[basetemp]) {
2787                               q = &saveregs;
2788                     } else if (w >= &nblock[basetemp] && w < &nblock[tempmax]) {
2789                               q = &longregs;
2790                     } else
2791                               q = &shortregs;
2792                     DLIST_INSERT_AFTER(q, w, link);
2793           }
2794 #ifdef PCC_DEBUG
2795           if (r2debug) {
2796                     printf("permanent: ");
2797                     DLIST_FOREACH(w, &saveregs, link)
2798                               printf("%d ", ASGNUM(w));
2799                     printf("\nlong-lived: ");
2800                     DLIST_FOREACH(w, &longregs, link)
2801                               printf("%d ", ASGNUM(w));
2802                     printf("\nshort-lived: ");
2803                     DLIST_FOREACH(w, &shortregs, link)
2804                               printf("%d ", ASGNUM(w));
2805                     printf("\n");
2806           }
2807 #endif
2808           rwtyp = 0;
2809 
2810           if (!DLIST_ISEMPTY(&saveregs, link)) {
2811                     rwtyp = ONLYPERM;
2812                     DLIST_FOREACH(w, &saveregs, link) {
2813                               int num = w - nblock - tempmin;
2814                               nsavregs[num] = 1;
2815                     }
2816           }
2817           if (!DLIST_ISEMPTY(&longregs, link)) {
2818                     rwtyp = LEAVES;
2819                     DLIST_FOREACH(w, &longregs, link) {
2820                               w->r_class = xtemps ? temparg(ip, w) : 0;
2821                     }
2822           }
2823 
2824           if (rwtyp == LEAVES) {
2825                     leafrewrite(ip, &longregs);
2826                     rwtyp = ONLYPERM;
2827           }
2828 
2829           if (rwtyp == 0 && !DLIST_ISEMPTY(&shortregs, link)) {
2830                     /* Must rewrite the trees */
2831                     treerewrite(ip, &shortregs);
2832 #if 0
2833                     if (xtemps)
2834                               comperr("treerewrite");
2835 #endif
2836                     rwtyp = SMALL;
2837           }
2838 
2839           RDEBUG(("savregs %x rwtyp %d\n", 0, rwtyp));
2840 
2841           return rwtyp;
2842 }
2843 
2844 #ifdef PCC_DEBUG
2845 /*
2846  * Print TEMP/REG contents in a node.
2847  */
2848 void
prtreg(NODE * p)2849 prtreg(NODE *p)
2850 {
2851           int i, n = p->n_su == -1 ? 0 : ncnt(table[TBLIDX(p->n_su)].needs);
2852 if (p->n_reg == -1) goto foo;
2853           if (use_regw || p->n_reg > 0x40000000 || p->n_reg < 0) {
2854                     printf("TEMP ");
2855                     if (p->n_regw != NULL) {
2856                               for (i = 0; i < n+1; i++)
2857                                         printf("%d ", p->n_regw[i].nodnum);
2858                     } else
2859                               printf("<undef>");
2860           } else {
2861 foo:                printf("REG ");
2862                     if (p->n_reg != -1) {
2863                               for (i = 0; i < n+1; i++) {
2864                                         int r = DECRA(p->n_reg, i);
2865                                         if (r >= MAXREGS)
2866                                                   printf("<badreg> ");
2867                                         else
2868                                                   printf("%s ", rnames[r]);
2869                               }
2870                     } else
2871                               printf("<undef>");
2872           }
2873 }
2874 #endif
2875 
2876 #ifdef notyet
2877 /*
2878  * Assign instructions, calculate evaluation order and
2879  * set temporary register numbers.
2880  */
2881 static void
insgen()2882 insgen()
2883 {
2884           clrsu(p);
2885           geninsn(); /* instruction assignment */
2886           sucomp();  /* set evaluation order */
2887           slong();   /* set long temp types */
2888           sshort();  /* set short temp numbers */
2889 }
2890 #endif
2891 
2892 /*
2893  * Do register allocation for trees by graph-coloring.
2894  */
2895 void
ngenregs(struct p2env * p2e)2896 ngenregs(struct p2env *p2e)
2897 {
2898           struct interpass *ipole = &p2e->ipole;
2899           extern NODE *nodepole;
2900           struct interpass *ip;
2901           int i, j, tbits;
2902           int uu[NPERMREG] = { -1 };
2903           int xnsavregs[NPERMREG];
2904           int beenhere = 0;
2905           TWORD type;
2906 
2907           DLIST_INIT(&lunused, link);
2908           DLIST_INIT(&lused, link);
2909 
2910           /*
2911            * Do some setup before doing the real thing.
2912            */
2913           tempmin = p2e->ipp->ip_tmpnum;
2914 
2915           /*
2916            * Allocate space for the permanent registers in the
2917            * same block as the long-lived temporaries.
2918            * These temporaries will be handled the same way as
2919            * all other variables.
2920            */
2921           basetemp = tempmin;
2922           nsavregs = xnsavregs;
2923           for (i = 0; i < NPERMREG; i++)
2924                     xnsavregs[i] = 0;
2925           ndontregs = uu; /* currently never avoid any regs */
2926 
2927           tempmin -= (NPERMREG-1);
2928 #ifdef notyet
2929           if (xavoidfp)
2930                     dontregs |= REGBIT(FPREG);
2931 #endif
2932 
2933           /* Block for precolored nodes */
2934           ablock = tmpalloc(sizeof(REGW)*MAXREGS);
2935           memset(ablock, 0, sizeof(REGW)*MAXREGS);
2936           for (i = 0; i < MAXREGS; i++) {
2937                     ablock[i].r_onlist = &precolored;
2938                     ablock[i].r_class = GCLASS(i); /* XXX */
2939                     ablock[i].r_color = i;
2940 #ifdef PCC_DEBUG
2941                     ablock[i].nodnum = i;
2942 #endif
2943           }
2944 
2945 ssagain:
2946           tempmax = p2e->epp->ip_tmpnum;
2947 #ifdef PCC_DEBUG
2948           nodnum = tempmax;
2949 #endif
2950           tbits = tempmax - tempmin;    /* # of temporaries */
2951           xbits = tbits + MAXREGS;      /* total size of live array */
2952           if (tbits) {
2953                     nblock = tmpalloc(tbits * sizeof(REGW));
2954 
2955                     nblock -= tempmin;
2956 #ifdef HAVE_C99_FORMAT
2957                     RDEBUG(("nblock %p num %d size %zu\n",
2958                         nblock, tbits, (size_t)(tbits * sizeof(REGW))));
2959 #endif
2960           }
2961           live = tmpalloc(BIT2BYTE(xbits));
2962 
2963 #ifdef notyet
2964           TMPMARK();
2965 #endif
2966 
2967 
2968 recalc:
2969 onlyperm: /* XXX - should not have to redo all */
2970           memset(edgehash, 0, sizeof(edgehash));
2971 
2972           /* clear adjacent node list */
2973           for (i = 0; i < MAXREGS; i++)
2974                     for (j = 0; j < NUMCLASS+1; j++)
2975                               NCLASS(&ablock[i], j) = 0;
2976 
2977           if (tbits) {
2978                     memset(nblock+tempmin, 0, tbits * sizeof(REGW));
2979 #ifdef PCC_DEBUG
2980                     for (i = tempmin; i < tempmax; i++)
2981                               nblock[i].nodnum = i;
2982 #endif
2983           }
2984           memset(live, 0, BIT2BYTE(xbits));
2985           RPRINTIP(ipole);
2986           DLIST_INIT(&initial, link);
2987           ntsz = 0;
2988           DLIST_FOREACH(ip, ipole, qelem) {
2989                     extern int thisline;
2990                     if (ip->type != IP_NODE)
2991                               continue;
2992                     nodepole = ip->ip_node;
2993                     thisline = ip->lineno;
2994                     if (ip->ip_node->n_op != XASM) {
2995                               clrsu(ip->ip_node);
2996                               geninsn(ip->ip_node, FOREFF);
2997                     }
2998                     nsucomp(ip->ip_node);
2999                     walkf(ip->ip_node, traclass, 0);
3000           }
3001           nodepole = NIL;
3002           RDEBUG(("nsucomp allocated %d temps (%d,%d)\n",
3003               tempmax-tempmin, tempmin, tempmax));
3004 
3005 #ifdef PCC_DEBUG
3006           use_regw = 1;
3007           RPRINTIP(ipole);
3008           use_regw = 0;
3009 #endif
3010           RDEBUG(("ngenregs: numtemps %d (%d, %d)\n", tempmax-tempmin,
3011                         tempmin, tempmax));
3012 
3013           DLIST_INIT(&coalescedMoves, link);
3014           DLIST_INIT(&constrainedMoves, link);
3015           DLIST_INIT(&frozenMoves, link);
3016           DLIST_INIT(&worklistMoves, link);
3017           DLIST_INIT(&activeMoves, link);
3018 
3019           /* Set class and move-related for perm regs */
3020           for (i = 0; i < (NPERMREG-1); i++) {
3021                     if (nsavregs[i])
3022                               continue;
3023                     nblock[i+tempmin].r_class = GCLASS(permregs[i]);
3024                     DLIST_INSERT_AFTER(&initial, &nblock[i+tempmin], link);
3025                     moveadd(&nblock[i+tempmin], &ablock[permregs[i]]);
3026                     addalledges(&nblock[i+tempmin]);
3027           }
3028 
3029           Build(p2e);
3030           RDEBUG(("Build done\n"));
3031           MkWorklist();
3032           RDEBUG(("MkWorklist done\n"));
3033           Coalassign(p2e);
3034           do {
3035                     if (!WLISTEMPTY(simplifyWorklist))
3036                               Simplify();
3037                     else if (!WLISTEMPTY(worklistMoves))
3038                               Coalesce();
3039                     else if (!WLISTEMPTY(freezeWorklist))
3040                               Freeze();
3041                     else if (!WLISTEMPTY(spillWorklist))
3042                               SelectSpill();
3043           } while (!WLISTEMPTY(simplifyWorklist) || !WLISTEMPTY(worklistMoves) ||
3044               !WLISTEMPTY(freezeWorklist) || !WLISTEMPTY(spillWorklist));
3045           AssignColors(ipole);
3046 
3047           RDEBUG(("After AssignColors\n"));
3048           RPRINTIP(ipole);
3049 
3050           if (!WLISTEMPTY(spilledNodes)) {
3051                     switch (RewriteProgram(ipole)) {
3052                     case ONLYPERM:
3053                               goto onlyperm;
3054                     case SMALL:
3055                               optimize(p2e);
3056                               if (beenhere++ == MAXLOOP)
3057                                         comperr("cannot color graph - COLORMAP() bug?");
3058                               if (xssa)
3059                                         goto ssagain;
3060                               goto recalc;
3061                     }
3062           }
3063 
3064           /* fill in regs to save */
3065           memset(p2e->ipp->ipp_regs, 0, sizeof(p2e->ipp->ipp_regs));
3066           for (i = 0; i < NPERMREG-1; i++) {
3067                     NODE *p;
3068 
3069                     if (nsavregs[i]) {
3070                               BITSET(p2e->ipp->ipp_regs, permregs[i]);
3071                               continue; /* Spilled */
3072                     }
3073                     if (nblock[i+tempmin].r_color == permregs[i])
3074                               continue; /* Coalesced */
3075                     /*
3076                      * If the original color of this permreg is used for
3077                      * coloring another register, swap them to avoid
3078                      * unnecessary moves.
3079                      */
3080                     for (j = i+1; j < NPERMREG-1; j++) {
3081                               if (nblock[j+tempmin].r_color != permregs[i])
3082                                         continue;
3083                               nblock[j+tempmin].r_color = nblock[i+tempmin].r_color;
3084                               break;
3085                     }
3086                     if (j != NPERMREG-1)
3087                               continue;
3088 
3089                     /* Generate reg-reg move nodes for save */
3090                     type = PERMTYPE(permregs[i]);
3091 #ifdef PCC_DEBUG
3092                     if (PERMTYPE(nblock[i+tempmin].r_color) != type)
3093                               comperr("permreg botch");
3094 #endif
3095                     p = mkbinode(ASSIGN,
3096                         mklnode(REG, 0, nblock[i+tempmin].r_color, type),
3097                         mklnode(REG, 0, permregs[i], type), type);
3098                     p->n_reg = p->n_left->n_reg = p->n_right->n_reg = -1;
3099                     clrsu(p);
3100                     geninsn(p, FOREFF);
3101                     ip = ipnode(p);
3102                     DLIST_INSERT_AFTER(ipole->qelem.q_forw, ip, qelem);
3103                     p = mkbinode(ASSIGN, mklnode(REG, 0, permregs[i], type),
3104                         mklnode(REG, 0, nblock[i+tempmin].r_color, type), type);
3105                     p->n_reg = p->n_left->n_reg = p->n_right->n_reg = -1;
3106                     clrsu(p);
3107                     geninsn(p, FOREFF);
3108                     ip = ipnode(p);
3109                     DLIST_INSERT_BEFORE(ipole->qelem.q_back, ip, qelem);
3110           }
3111           stktemp = freetemp(ntsz);
3112           memcpy(p2e->epp->ipp_regs, p2e->ipp->ipp_regs, sizeof(p2e->epp->ipp_regs));
3113           /* Done! */
3114 }
3115