1 /* $Id: regs.c,v 1.216.2.1 2011/02/22 18:38:08 ragge Exp $ */
3 * Copyright (c) 2005 Anders Magnusson (ragge@ludd.luth.se).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #define MAXLOOP 20 /* Max number of allocation loops XXX 3 should be enough */
42 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
46 * New-style register allocator using graph coloring.
47 * The design is based on the George and Appel paper
48 * "Iterated Register Coalescing", ACM Transactions, No 3, May 1996.
51 #define BITALLOC(ptr,all,sz) { \
52 int sz__s = BIT2BYTE(sz); ptr = all(sz__s); memset(ptr, 0, sz__s); }
54 #undef COMPERR_PERM_MOVE
56 #define RDEBUG(x) if (rdebug) printf x
57 #define RRDEBUG(x) if (rdebug > 1) printf x
58 #define RPRINTIP(x) if (rdebug) printip(x)
60 #define UDEBUG(x) if (udebug) printf x
61 #define BDEBUG(x) if (b2debug) printf x
62 #define BBDEBUG(x) if (b2debug > 1) printf x
73 #define VALIDREG(p) (p->n_op == REG && TESTBIT(validregs, regno(p)))
76 * Data structure overview for this implementation of graph coloring:
78 * Each temporary (called "node") is described by the type REGW.
79 * Space for all nodes is allocated initially as an array, so
80 * the nodes can be can be referenced both by the node number and
83 * All moves are represented by the type REGM, allocated when needed.
85 * The "live" set used during graph building is represented by a bitset.
87 * Interference edges are represented by struct AdjSet, hashed and linked
88 * from index into the edgehash array.
90 * A mapping from each node to the moves it is assiciated with is
91 * maintained by an array moveList which for each node number has a linked
92 * list of MOVL types, each pointing to a REGM.
94 * Adjacency list is maintained by the adjList array, indexed by the
95 * node number. Each adjList entry points to an ADJL type, and is a
96 * single-linked list for all adjacent nodes.
98 * degree, alias and color are integer arrays indexed by node number.
102 * linked list of adjacent nodes.
104 typedef struct regw3
{
105 struct regw3
*r_next
;
110 * Structure describing a move.
112 typedef struct regm
{
113 DLIST_ENTRY(regm
) link
;
114 struct regw
*src
, *dst
;
118 typedef struct movlink
{
119 struct movlink
*next
;
124 * Structure describing a temporary.
126 typedef struct regw
{
127 DLIST_ENTRY(regw
) link
;
128 ADJL
*r_adjList
; /* linked list of adjacent nodes */
129 int r_class
; /* this nodes class */
130 int r_nclass
[NUMCLASS
+1]; /* count of adjacent classes */
131 struct regw
*r_alias
; /* aliased temporary */
132 int r_color
; /* final node color */
133 struct regw
*r_onlist
; /* which work list this node belongs to */
134 MOVL
*r_moveList
; /* moves associated with this node */
136 int nodnum
; /* Debug number */
141 * Worklists, a node is always on exactly one of these lists.
143 static REGW precolored
, simplifyWorklist
, freezeWorklist
, spillWorklist
,
144 spilledNodes
, coalescedNodes
, coloredNodes
, selectStack
;
145 static REGW initial
, *nblock
;
146 static void insnwalk(NODE
*p
);
150 #define SETNUM(x) (x)->nodnum = nodnum++
151 #define ASGNUM(x) (x)->nodnum
157 #define ALLNEEDS (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT)
162 static int tempmin
, tempmax
, basetemp
, xbits
;
164 * nsavregs is an array that matches the permregs array.
165 * Each entry in the array may have the values:
166 * 0 : register coalesced, just ignore.
167 * 1 : save register on stack
168 * If the entry is 0 but the resulting color differs from the
169 * corresponding permregs index, add moves.
170 * XXX - should be a bitfield!
172 static int *nsavregs
, *ndontregs
;
175 * Return the REGW struct for a temporary.
176 * If first time touched, enter into list for existing vars.
177 * Only called from sucomp().
185 if (regno(p
) < tempmin
|| regno(p
) >= tempmax
)
186 comperr("temp %p(%d) outside limits (%d-%d)",
187 p
, regno(p
), tempmin
, tempmax
);
189 nb
= &nblock
[regno(p
)];
190 if (nb
->link
.q_forw
== 0) {
191 DLIST_INSERT_AFTER(&initial
, nb
, link
);
193 ASGNUM(nb
) = regno(p
);
194 RDEBUG(("Adding longtime %d for tmp %d\n",
195 nb
->nodnum
, regno(p
)));
198 if (nb
->r_class
== 0)
199 nb
->r_class
= gclass(p
->n_type
);
201 RDEBUG(("newblock: p %p, node %d class %d\n",
202 p
, nb
->nodnum
, nb
->r_class
));
208 * Count the number of registers needed to evaluate a tree.
209 * This is only done to find the evaluation order of the tree.
210 * While here, assign temp numbers to the registers that will
211 * be needed when the tree is evaluated.
213 * While traversing the tree, assign REGW nodes to the registers
214 * used by all instructions:
215 * - n_regw[0] is always set to the outgoing node. If the
216 * instruction is 2-op (addl r0,r1) then an implicit move
217 * is inserted just before the left (clobbered) operand.
218 * - if the instruction has needs then REGW nodes are
219 * allocated as n_regw[1] etc.
226 int nreg
, need
, i
, nxreg
, o
;
227 int nareg
, nbreg
, ncreg
, ndreg
, nereg
, nfreg
, ngreg
;
232 UDEBUG(("entering nsucomp, node %p\n", p
));
234 if (TBLIDX(p
->n_su
) == 0) {
240 p
->n_regw
= newblock(p
);
241 else if (p
->n_op
== REG
)
242 p
->n_regw
= &ablock
[regno(p
)];
244 a
= nsucomp(p
->n_left
);
246 b
= nsucomp(p
->n_right
);
254 q
= &table
[TBLIDX(p
->n_su
)];
256 for (i
= (q
->needs
& NACOUNT
), nareg
= 0; i
; i
-= NAREG
)
258 for (i
= (q
->needs
& NBCOUNT
), nbreg
= 0; i
; i
-= NBREG
)
260 for (i
= (q
->needs
& NCCOUNT
), ncreg
= 0; i
; i
-= NCREG
)
262 for (i
= (q
->needs
& NDCOUNT
), ndreg
= 0; i
; i
-= NDREG
)
264 for (i
= (q
->needs
& NECOUNT
), nereg
= 0; i
; i
-= NEREG
)
266 for (i
= (q
->needs
& NFCOUNT
), nfreg
= 0; i
; i
-= NFREG
)
268 for (i
= (q
->needs
& NGCOUNT
), ngreg
= 0; i
; i
-= NGREG
)
271 nxreg
= nareg
+ nbreg
+ ncreg
+ ndreg
+ nereg
+ nfreg
+ ngreg
;
274 nreg
= MAX(fregs
, nreg
);
277 right
= nsucomp(p
->n_right
);
282 left
= nsucomp(p
->n_left
);
286 UDEBUG(("node %p left %d right %d\n", p
, left
, right
));
291 need
= left
+ MAX(nreg
, 1);
293 need
= MAX(right
, left
);
294 need
= MAX(need
, nreg
);
296 if (setorder(p
) == 0) {
297 /* XXX - should take care of overlapping needs */
300 } else if (right
== left
) {
301 /* A favor to 2-operand architectures */
302 if ((q
->rewrite
& RRIGHT
) == 0)
306 } else if (o
!= LTYPE
) {
308 need
= MAX(right
, left
) + nreg
;
315 if (TCLASS(p
->n_su
) == 0 && nxreg
== 0) {
316 UDEBUG(("node %p no class\n", p
));
317 p
->n_regw
= NULL
; /* may be set earlier */
322 #define ADCL(n, cl) \
323 for (i = 0; i < n; i++, w++) { w->r_class = cl; \
324 DLIST_INSERT_BEFORE(&initial, w, link); SETNUM(w); \
325 UDEBUG(("Adding " #n " %d\n", w->nodnum)); \
328 #define ADCL(n, cl) \
329 for (i = 0; i < n; i++, w++) { w->r_class = cl; \
330 DLIST_INSERT_BEFORE(&initial, w, link); SETNUM(w); \
334 UDEBUG(("node %p numregs %d\n", p
, nxreg
+1));
335 w
= p
->n_regw
= tmpalloc(sizeof(REGW
) * (nxreg
+1));
336 memset(w
, 0, sizeof(REGW
) * (nxreg
+1));
338 w
->r_class
= TCLASS(p
->n_su
);
340 w
->r_class
= gclass(p
->n_type
);
341 w
->r_nclass
[0] = o
== LTYPE
; /* XXX store leaf info here */
344 DLIST_INSERT_BEFORE(&initial
, w
, link
);
346 UDEBUG(("Adding short %d class %d\n", w
->nodnum
, w
->r_class
));
357 if (q
->rewrite
& RESC1
) {
360 DLIST_REMOVE(w
,link
);
361 } else if (q
->rewrite
& RESC2
) {
364 DLIST_REMOVE(w
,link
);
365 } else if (q
->rewrite
& RESC3
) {
368 DLIST_REMOVE(w
,link
);
371 UDEBUG(("node %p return regs %d\n", p
, need
));
376 #define CLASS(x) (x)->r_class
377 #define NCLASS(x,c) (x)->r_nclass[c]
378 #define ADJLIST(x) (x)->r_adjList
379 #define ALIAS(x) (x)->r_alias
380 #define ONLIST(x) (x)->r_onlist
381 #define MOVELIST(x) (x)->r_moveList
382 #define COLOR(x) (x)->r_color
384 static bittype
*live
;
386 #define PUSHWLIST(w, l) DLIST_INSERT_AFTER(&l, w, link); w->r_onlist = &l
387 #define POPWLIST(l) popwlist(&l);
388 #define DELWLIST(w) DLIST_REMOVE(w, link)
389 #define WLISTEMPTY(h) DLIST_ISEMPTY(&h,link)
390 #define PUSHMLIST(w, l, q) DLIST_INSERT_AFTER(&l, w, link); w->queue = q
391 #define POPMLIST(l) popmlist(&l);
393 #define trivially_colorable(x) \
394 trivially_colorable_p((x)->r_class, (x)->r_nclass)
396 * Determine if a node is trivially colorable ("degree < K").
397 * This implementation is a dumb one, without considering speed.
400 trivially_colorable_p(int c
, int *n
)
405 for (i
= 1; i
< NUMCLASS
+1; i
++)
406 r
[i
] = n
[i
] < regK
[i
] ? n
[i
] : regK
[i
];
409 /* add the exclusion nodes. */
410 /* XXX can we do someything smart here? */
411 /* worst-case for exclusion nodes are better than the `worst-case' */
412 for (; excl
; excl
>>= 1)
419 comperr("trivially_colorable_p");
422 printf("trivially_colorable_p: n[1] %d n[2] %d n[3] %d n[4] "
423 "%d for class %d, triv %d\n", n
[1], n
[2], n
[3], n
[4], c
, i
);
433 while (needs
& NACOUNT
)
435 while (needs
& NBCOUNT
)
437 while (needs
& NCCOUNT
)
439 while (needs
& NDCOUNT
)
441 while (needs
& NECOUNT
)
443 while (needs
& NFCOUNT
)
445 while (needs
& NGCOUNT
)
453 REGW
*w
= DLIST_NEXT(l
, link
);
455 DLIST_REMOVE(w
, link
);
461 * Move lists, a move node is always on only one list.
463 static REGM coalescedMoves
, constrainedMoves
, frozenMoves
,
464 worklistMoves
, activeMoves
;
465 enum { COAL
, CONSTR
, FROZEN
, WLIST
, ACTIVE
};
470 REGM
*w
= DLIST_NEXT(l
, link
);
472 DLIST_REMOVE(w
, link
);
477 * About data structures used in liveness analysis:
479 * The temporaries generated in pass1 are numbered between tempmin and
480 * tempmax. Temporaries generated in pass2 are numbered above tempmax,
481 * so they are sequentially numbered.
483 * Bitfields are used for liveness. Bit arrays are allocated on the
484 * heap for the "live" variable and on the stack for the in, out, gen
485 * and killed variables. Therefore, for a temp number, the bit number must
486 * be biased with tempmin.
488 * There may be an idea to use a different data structure to store
489 * pass2 allocated temporaries, because they are very sparse.
496 RDEBUG(("Liveadd: %d\n", x
));
497 if (x
>= MAXREGS
&& (x
< tempmin
|| x
>= tempmax
))
498 comperr("LIVEADD: out of range");
502 BITSET(live
, (x
-tempmin
+MAXREGS
));
508 RDEBUG(("Livedel: %d\n", x
));
510 if (x
>= MAXREGS
&& (x
< tempmin
|| x
>= tempmax
))
511 comperr("LIVEDEL: out of range");
515 BITCLEAR(live
, (x
-tempmin
+MAXREGS
));
519 (x >= MAXREGS ? BITSET(live, (x-tempmin+MAXREGS)) : BITSET(live, x))
521 (x >= MAXREGS ? BITCLEAR(live, (x-tempmin+MAXREGS)) : BITCLEAR(live, x))
524 static struct lives
{
525 DLIST_ENTRY(lives
) link
;
535 RDEBUG(("LIVEADDR: %d\n", x
->nodnum
));
536 DLIST_FOREACH(l
, &lused
, link
)
540 comperr("LIVEADDR: multiple %d", ASGNUM(x
));
543 if (!DLIST_ISEMPTY(&lunused
, link
)) {
544 l
= DLIST_NEXT(&lunused
, link
);
545 DLIST_REMOVE(l
, link
);
547 l
= tmpalloc(sizeof(struct lives
));
550 DLIST_INSERT_AFTER(&lused
, l
, link
);
559 RDEBUG(("LIVEDELR: %d\n", x
->nodnum
));
561 DLIST_FOREACH(l
, &lused
, link
) {
564 DLIST_REMOVE(l
, link
);
565 DLIST_INSERT_AFTER(&lunused
, l
, link
);
569 comperr("LIVEDELR: %p not found", x
);
573 #define MOVELISTADD(t, p) movelistadd(t, p)
574 #define WORKLISTMOVEADD(s,d) worklistmoveadd(s,d)
577 movelistadd(REGW
*t
, REGM
*p
)
579 MOVL
*w
= tmpalloc(sizeof(MOVL
));
582 w
->next
= t
->r_moveList
;
587 worklistmoveadd(REGW
*src
, REGW
*dst
)
589 REGM
*w
= tmpalloc(sizeof(REGM
));
591 DLIST_INSERT_AFTER(&worklistMoves
, w
, link
);
604 /* Check if a node pair is adjacent */
606 adjSet(REGW
*u
, REGW
*v
)
611 if (ONLIST(u
) == &precolored
) {
612 ADJL
*a
= ADJLIST(v
);
614 * Check if any of the registers that have edges against v
617 for (; a
; a
= a
->r_next
) {
618 if (ONLIST(a
->a_temp
) != &precolored
)
621 if (interferes(t
- ablock
, u
- ablock
))
628 w
= edgehash
[((intptr_t)u
+(intptr_t)v
) & (HASHSZ
-1)];
630 w
= edgehash
[(u
->nodnum
+v
->nodnum
)& (HASHSZ
-1)];
632 for (; w
; w
= w
->next
) {
633 if ((u
== w
->u
&& v
== w
->v
) || (u
== w
->v
&& v
== w
->u
))
639 /* Add a pair to adjset. No check for dups */
641 adjSetadd(REGW
*u
, REGW
*v
)
649 x
= ((intptr_t)u
+(intptr_t)v
) & (HASHSZ
-1);
651 x
= (u
->nodnum
+v
->nodnum
)& (HASHSZ
-1);
653 w
= tmpalloc(sizeof(struct AdjSet
));
655 w
->next
= edgehash
[x
];
660 * Add an interference edge between two nodes.
663 AddEdge(REGW
*u
, REGW
*v
)
668 RRDEBUG(("AddEdge: u %d v %d\n", ASGNUM(u
), ASGNUM(v
)));
672 comperr("AddEdge 0");
674 if (CLASS(u
) == 0 || CLASS(v
) == 0)
675 comperr("AddEdge class == 0 (%d=%d, %d=%d)",
676 CLASS(u
), ASGNUM(u
), CLASS(v
), ASGNUM(v
));
687 if (ONLIST(u
) == &precolored
|| ONLIST(v
) == &precolored
)
688 comperr("precolored node in AddEdge");
691 if (ONLIST(u
) != &precolored
) {
692 x
= tmpalloc(sizeof(ADJL
));
694 x
->r_next
= u
->r_adjList
;
696 NCLASS(u
, CLASS(v
))++;
699 if (ONLIST(v
) != &precolored
) {
700 x
= tmpalloc(sizeof(ADJL
));
702 x
->r_next
= v
->r_adjList
;
704 NCLASS(v
, CLASS(u
))++;
708 RDEBUG(("AddEdge: u %d(d %d) v %d(d %d)\n", u
, DEGREE(u
), v
, DEGREE(v
)));
718 for (l
= MOVELIST(n
); l
; l
= l
->next
) {
720 if (w
->queue
== ACTIVE
|| w
->queue
== WLIST
)
735 DLIST_INIT(&precolored
, link
);
736 DLIST_INIT(&simplifyWorklist
, link
);
737 DLIST_INIT(&freezeWorklist
, link
);
738 DLIST_INIT(&spillWorklist
, link
);
739 DLIST_INIT(&spilledNodes
, link
);
740 DLIST_INIT(&coalescedNodes
, link
);
741 DLIST_INIT(&coloredNodes
, link
);
742 DLIST_INIT(&selectStack
, link
);
745 * Remove all nodes from the initial list and put them on
746 * one of the worklists.
748 while (!DLIST_ISEMPTY(&initial
, link
)) {
749 w
= DLIST_NEXT(&initial
, link
);
750 DLIST_REMOVE(w
, link
);
751 if (!trivially_colorable(w
)) {
752 PUSHWLIST(w
, spillWorklist
);
754 } else if (MoveRelated(w
)) {
755 PUSHWLIST(w
, freezeWorklist
);
758 PUSHWLIST(w
, simplifyWorklist
);
762 RDEBUG(("MkWorklist: spill %d freeze %d simplify %d\n", s
,f
,d
));
772 RDEBUG(("addalledges for %d\n", e
->nodnum
));
775 if (e
->r_class
== -1)
778 if (ONLIST(e
) != &precolored
) {
779 for (i
= 0; ndontregs
[i
] >= 0; i
++)
780 AddEdge(e
, &ablock
[ndontregs
[i
]]);
783 /* First add to long-lived temps and hard regs */
784 RDEBUG(("addalledges longlived "));
785 for (i
= 0; i
< xbits
; i
+= NUMBITS
) {
786 if ((k
= live
[i
/NUMBITS
])) {
790 AddEdge(&ablock
[i
+j
], e
);
792 AddEdge(&nblock
[i
+j
+tempmin
-MAXREGS
],e
);
793 RRDEBUG(("%d ", i
+j
+tempmin
));
797 #if NUMBITS > 32 /* XXX hack for LP64 */
798 k
= (live
[i
/NUMBITS
] >> 32);
801 if (i
+j
+32 < MAXREGS
)
802 AddEdge(&ablock
[i
+j
+32], e
);
804 AddEdge(&nblock
[i
+j
+tempmin
-MAXREGS
+32], e
);
805 RRDEBUG(("%d ", i
+j
+tempmin
+32));
811 /* short-lived temps */
812 RDEBUG(("addalledges shortlived "));
813 DLIST_FOREACH(l
, &lused
, link
) {
815 RRDEBUG(("%d ", ASGNUM(l
->var
)));
823 * Add a move edge between def and use.
826 moveadd(REGW
*def
, REGW
*use
)
832 return; /* no move to itself XXX - ``shouldn't happen'' */
834 RDEBUG(("moveadd: def %d use %d\n", ASGNUM(def
), ASGNUM(use
)));
838 * Check if we are already on move list.
839 * XXX How can that happen ???
841 for (w
= MOVELIST(def
); w
; w
= w
->next
) {
842 if ((w
->regm
->src
== def
&& w
->regm
->dst
== use
) ||
843 (w
->regm
->src
== use
&& w
->regm
->dst
== def
))
844 return; /* already there XXX reverse? */
847 r
= WORKLISTMOVEADD(use
, def
);
853 * Traverse arguments backwards.
854 * XXX - can this be tricked in some other way?
862 insnwalk(p
->n_right
);
868 * Add to (or remove from) live set variables that must not
869 * be clobbered when traversing down on the other leg for
873 setlive(NODE
*p
, int set
, REGW
*rv
)
876 if (rv
->nodnum
< MAXREGS
&&
877 TESTBIT(validregs
, rv
->nodnum
) == 0)
879 set
? LIVEADDR(rv
) : LIVEDELR(rv
);
883 if (p
->n_regw
!= NULL
) {
884 if (p
->n_regw
->nodnum
< MAXREGS
&&
885 TESTBIT(validregs
, p
->n_regw
->nodnum
) == 0)
887 set
? LIVEADDR(p
->n_regw
) : LIVEDELR(p
->n_regw
);
891 switch (optype(p
->n_op
)) {
893 if (p
->n_op
== TEMP
|| VALIDREG(p
))
894 set
? LIVEADD(regno(p
)) : LIVEDEL(regno(p
));
897 setlive(p
->n_right
, set
, rv
);
900 setlive(p
->n_left
, set
, rv
);
906 * Add edges for temporary w against all temporaries that may be
907 * used simultaneously (like index registers).
910 addedge_r(NODE
*p
, REGW
*w
)
912 RRDEBUG(("addedge_r: node %p regw %p\n", p
, w
));
914 if (p
->n_regw
!= NULL
) {
915 if (p
->n_regw
->nodnum
< MAXREGS
&&
916 TESTBIT(validregs
, p
->n_regw
->nodnum
) == 0)
918 AddEdge(p
->n_regw
, w
);
922 if (optype(p
->n_op
) == BITYPE
)
923 addedge_r(p
->n_right
, w
);
924 if (optype(p
->n_op
) != LTYPE
)
925 addedge_r(p
->n_left
, w
);
929 * add/del parameter from live set.
934 int i
, ut
= 0, in
= 0;
938 if (p
->n_op
== ICON
&& p
->n_type
== STRTY
)
941 RDEBUG(("setxarg %p %s\n", p
, p
->n_name
));
942 cw
= xasmcode(p
->n_name
);
957 /* must find all TEMPs/REGs and set them live */
958 if (p
->n_left
->n_op
!= REG
&& p
->n_left
->n_op
!= TEMP
) {
964 i
= regno(p
->n_left
);
965 rw
= p
->n_left
->n_op
== REG
? ablock
: nblock
;
979 comperr("bad ixarg %s", p
->n_name
);
987 * Do the in-tree part of liveness analysis. (the difficult part)
989 * Walk down the tree in reversed-evaluation order (backwards).
990 * The moves and edges inserted and evaluation order for
991 * instructions when code is emitted is described here, hence
992 * this code runs the same but backwards.
994 * 2-op reclaim LEFT: eval L, move to DEST, eval R.
995 * moveadd L,DEST; addedge DEST,R
996 * 2-op reclaim LEFT DORIGHT: eval R, eval L, move to DEST.
997 * moveadd L,DEST; addedge DEST,R; addedge L,R
998 * 2-op reclaim RIGHT; eval L, eval R, move to DEST.
999 * moveadd R,DEST; addedge DEST,L; addedge L,R
1000 * 2-op reclaim RIGHT DORIGHT: eval R, move to DEST, eval L.
1001 * moveadd R,DEST; addedge DEST,L
1002 * 3-op: eval L, eval R
1004 * 3-op DORIGHT: eval R, eval L
1007 * Instructions with special needs are handled just like these variants,
1008 * with the exception of extra added moves and edges.
1009 * Moves to special regs are scheduled after the evaluation of both legs.
1016 struct optab
*q
= &table
[TBLIDX(p
->n_su
)];
1017 REGW
*lr
, *rr
, *rv
, *r
, *rrv
, *lrv
;
1021 RDEBUG(("insnwalk %p\n", p
));
1026 if (p
->n_op
== ASSIGN
&&
1027 (p
->n_left
->n_op
== TEMP
|| VALIDREG(p
->n_left
))) {
1028 lr
= p
->n_left
->n_op
== TEMP
? nblock
: ablock
;
1029 i
= regno(p
->n_left
);
1030 LIVEDEL(i
); /* remove assigned temp from live set */
1031 addalledges(&lr
[i
]);
1034 /* Add edges for the result of this node */
1035 if (rv
&& (q
->visit
& INREGS
|| o
== TEMP
|| VALIDREG(p
)))
1038 /* special handling of CALL operators */
1041 moveadd(rv
, &ablock
[RETREG(p
->n_type
)]);
1042 for (i
= 0; tempregs
[i
] >= 0; i
++)
1043 addalledges(&ablock
[tempregs
[i
]]);
1046 /* for special return value registers add moves */
1047 if ((q
->needs
& NSPECIAL
) && (n
= rspecial(q
, NRES
)) >= 0) {
1049 moveadd(p
->n_regw
, rv
);
1052 /* Check leaves for results in registers */
1053 lr
= optype(o
) != LTYPE
? p
->n_left
->n_regw
: NULL
;
1054 lp
= optype(o
) != LTYPE
? p
->n_left
: NULL
;
1055 rr
= optype(o
) == BITYPE
? p
->n_right
->n_regw
: NULL
;
1056 rp
= optype(o
) == BITYPE
? p
->n_right
: NULL
;
1060 for (i
= 0; i
< n
; i
++) {
1063 { 0, NASL
, NBSL
, NCSL
, NDSL
, NESL
, NFSL
, NGSL
};
1065 { 0, NASR
, NBSR
, NCSR
, NDSR
, NESR
, NFSR
, NGSR
};
1068 /* edges are already added */
1069 if ((r
= &p
->n_regw
[1+i
])->r_class
== -1) {
1072 AddEdge(r
, p
->n_regw
);
1075 if (optype(o
) != LTYPE
&& (q
->needs
& ncl
[CLASS(r
)]) == 0)
1076 addedge_r(p
->n_left
, r
);
1077 if (optype(o
) == BITYPE
&& (q
->needs
& ncr
[CLASS(r
)]) == 0)
1078 addedge_r(p
->n_right
, r
);
1079 for (j
= i
+ 1; j
< n
; j
++) {
1080 if (p
->n_regw
[j
+1].r_class
== -1)
1082 AddEdge(r
, &p
->n_regw
[j
+1]);
1085 if ((r
= &p
->n_regw
[1+i
])->r_class
== -1)
1088 if (optype(o
) != LTYPE
&& (q
->needs
& NASL
) == 0)
1089 addedge_r(p
->n_left
, r
);
1090 if (optype(o
) == BITYPE
&& (q
->needs
& NASR
) == 0)
1091 addedge_r(p
->n_right
, r
);
1096 if (q
->needs
& NSPECIAL
) {
1097 struct rspecial
*rc
;
1098 for (rc
= nspecial(q
); rc
->op
; rc
++) {
1100 #define ONLY(c,s) if (c) s(c, &ablock[rc->num])
1102 addalledges(&ablock
[rc
->num
]);
1106 addedge_r(p
->n_left
, &ablock
[rc
->num
]);
1109 addalledges(&ablock
[rc
->num
]);
1113 addedge_r(p
->n_right
, &ablock
[rc
->num
]);
1116 addalledges(&ablock
[rc
->num
]);
1124 /* avoid use of unhandled registers */
1125 if (p
->n_left
->n_op
== REG
&&
1126 !TESTBIT(validregs
, regno(p
->n_left
)))
1128 if (p
->n_right
->n_op
== REG
&&
1129 !TESTBIT(validregs
, regno(p
->n_right
)))
1131 /* needs special treatment */
1138 } else if (callop(o
)) {
1141 for (c
= livecall(p
); *c
!= -1; c
++) {
1142 addalledges(ablock
+ *c
);
1145 } else if (q
->rewrite
& (RESC1
|RESC2
|RESC3
)) {
1148 } else if (q
->rewrite
& RLEFT
) {
1150 moveadd(rv
, lr
), lrv
= rv
;
1153 } else if (q
->rewrite
& RRIGHT
) {
1155 moveadd(rv
, rr
), rrv
= rv
;
1160 switch (optype(o
)) {
1162 if (p
->n_op
== ASSIGN
&&
1163 (p
->n_left
->n_op
== TEMP
|| p
->n_left
->n_op
== REG
)) {
1164 /* only go down right node */
1165 insnwalk(p
->n_right
);
1166 } else if (callop(o
)) {
1167 insnwalk(p
->n_left
);
1168 /* Do liveness analysis on arguments (backwards) */
1169 argswalk(p
->n_right
);
1170 } else if ((p
->n_su
& DORIGHT
) == 0) {
1171 setlive(p
->n_left
, 1, lrv
);
1172 insnwalk(p
->n_right
);
1173 setlive(p
->n_left
, 0, lrv
);
1174 insnwalk(p
->n_left
);
1176 setlive(p
->n_right
, 1, rrv
);
1177 insnwalk(p
->n_left
);
1178 setlive(p
->n_right
, 0, rrv
);
1179 insnwalk(p
->n_right
);
1184 insnwalk(p
->n_left
);
1190 if (!TESTBIT(validregs
, regno(p
)))
1191 break; /* never add moves */
1195 rr
= (o
== TEMP
? &nblock
[i
] : &ablock
[i
]);
1203 case OREG
: /* XXX - not yet */
1213 static bittype
**gen
, **killed
, **in
, **out
;
1216 SLIST_ENTRY(notspill
) link
;
1219 SLIST_HEAD(, notspill
) nothead
;
1224 struct notspill
*nsp
;
1226 SLIST_FOREACH(nsp
, ¬head
, link
)
1227 if (nsp
->spnum
== n
)
1235 struct notspill
*nsp
;
1239 nsp
= tmpalloc(sizeof(struct notspill
));
1241 SLIST_INSERT_LAST(¬head
, nsp
, link
);
1245 * Found an extended assembler node, so growel out gen/killed nodes.
1248 xasmionize(NODE
*p
, void *arg
)
1250 int bb
= *(int *)arg
;
1253 if (p
->n_op
== ICON
&& p
->n_type
== STRTY
)
1254 return; /* dummy end marker */
1256 cw
= xasmcode(p
->n_name
);
1257 if (XASMVAL(cw
) == 'n' /* || XASMVAL(cw) == 'm' */)
1258 return; /* no flow analysis */
1261 if (XASMVAL(cw
) == 'g' && p
->n_op
!= TEMP
&& p
->n_op
!= REG
)
1262 return; /* no flow analysis */
1265 if (XASMVAL(cw
) == 'r' && p
->n_op
== TEMP
)
1267 if (XASMVAL(cw
) == 'm') {
1268 if (p
->n_op
== UMUL
&& p
->n_left
->n_op
== TEMP
) {
1275 #define MKTOFF(r) ((r) - tempmin + MAXREGS)
1276 if (XASMISOUT(cw
)) {
1277 if (p
->n_op
== TEMP
) {
1278 BITCLEAR(gen
[bb
], MKTOFF(b
));
1279 BITSET(killed
[bb
], MKTOFF(b
));
1280 } else if (p
->n_op
== REG
) {
1281 BITCLEAR(gen
[bb
], b
);
1282 BITSET(killed
[bb
], b
);
1284 uerror("bad xasm node type %d", p
->n_op
);
1286 if (XASMISINP(cw
)) {
1287 if (p
->n_op
== TEMP
) {
1288 BITSET(gen
[bb
], MKTOFF(b
));
1289 } else if (p
->n_op
== REG
) {
1291 } else if (optype(p
->n_op
) != LTYPE
) {
1292 if (XASMVAL(cw
) == 'r')
1293 uerror("couldn't find available register");
1295 uerror("bad xasm node type2");
1300 #ifndef XASMCONSTREGS
1301 #define XASMCONSTREGS(x) (-1)
1305 * Check that given constraints are valid.
1308 xasmconstr(NODE
*p
, void *arg
)
1312 if (p
->n_op
== ICON
&& p
->n_type
== STRTY
)
1313 return; /* no constraints */
1315 if (strcmp(p
->n_name
, "cc") == 0 || strcmp(p
->n_name
, "memory") == 0)
1318 for (i
= 0; i
< MAXREGS
; i
++)
1319 if (strcmp(rnames
[i
], p
->n_name
) == 0) {
1320 addalledges(&ablock
[i
]);
1323 if ((i
= XASMCONSTREGS(p
->n_name
)) < 0)
1324 comperr("unsupported xasm constraint %s", p
->n_name
);
1325 addalledges(&ablock
[i
]);
1328 #define RUP(x) (((x)+NUMBITS-1)/NUMBITS)
1329 #define SETCOPY(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] = f[i]
1330 #define SETSET(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] |= f[i]
1331 #define SETCLEAR(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] &= ~f[i]
1332 #define SETCMP(v,t,f,i,n) for (i = 0; i < RUP(n); i++) \
1333 if (t[i] != f[i]) v = 1
1334 #define SETEMPTY(t,sz) memset(t, 0, BIT2BYTE(sz))
1337 deldead(NODE
*p
, bittype
*lvar
)
1342 #define BNO(p) (regno(p) - tempmin+MAXREGS)
1343 if (p
->n_op
== TEMP
)
1344 BITSET(lvar
, BNO(p
));
1345 if (asgop(p
->n_op
) && p
->n_left
->n_op
== TEMP
&&
1346 TESTBIT(lvar
, BNO(p
->n_left
)) == 0) {
1348 * Not live, must delete the right tree at least
1349 * down to next statement with side effects.
1351 BDEBUG(("DCE deleting temp %d\n", regno(p
->n_left
)));
1358 ty
= optype(p
->n_op
);
1360 rv
|= deldead(p
->n_left
, lvar
);
1362 rv
|= deldead(p
->n_right
, lvar
);
1367 * Do dead code elimination.
1370 dce(struct p2env
*p2e
)
1372 extern struct interpass prepole
;
1373 struct basicblock
*bb
;
1374 struct interpass
*ip
;
1377 int i
, bbnum
, fix
= 0;
1379 BDEBUG(("Entering DCE\n"));
1381 * Traverse over the basic blocks.
1382 * if an assignment is found that writes to a temporary
1383 * that is not live out, remove that assignment and its legs.
1385 DLIST_INIT(&prepole
, qelem
);
1386 BITALLOC(lvar
, tmpalloc
, xbits
);
1387 DLIST_FOREACH(bb
, &p2e
->bblocks
, bbelem
) {
1389 BBDEBUG(("DCE bblock %d, start %p last %p\n",
1390 bbnum
, bb
->first
, bb
->last
));
1391 SETCOPY(lvar
, out
[bbnum
], i
, xbits
);
1392 for (ip
= bb
->last
; ; ip
= DLIST_PREV(ip
, qelem
)) {
1393 if (ip
->type
== IP_NODE
&& deldead(ip
->ip_node
, lvar
)) {
1394 if ((p
= deluseless(ip
->ip_node
)) == NULL
) {
1395 struct interpass
*previp
;
1396 struct basicblock
*prevbb
;
1398 if (ip
== bb
->first
&& ip
== bb
->last
) {
1399 /* Remove basic block */
1400 previp
= DLIST_PREV(ip
, qelem
);
1401 DLIST_REMOVE(ip
, qelem
);
1402 prevbb
= DLIST_PREV(bb
, bbelem
);
1403 DLIST_REMOVE(bb
, bbelem
);
1405 } else if (ip
== bb
->first
) {
1407 DLIST_NEXT(ip
, qelem
);
1408 DLIST_REMOVE(ip
, qelem
);
1409 } else if (ip
== bb
->last
) {
1410 previp
= DLIST_PREV(ip
, qelem
);
1411 DLIST_REMOVE(ip
, qelem
);
1413 bb
= DLIST_PREV(bb
, bbelem
);
1415 previp
= DLIST_NEXT(ip
, qelem
);
1416 DLIST_REMOVE(ip
, qelem
);
1422 BDEBUG(("bb %d: DCE ip %p deleted\n",
1425 } else while (!DLIST_ISEMPTY(&prepole
, qelem
)) {
1427 BDEBUG(("bb %d: DCE doing ip prepend\n", bbnum
));
1429 struct interpass
*tipp
;
1430 tipp
= DLIST_NEXT(&prepole
, qelem
);
1431 DLIST_REMOVE(tipp
, qelem
);
1432 DLIST_INSERT_BEFORE(ip
, tipp
, qelem
);
1433 if (ip
== bb
->first
)
1437 comperr("dce needs bb fixup");
1439 BDEBUG(("DCE ip prepended\n"));
1441 if (ip
->type
== IP_NODE
) {
1447 if (ip
== bb
->first
)
1451 BDEBUG(("DCE fix %d\n", fix
));
1456 * Set/clear long term liveness for regs and temps.
1459 unionize(NODE
*p
, int bb
)
1463 if ((o
= p
->n_op
) == TEMP
) {
1465 for (i
= 0; i
< szty(p
->n_type
); i
++) {
1466 BITSET(gen
[bb
], (regno(p
) - tempmin
+i
+MAXREGS
));
1470 BITSET(gen
[bb
], (regno(p
) - tempmin
+i
+MAXREGS
));
1472 } else if (VALIDREG(p
)) {
1473 BITSET(gen
[bb
], regno(p
));
1476 if (p
->n_left
->n_op
== TEMP
) {
1477 int b
= regno(p
->n_left
) - tempmin
+MAXREGS
;
1479 for (i
= 0; i
< szty(p
->n_type
); i
++) {
1480 BITCLEAR(gen
[bb
], (b
+i
));
1481 BITSET(killed
[bb
], (b
+i
));
1485 BITCLEAR(gen
[bb
], (b
+i
));
1486 BITSET(killed
[bb
], (b
+i
));
1488 unionize(p
->n_right
, bb
);
1490 } else if (VALIDREG(p
->n_left
)) {
1491 int b
= regno(p
->n_left
);
1492 BITCLEAR(gen
[bb
], b
);
1493 BITSET(killed
[bb
], b
);
1494 unionize(p
->n_right
, bb
);
1500 unionize(p
->n_left
, bb
);
1502 unionize(p
->n_right
, bb
);
1506 * Do variable liveness analysis. Only analyze the long-lived
1507 * variables, and save the live-on-exit temporaries in a bit-field
1508 * at the end of each basic block. This bit-field is later used
1509 * when doing short-range liveness analysis in Build().
1512 LivenessAnalysis(struct p2env
*p2e
)
1514 struct basicblock
*bb
;
1515 struct interpass
*ip
;
1519 * generate the gen-killed sets for all basic blocks.
1521 DLIST_FOREACH(bb
, &p2e
->bblocks
, bbelem
) {
1523 for (ip
= bb
->last
; ; ip
= DLIST_PREV(ip
, qelem
)) {
1524 /* gen/killed is 'p', this node is 'n' */
1525 if (ip
->type
== IP_NODE
) {
1526 if (ip
->ip_node
->n_op
== XASM
)
1527 flist(ip
->ip_node
->n_left
,
1528 xasmionize
, &bbnum
);
1530 unionize(ip
->ip_node
, bbnum
);
1532 if (ip
== bb
->first
)
1535 memcpy(in
[bbnum
], gen
[bbnum
], BIT2BYTE(xbits
));
1537 #define PRTRG(x) printf("%d ", i < MAXREGS ? i : i + tempmin-MAXREGS)
1539 printf("basic block %d\ngen: ", bbnum
);
1540 for (i
= 0; i
< xbits
; i
++)
1541 if (TESTBIT(gen
[bbnum
], i
))
1543 printf("\nkilled: ");
1544 for (i
= 0; i
< xbits
; i
++)
1545 if (TESTBIT(killed
[bbnum
], i
))
1554 * Build the set of interference edges and adjacency list.
1557 Build(struct p2env
*p2e
)
1559 struct interpass
*ipole
= &p2e
->ipole
;
1560 struct basicblock bbfake
;
1561 struct interpass
*ip
;
1562 struct basicblock
*bb
;
1568 * No basic block splitup is done if not optimizing,
1569 * so fake one basic block to keep the liveness analysis
1574 bbfake
.last
= DLIST_PREV(ipole
, qelem
);
1575 bbfake
.first
= DLIST_NEXT(ipole
, qelem
);
1576 DLIST_INIT(&p2e
->bblocks
, bbelem
);
1577 DLIST_INSERT_AFTER(&p2e
->bblocks
, &bbfake
, bbelem
);
1578 bbfake
.ch
[0] = bbfake
.ch
[1] = NULL
;
1581 /* Just fetch space for the temporaries from stack */
1582 gen
= tmpalloc(p2e
->nbblocks
*sizeof(bittype
*));
1583 killed
= tmpalloc(p2e
->nbblocks
*sizeof(bittype
*));
1584 in
= tmpalloc(p2e
->nbblocks
*sizeof(bittype
*));
1585 out
= tmpalloc(p2e
->nbblocks
*sizeof(bittype
*));
1586 for (i
= 0; i
< p2e
->nbblocks
; i
++) {
1587 BITALLOC(gen
[i
],tmpalloc
,xbits
);
1588 BITALLOC(killed
[i
],tmpalloc
,xbits
);
1589 BITALLOC(in
[i
],tmpalloc
,xbits
);
1590 BITALLOC(out
[i
],tmpalloc
,xbits
);
1592 BITALLOC(saved
,tmpalloc
,xbits
);
1594 SLIST_INIT(¬head
);
1596 LivenessAnalysis(p2e
);
1598 /* register variable temporaries are live */
1599 for (i
= 0; i
< NPERMREG
-1; i
++) {
1602 BITSET(out
[p2e
->nbblocks
-1], (i
+MAXREGS
));
1603 for (j
= i
+1; j
< NPERMREG
-1; j
++) {
1606 AddEdge(&nblock
[i
+tempmin
], &nblock
[j
+tempmin
]);
1610 /* do liveness analysis on basic block level */
1613 /* XXX - loop should be in reversed execution-order */
1614 DLIST_FOREACH_REVERSE(bb
, &p2e
->bblocks
, bbelem
) {
1616 SETCOPY(saved
, out
[i
], j
, xbits
);
1618 SETSET(out
[i
], in
[bb
->ch
[0]->bblock
->bbnum
], j
, xbits
);
1620 SETSET(out
[i
], in
[bb
->ch
[1]->bblock
->bbnum
], j
, xbits
);
1621 SETCMP(again
, saved
, out
[i
], j
, xbits
);
1622 SETCOPY(saved
, in
[i
], j
, xbits
);
1623 SETCOPY(in
[i
], out
[i
], j
, xbits
);
1624 SETCLEAR(in
[i
], killed
[i
], j
, xbits
);
1625 SETSET(in
[i
], gen
[i
], j
, xbits
);
1626 SETCMP(again
, saved
, in
[i
], j
, xbits
);
1632 DLIST_FOREACH(bb
, &p2e
->bblocks
, bbelem
) {
1633 printf("basic block %d\nin: ", bb
->bbnum
);
1634 for (i
= 0; i
< xbits
; i
++)
1635 if (TESTBIT(in
[bb
->bbnum
], i
))
1638 for (i
= 0; i
< xbits
; i
++)
1639 if (TESTBIT(out
[bb
->bbnum
], i
))
1645 if (xtemps
&& xdce
) {
1647 * Do dead code elimination by using live out.
1648 * Ignores if any variable read from is marked volatile,
1649 * but what it should do is unspecified anyway.
1650 * Liveness Analysis should be done in optim2 instead.
1652 * This should recalculate the basic block structure.
1655 /* Clear bitfields */
1656 for (i
= 0; i
< p2e
->nbblocks
; i
++) {
1657 SETEMPTY(gen
[i
],xbits
);
1658 SETEMPTY(killed
[i
],xbits
);
1659 SETEMPTY(in
[i
],xbits
);
1660 SETEMPTY(out
[i
],xbits
);
1662 SETEMPTY(saved
,xbits
);
1667 DLIST_FOREACH(bb
, &p2e
->bblocks
, bbelem
) {
1668 RDEBUG(("liveadd bb %d\n", bb
->bbnum
));
1670 for (j
= 0; j
< xbits
; j
+= NUMBITS
)
1671 live
[j
/NUMBITS
] = 0;
1672 SETCOPY(live
, out
[i
], j
, xbits
);
1673 for (ip
= bb
->last
; ; ip
= DLIST_PREV(ip
, qelem
)) {
1674 if (ip
->type
== IP_NODE
) {
1675 if (ip
->ip_node
->n_op
== XASM
) {
1676 flist(ip
->ip_node
->n_right
,
1678 listf(ip
->ip_node
->n_left
, setxarg
);
1680 insnwalk(ip
->ip_node
);
1682 if (ip
== bb
->first
)
1694 printf("Interference edges\n");
1695 for (i
= 0; i
< HASHSZ
; i
++) {
1696 if ((w
= edgehash
[i
]) == NULL
)
1698 for (; w
; w
= w
->next
)
1699 printf("%d <-> %d\n", ASGNUM(w
->u
), ASGNUM(w
->v
));
1701 printf("Degrees\n");
1702 DLIST_FOREACH(y
, &initial
, link
) {
1703 printf("%d (%c): trivial [%d] ", ASGNUM(y
),
1704 CLASS(y
)+'@', trivially_colorable(y
));
1706 for (x
= ADJLIST(y
); x
; x
= x
->r_next
) {
1707 if (ONLIST(x
->a_temp
) != &selectStack
&&
1708 ONLIST(x
->a_temp
) != &coalescedNodes
)
1709 printf("%d ", ASGNUM(x
->a_temp
));
1711 printf("(%d) ", ASGNUM(x
->a_temp
));
1714 printf(": n=%d\n", i
);
1716 printf("Move nodes\n");
1717 DLIST_FOREACH(y
, &initial
, link
) {
1718 if (MOVELIST(y
) == NULL
)
1720 printf("%d: ", ASGNUM(y
));
1721 for (m
= MOVELIST(y
); m
; m
= m
->next
) {
1722 REGW
*yy
= m
->regm
->src
== y
?
1723 m
->regm
->dst
: m
->regm
->src
;
1724 printf("%d ", ASGNUM(yy
));
1734 EnableMoves(REGW
*n
)
1739 for (l
= MOVELIST(n
); l
; l
= l
->next
) {
1741 if (m
->queue
!= ACTIVE
)
1743 DLIST_REMOVE(m
, link
);
1744 PUSHMLIST(m
, worklistMoves
, WLIST
);
1749 EnableAdjMoves(REGW
*nodes
)
1755 for (w
= ADJLIST(nodes
); w
; w
= w
->r_next
) {
1757 if (ONLIST(n
) == &selectStack
|| ONLIST(n
) == &coalescedNodes
)
1759 EnableMoves(w
->a_temp
);
1764 * Decrement the degree of node w for class c.
1767 DecrementDegree(REGW
*w
, int c
)
1772 RRDEBUG(("DecrementDegree: w %d, c %d\n", ASGNUM(w
), c
));
1775 wast
= trivially_colorable(w
);
1777 if (wast
== trivially_colorable(w
))
1783 if (MoveRelated(w
)) {
1784 PUSHWLIST(w
, freezeWorklist
);
1786 PUSHWLIST(w
, simplifyWorklist
);
1796 w
= POPWLIST(simplifyWorklist
);
1797 PUSHWLIST(w
, selectStack
);
1799 RDEBUG(("Simplify: node %d class %d\n", ASGNUM(w
), w
->r_class
));
1803 for (; l
; l
= l
->r_next
) {
1804 if (ONLIST(l
->a_temp
) == &selectStack
||
1805 ONLIST(l
->a_temp
) == &coalescedNodes
)
1807 DecrementDegree(l
->a_temp
, w
->r_class
);
1814 if (ONLIST(n
) == &coalescedNodes
)
1815 return GetAlias(ALIAS(n
));
1820 OK(REGW
*t
, REGW
*r
)
1823 RDEBUG(("OK: t %d CLASS(t) %d adjSet(%d,%d)=%d\n",
1824 ASGNUM(t
), CLASS(t
), ASGNUM(t
), ASGNUM(r
), adjSet(t
, r
)));
1829 printf("OK degree: ");
1830 for (w
= ADJLIST(t
); w
; w
= w
->r_next
) {
1831 if (ONLIST(w
->a_temp
) != &selectStack
&&
1832 ONLIST(w
->a_temp
) != &coalescedNodes
)
1833 printf("%c%d ", CLASS(w
->a_temp
)+'@',
1834 ASGNUM(w
->a_temp
)), ndeg
++;
1836 printf("(%d) ", ASGNUM(w
->a_temp
));
1840 if (ndeg
!= DEGREE(t
) && DEGREE(t
) >= 0)
1841 printf("!!!ndeg %d != DEGREE(t) %d\n", ndeg
, DEGREE(t
));
1846 if (trivially_colorable(t
) || ONLIST(t
) == &precolored
||
1847 (adjSet(t
, r
) || !aliasmap(CLASS(t
), COLOR(r
))))/* XXX - check aliasmap */
1853 adjok(REGW
*v
, REGW
*u
)
1858 RDEBUG(("adjok\n"));
1859 for (w
= ADJLIST(v
); w
; w
= w
->r_next
) {
1861 if (ONLIST(t
) == &selectStack
|| ONLIST(t
) == &coalescedNodes
)
1866 RDEBUG(("adjok returns OK\n"));
1871 * Do a conservative estimation of whether two temporaries can
1872 * be coalesced. This is "Briggs-style" check.
1873 * Neither u nor v is precolored when called.
1876 Conservative(REGW
*u
, REGW
*v
)
1880 int xncl
[NUMCLASS
+1], mcl
= 0, j
;
1882 for (j
= 0; j
< NUMCLASS
+1; j
++)
1885 * Increment xncl[class] up to K for each class.
1886 * If all classes has reached K then check colorability and return.
1888 for (w
= ADJLIST(u
); w
; w
= w
->r_next
) {
1890 if (ONLIST(n
) == &selectStack
|| ONLIST(n
) == &coalescedNodes
)
1892 if (xncl
[CLASS(n
)] == regK
[CLASS(n
)])
1894 if (!trivially_colorable(n
) || ONLIST(n
) == &precolored
)
1896 if (xncl
[CLASS(n
)] < regK
[CLASS(n
)])
1898 if (++mcl
== NUMCLASS
)
1899 goto out
; /* cannot get more out of it */
1901 for (w
= ADJLIST(v
); w
; w
= w
->r_next
) {
1903 if (ONLIST(n
) == &selectStack
|| ONLIST(n
) == &coalescedNodes
)
1905 if (xncl
[CLASS(n
)] == regK
[CLASS(n
)])
1907 /* ugly: have we been here already? */
1908 for (ww
= ADJLIST(u
); ww
; ww
= ww
->r_next
)
1909 if (ww
->a_temp
== n
)
1913 if (!trivially_colorable(n
) || ONLIST(n
) == &precolored
)
1915 if (xncl
[CLASS(n
)] < regK
[CLASS(n
)])
1917 if (++mcl
== NUMCLASS
)
1920 out
: j
= trivially_colorable_p(CLASS(u
), xncl
);
1925 AddWorkList(REGW
*w
)
1928 if (ONLIST(w
) != &precolored
&& !MoveRelated(w
) &&
1929 trivially_colorable(w
)) {
1931 PUSHWLIST(w
, simplifyWorklist
);
1936 Combine(REGW
*u
, REGW
*v
)
1943 RDEBUG(("Combine (%d,%d)\n", ASGNUM(u
), ASGNUM(v
)));
1946 if (ONLIST(v
) == &freezeWorklist
) {
1951 PUSHWLIST(v
, coalescedNodes
);
1955 printf("adjlist(%d): ", ASGNUM(v
));
1956 for (l
= ADJLIST(v
); l
; l
= l
->r_next
)
1957 printf("%d ", l
->a_temp
->nodnum
);
1963 MOVL
*m0
= MOVELIST(v
);
1965 for (m0
= MOVELIST(v
); m0
; m0
= m0
->next
) {
1966 for (m
= MOVELIST(u
); m
; m
= m
->next
)
1967 if (m
->regm
== m0
->regm
)
1968 break; /* Already on list */
1970 continue; /* already on list */
1971 MOVELISTADD(u
, m0
->regm
);
1976 if ((m
= MOVELIST(u
))) {
1979 m
->next
= MOVELIST(v
);
1981 MOVELIST(u
) = MOVELIST(v
);
1984 for (l
= ADJLIST(v
); l
; l
= l
->r_next
) {
1986 if (ONLIST(t
) == &selectStack
|| ONLIST(t
) == &coalescedNodes
)
1988 /* Do not add edge if u cannot affect the colorability of t */
1989 /* XXX - check aliasmap */
1990 if (ONLIST(u
) != &precolored
|| aliasmap(CLASS(t
), COLOR(u
)))
1992 DecrementDegree(t
, CLASS(v
));
1994 if (!trivially_colorable(u
) && ONLIST(u
) == &freezeWorklist
) {
1996 PUSHWLIST(u
, spillWorklist
);
2001 printf("Combine %d class (%d): ", ASGNUM(u
), CLASS(u
));
2002 for (w
= ADJLIST(u
); w
; w
= w
->r_next
) {
2003 if (ONLIST(w
->a_temp
) != &selectStack
&&
2004 ONLIST(w
->a_temp
) != &coalescedNodes
)
2005 printf("%d ", ASGNUM(w
->a_temp
));
2007 printf("(%d) ", ASGNUM(w
->a_temp
));
2018 REGW
*x
, *y
, *u
, *v
;
2020 m
= POPMLIST(worklistMoves
);
2021 x
= GetAlias(m
->src
);
2022 y
= GetAlias(m
->dst
);
2024 if (ONLIST(y
) == &precolored
)
2030 RDEBUG(("Coalesce: src %d dst %d u %d v %d x %d y %d\n",
2031 ASGNUM(m
->src
), ASGNUM(m
->dst
), ASGNUM(u
), ASGNUM(v
),
2032 ASGNUM(x
), ASGNUM(y
)));
2035 if (CLASS(m
->src
) != CLASS(m
->dst
))
2036 comperr("Coalesce: src class %d, dst class %d",
2037 CLASS(m
->src
), CLASS(m
->dst
));
2040 RDEBUG(("Coalesce: u == v\n"));
2041 PUSHMLIST(m
, coalescedMoves
, COAL
);
2043 } else if (ONLIST(v
) == &precolored
|| adjSet(u
, v
)) {
2044 RDEBUG(("Coalesce: constrainedMoves\n"));
2045 PUSHMLIST(m
, constrainedMoves
, CONSTR
);
2048 } else if ((ONLIST(u
) == &precolored
&& adjok(v
, u
)) ||
2049 (ONLIST(u
) != &precolored
&& Conservative(u
, v
))) {
2050 RDEBUG(("Coalesce: Conservative\n"));
2051 PUSHMLIST(m
, coalescedMoves
, COAL
);
2055 RDEBUG(("Coalesce: activeMoves\n"));
2056 PUSHMLIST(m
, activeMoves
, ACTIVE
);
2061 FreezeMoves(REGW
*u
)
2068 for (w
= MOVELIST(u
); w
; w
= w
->next
) {
2070 if (m
->queue
!= WLIST
&& m
->queue
!= ACTIVE
)
2074 if (GetAlias(y
) == GetAlias(u
))
2079 RDEBUG(("FreezeMoves: u %d (%d,%d) v %d\n",
2080 ASGNUM(u
),ASGNUM(x
),ASGNUM(y
),ASGNUM(v
)));
2082 DLIST_REMOVE(m
, link
);
2083 PUSHMLIST(m
, frozenMoves
, FROZEN
);
2084 if (ONLIST(v
) != &freezeWorklist
)
2086 for (o
= MOVELIST(v
); o
; o
= o
->next
)
2087 if (o
->regm
->queue
== WLIST
|| o
->regm
->queue
== ACTIVE
)
2092 PUSHWLIST(z
, simplifyWorklist
);
2104 * Check if the moves to freeze have exactly the same
2105 * interference edges. If they do, coalesce them instead, it
2106 * may free up other nodes that they interfere with.
2110 * Select nodes to freeze first by using following criteria:
2111 * - Trivially colorable
2112 * - Single or few moves to less trivial nodes.
2114 DLIST_FOREACH(u
, &freezeWorklist
, link
) {
2115 if (u
>= &nblock
[tempmax
] || u
< &nblock
[tempmin
])
2116 continue; /* No short range temps */
2117 if (!trivially_colorable(u
))
2118 continue; /* Prefer colorable nodes */
2119 /* Check for at most two move-related nodes */
2120 if (u
->r_moveList
->next
&& u
->r_moveList
->next
->next
)
2122 /* Ok, remove node */
2123 DLIST_REMOVE(u
, link
);
2127 if (u
== &freezeWorklist
) /* Nothing matched criteria, just take one */
2128 u
= POPWLIST(freezeWorklist
);
2129 PUSHWLIST(u
, simplifyWorklist
);
2131 RDEBUG(("Freeze %d\n", ASGNUM(u
)));
2141 RDEBUG(("SelectSpill\n"));
2144 DLIST_FOREACH(w
, &spillWorklist
, link
)
2145 printf("SelectSpill: %d\n", ASGNUM(w
));
2148 /* First check if we can spill register variables */
2149 DLIST_FOREACH(w
, &spillWorklist
, link
) {
2150 if (w
>= &nblock
[tempmin
] && w
< &nblock
[basetemp
])
2154 if (w
== &spillWorklist
) {
2155 /* try to find another long-range variable */
2156 DLIST_FOREACH(w
, &spillWorklist
, link
) {
2157 if (innotspill(w
- nblock
))
2159 if (w
>= &nblock
[tempmin
] && w
< &nblock
[tempmax
])
2164 if (w
== &spillWorklist
) {
2165 /* no heuristics, just fetch first element */
2166 /* but not if leaf */
2167 DLIST_FOREACH(w
, &spillWorklist
, link
) {
2168 if (w
->r_nclass
[0] == 0)
2173 if (w
== &spillWorklist
) {
2174 /* Eh, only leaves :-/ Try anyway */
2175 /* May not be useable */
2176 w
= DLIST_NEXT(&spillWorklist
, link
);
2179 DLIST_REMOVE(w
, link
);
2181 PUSHWLIST(w
, simplifyWorklist
);
2183 RDEBUG(("Freezing node %d\n", ASGNUM(w
)));
2189 * Set class on long-lived temporaries based on its type.
2192 traclass(NODE
*p
, void *arg
)
2196 if (p
->n_op
!= TEMP
)
2199 nb
= &nblock
[regno(p
)];
2201 CLASS(nb
) = gclass(p
->n_type
);
2205 paint(NODE
*p
, void *arg
)
2212 /* XXX - trashes rewrite of trees (short) */
2213 if (!DLIST_ISEMPTY(&spilledNodes
, link
)) {
2218 if (p
->n_regw
!= NULL
) {
2219 /* Must color all allocated regs also */
2221 q
= &table
[TBLIDX(p
->n_su
)];
2222 p
->n_reg
= COLOR(w
);
2224 if (q
->needs
& ALLNEEDS
)
2225 for (i
= 0; i
< ncnt(q
->needs
); i
++) {
2226 if (w
->r_class
== -1)
2227 p
->n_reg
|= ENCRA(COLOR(ww
), i
);
2229 p
->n_reg
|= ENCRA(COLOR(w
), i
);
2234 if (p
->n_op
== TEMP
) {
2235 REGW
*nb
= &nblock
[regno(p
)];
2236 regno(p
) = COLOR(nb
);
2237 if (TCLASS(p
->n_su
) == 0)
2238 SCLASS(p
->n_su
, CLASS(nb
));
2245 * See if this node have a move that has been removed in Freeze
2246 * but as we can make use of anyway.
2249 colfind(int okColors
, REGW
*r
)
2255 for (m
= MOVELIST(r
); m
; m
= m
->next
) {
2256 if ((w
= m
->regm
->src
) == r
)
2259 if (ONLIST(w
) != &coloredNodes
&& ONLIST(w
) != &precolored
)
2260 continue; /* Not yet colored */
2261 c
= aliasmap(CLASS(w
), COLOR(w
));
2262 if ((c
& okColors
) == 0) {
2263 RDEBUG(("colfind: Failed coloring from %d\n", ASGNUM(w
)));
2267 RDEBUG(("colfind: Recommend color from %d\n", ASGNUM(w
)));
2271 return ffs(okColors
)-1;
2275 AssignColors(struct interpass
*ip
)
2277 struct interpass
*ip2
;
2282 RDEBUG(("AssignColors\n"));
2283 while (!WLISTEMPTY(selectStack
)) {
2284 w
= POPWLIST(selectStack
);
2285 okColors
= classmask(CLASS(w
));
2287 RDEBUG(("classmask av %d, class %d: %x\n",
2288 w
->nodnum
, CLASS(w
), okColors
));
2291 for (x
= ADJLIST(w
); x
; x
= x
->r_next
) {
2292 o
= GetAlias(x
->a_temp
);
2294 RRDEBUG(("Adj(%d): %d (%d)\n",
2295 ASGNUM(w
), ASGNUM(o
), ASGNUM(x
->a_temp
)));
2298 if (ONLIST(o
) == &coloredNodes
||
2299 ONLIST(o
) == &precolored
) {
2300 c
= aliasmap(CLASS(w
), COLOR(o
));
2301 RRDEBUG(("aliasmap in class %d by color %d: "
2302 "%x, okColors %x\n",
2303 CLASS(w
), COLOR(o
), c
, okColors
));
2308 if (okColors
== 0) {
2309 PUSHWLIST(w
, spilledNodes
);
2311 RDEBUG(("Spilling node %d\n", ASGNUM(w
)));
2314 c
= colfind(okColors
, w
);
2315 COLOR(w
) = color2reg(c
, CLASS(w
));
2316 PUSHWLIST(w
, coloredNodes
);
2318 RDEBUG(("Coloring %d with %s, free %x\n",
2319 ASGNUM(w
), rnames
[COLOR(w
)], okColors
));
2323 DLIST_FOREACH(w
, &coalescedNodes
, link
) {
2324 REGW
*ww
= GetAlias(w
);
2325 COLOR(w
) = COLOR(ww
);
2326 if (ONLIST(ww
) == &spilledNodes
) {
2328 RDEBUG(("coalesced node %d spilled\n", w
->nodnum
));
2330 ww
= DLIST_PREV(w
, link
);
2331 DLIST_REMOVE(w
, link
);
2332 PUSHWLIST(w
, spilledNodes
);
2336 RDEBUG(("Giving coalesced node %d color %s\n",
2337 w
->nodnum
, rnames
[COLOR(w
)]));
2344 DLIST_FOREACH(w
, &coloredNodes
, link
)
2345 printf("%d: color %s\n", ASGNUM(w
), rnames
[COLOR(w
)]);
2347 if (DLIST_ISEMPTY(&spilledNodes
, link
)) {
2348 DLIST_FOREACH(ip2
, ip
, qelem
)
2349 if (ip2
->type
== IP_NODE
)
2350 walkf(ip2
->ip_node
, paint
, 0);
2356 * Store all spilled nodes in memory by fetching a temporary on the stack.
2357 * Will never end up here if not optimizing.
2360 longtemp(NODE
*p
, void *arg
)
2365 if (p
->n_op
!= TEMP
)
2367 /* XXX - should have a bitmask to find temps to convert */
2368 DLIST_FOREACH(w
, spole
, link
) {
2369 if (w
!= &nblock
[regno(p
)])
2371 if (w
->r_class
== 0) {
2372 w
->r_color
= BITOOR(freetemp(szty(p
->n_type
)));
2375 l
= mklnode(REG
, 0, FPREG
, INCREF(p
->n_type
));
2376 r
= mklnode(ICON
, w
->r_color
, 0, INT
);
2377 p
->n_left
= mkbinode(PLUS
, l
, r
, INCREF(p
->n_type
));
2384 static struct interpass
*cip
;
2386 * Rewrite a tree by storing a variable in memory.
2387 * XXX - must check if basic block structure is destroyed!
2390 shorttemp(NODE
*p
, void *arg
)
2392 struct interpass
*nip
;
2398 /* XXX - optimize this somewhat */
2399 DLIST_FOREACH(w
, spole
, link
) {
2402 /* XXX - use canaddr() */
2403 if (p
->n_op
== OREG
|| p
->n_op
== NAME
) {
2404 DLIST_REMOVE(w
, link
);
2406 RDEBUG(("Node %d already in memory\n", ASGNUM(w
)));
2411 RDEBUG(("rewriting node %d\n", ASGNUM(w
)));
2414 off
= BITOOR(freetemp(szty(p
->n_type
)));
2415 l
= mklnode(OREG
, off
, FPREG
, p
->n_type
);
2418 * If this is a binode which reclaim a leg, and it had
2419 * to walk down the other leg first, then it must be
2420 * split below this node instead.
2422 q
= &table
[TBLIDX(p
->n_su
)];
2423 if (optype(p
->n_op
) == BITYPE
&&
2424 (q
->rewrite
& RLEFT
&& (p
->n_su
& DORIGHT
) == 0) &&
2425 (TBLIDX(p
->n_right
->n_su
) != 0)) {
2427 nip
= ipnode(mkbinode(ASSIGN
, l
,
2428 p
->n_left
, p
->n_type
));
2430 } else if (optype(p
->n_op
) == BITYPE
&&
2431 (q
->rewrite
& RRIGHT
&& (p
->n_su
& DORIGHT
) != 0) &&
2432 (TBLIDX(p
->n_left
->n_su
) != 0)) {
2434 nip
= ipnode(mkbinode(ASSIGN
, l
,
2435 p
->n_right
, p
->n_type
));
2439 nip
= ipnode(mkbinode(ASSIGN
, l
, r
, p
->n_type
));
2442 DLIST_INSERT_BEFORE(cip
, nip
, qelem
);
2443 DLIST_REMOVE(w
, link
);
2449 * Change the TEMPs in the ipole list to stack variables.
2452 treerewrite(struct interpass
*ipole
, REGW
*rpole
)
2454 struct interpass
*ip
;
2458 DLIST_FOREACH(ip
, ipole
, qelem
) {
2459 if (ip
->type
!= IP_NODE
)
2462 walkf(ip
->ip_node
, shorttemp
, 0); /* convert temps to oregs */
2464 if (!DLIST_ISEMPTY(spole
, link
))
2465 comperr("treerewrite not empty");
2469 * Change the TEMPs in the ipole list to stack variables.
2472 leafrewrite(struct interpass
*ipole
, REGW
*rpole
)
2474 extern NODE
*nodepole
;
2475 extern int thisline
;
2476 struct interpass
*ip
;
2479 DLIST_FOREACH(ip
, ipole
, qelem
) {
2480 if (ip
->type
!= IP_NODE
)
2482 nodepole
= ip
->ip_node
;
2483 thisline
= ip
->lineno
;
2484 walkf(ip
->ip_node
, longtemp
, 0); /* convert temps to oregs */
2490 * Avoid copying spilled argument to new position on stack.
2493 temparg(struct interpass
*ipole
, REGW
*w
)
2495 struct interpass
*ip
;
2498 ip
= DLIST_NEXT(ipole
, qelem
); /* PROLOG */
2499 while (ip
->type
!= IP_DEFLAB
)
2500 ip
= DLIST_NEXT(ip
, qelem
);
2501 ip
= DLIST_NEXT(ip
, qelem
); /* first NODE */
2502 for (; ip
->type
!= IP_DEFLAB
; ip
= DLIST_NEXT(ip
, qelem
)) {
2503 if (ip
->type
== IP_ASM
)
2507 /* register args may already have been put on stack */
2508 if (p
->n_op
!= ASSIGN
|| p
->n_left
->n_op
!= TEMP
)
2511 if (p
->n_op
!= ASSIGN
|| p
->n_left
->n_op
!= TEMP
)
2512 continue; /* unknown tree */
2514 if (p
->n_right
->n_op
!= OREG
)
2515 continue; /* arg in register */
2516 if (w
!= &nblock
[regno(p
->n_left
)])
2518 w
->r_color
= (int)p
->n_right
->n_lval
;
2520 /* Cannot DLIST_REMOVE here, would break basic blocks */
2521 /* Make it a nothing instead */
2534 * Scan the whole function and search for temporaries to be stored
2537 * Be careful to not destroy the basic block structure in the first scan.
2540 RewriteProgram(struct interpass
*ip
)
2542 REGW shortregs
, longregs
, saveregs
, *q
;
2546 RDEBUG(("RewriteProgram\n"));
2547 DLIST_INIT(&shortregs
, link
);
2548 DLIST_INIT(&longregs
, link
);
2549 DLIST_INIT(&saveregs
, link
);
2551 /* sort the temporaries in three queues, short, long and perm */
2552 while (!DLIST_ISEMPTY(&spilledNodes
, link
)) {
2553 w
= DLIST_NEXT(&spilledNodes
, link
);
2554 DLIST_REMOVE(w
, link
);
2556 if (w
>= &nblock
[tempmin
] && w
< &nblock
[basetemp
]) {
2558 } else if (w
>= &nblock
[basetemp
] && w
< &nblock
[tempmax
]) {
2562 DLIST_INSERT_AFTER(q
, w
, link
);
2566 printf("permanent: ");
2567 DLIST_FOREACH(w
, &saveregs
, link
)
2568 printf("%d ", ASGNUM(w
));
2569 printf("\nlong-lived: ");
2570 DLIST_FOREACH(w
, &longregs
, link
)
2571 printf("%d ", ASGNUM(w
));
2572 printf("\nshort-lived: ");
2573 DLIST_FOREACH(w
, &shortregs
, link
)
2574 printf("%d ", ASGNUM(w
));
2580 if (!DLIST_ISEMPTY(&saveregs
, link
)) {
2582 DLIST_FOREACH(w
, &saveregs
, link
) {
2583 int num
= w
- nblock
- tempmin
;
2587 if (!DLIST_ISEMPTY(&longregs
, link
)) {
2589 DLIST_FOREACH(w
, &longregs
, link
) {
2590 w
->r_class
= xtemps
? temparg(ip
, w
) : 0;
2594 if (rwtyp
== LEAVES
) {
2595 leafrewrite(ip
, &longregs
);
2599 if (rwtyp
== 0 && !DLIST_ISEMPTY(&shortregs
, link
)) {
2600 /* Must rewrite the trees */
2601 treerewrite(ip
, &shortregs
);
2604 comperr("treerewrite");
2609 RDEBUG(("savregs %x rwtyp %d\n", 0, rwtyp
));
2616 * Print TEMP/REG contents in a node.
2619 prtreg(FILE *fp
, NODE
*p
)
2621 int i
, n
= p
->n_su
== -1 ? 0 : ncnt(table
[TBLIDX(p
->n_su
)].needs
);
2622 if (p
->n_reg
== -1) goto foo
;
2623 if (use_regw
|| p
->n_reg
> 0x40000000 || p
->n_reg
< 0) {
2624 fprintf(fp
, "TEMP ");
2625 if (p
->n_regw
!= NULL
) {
2626 for (i
= 0; i
< n
+1; i
++)
2627 fprintf(fp
, "%d ", p
->n_regw
[i
].nodnum
);
2629 fprintf(fp
, "<undef>");
2631 foo
: fprintf(fp
, "REG ");
2632 if (p
->n_reg
!= -1) {
2633 for (i
= 0; i
< n
+1; i
++) {
2634 int r
= DECRA(p
->n_reg
, i
);
2636 fprintf(fp
, "<badreg> ");
2638 fprintf(fp
, "%s ", rnames
[r
]);
2641 fprintf(fp
, "<undef>");
2648 * Assign instructions, calculate evaluation order and
2649 * set temporary register numbers.
2654 geninsn(); /* instruction assignment */
2655 sucomp(); /* set evaluation order */
2656 slong(); /* set long temp types */
2657 sshort(); /* set short temp numbers */
2662 * Do register allocation for trees by graph-coloring.
2665 ngenregs(struct p2env
*p2e
)
2667 struct interpass
*ipole
= &p2e
->ipole
;
2668 extern NODE
*nodepole
;
2669 struct interpass
*ip
;
2671 int uu
[NPERMREG
] = { -1 };
2672 int xnsavregs
[NPERMREG
];
2676 DLIST_INIT(&lunused
, link
);
2677 DLIST_INIT(&lused
, link
);
2680 * Do some setup before doing the real thing.
2682 tempmin
= p2e
->ipp
->ip_tmpnum
;
2683 tempmax
= p2e
->epp
->ip_tmpnum
;
2686 * Allocate space for the permanent registers in the
2687 * same block as the long-lived temporaries.
2688 * These temporaries will be handled the same way as
2689 * all other variables.
2692 nsavregs
= xnsavregs
;
2693 for (i
= 0; i
< NPERMREG
; i
++)
2695 ndontregs
= uu
; /* currently never avoid any regs */
2697 tempmin
-= (NPERMREG
-1);
2700 dontregs
|= REGBIT(FPREG
);
2706 tbits
= tempmax
- tempmin
; /* # of temporaries */
2707 xbits
= tbits
+ MAXREGS
; /* total size of live array */
2709 nblock
= tmpalloc(tbits
* sizeof(REGW
));
2712 #ifdef HAVE_C99_FORMAT
2713 RDEBUG(("nblock %p num %d size %zu\n",
2714 nblock
, tbits
, (size_t)(tbits
* sizeof(REGW
))));
2717 live
= tmpalloc(BIT2BYTE(xbits
));
2719 /* Block for precolored nodes */
2720 ablock
= tmpalloc(sizeof(REGW
)*MAXREGS
);
2721 memset(ablock
, 0, sizeof(REGW
)*MAXREGS
);
2722 for (i
= 0; i
< MAXREGS
; i
++) {
2723 ablock
[i
].r_onlist
= &precolored
;
2724 ablock
[i
].r_class
= GCLASS(i
); /* XXX */
2725 ablock
[i
].r_color
= i
;
2727 ablock
[i
].nodnum
= i
;
2736 onlyperm
: /* XXX - should not have to redo all */
2737 memset(edgehash
, 0, sizeof(edgehash
));
2740 memset(nblock
+tempmin
, 0, tbits
* sizeof(REGW
));
2742 for (i
= tempmin
; i
< tempmax
; i
++)
2743 nblock
[i
].nodnum
= i
;
2746 memset(live
, 0, BIT2BYTE(xbits
));
2748 DLIST_INIT(&initial
, link
);
2749 DLIST_FOREACH(ip
, ipole
, qelem
) {
2750 extern int thisline
;
2751 if (ip
->type
!= IP_NODE
)
2753 nodepole
= ip
->ip_node
;
2754 thisline
= ip
->lineno
;
2755 if (ip
->ip_node
->n_op
!= XASM
)
2756 geninsn(ip
->ip_node
, FOREFF
);
2757 nsucomp(ip
->ip_node
);
2758 walkf(ip
->ip_node
, traclass
, 0);
2761 RDEBUG(("nsucomp allocated %d temps (%d,%d)\n",
2762 tempmax
-tempmin
, tempmin
, tempmax
));
2769 RDEBUG(("ngenregs: numtemps %d (%d, %d)\n", tempmax
-tempmin
,
2772 DLIST_INIT(&coalescedMoves
, link
);
2773 DLIST_INIT(&constrainedMoves
, link
);
2774 DLIST_INIT(&frozenMoves
, link
);
2775 DLIST_INIT(&worklistMoves
, link
);
2776 DLIST_INIT(&activeMoves
, link
);
2778 /* Set class and move-related for perm regs */
2779 for (i
= 0; i
< (NPERMREG
-1); i
++) {
2782 nblock
[i
+tempmin
].r_class
= GCLASS(permregs
[i
]);
2783 DLIST_INSERT_AFTER(&initial
, &nblock
[i
+tempmin
], link
);
2784 moveadd(&nblock
[i
+tempmin
], &ablock
[permregs
[i
]]);
2785 addalledges(&nblock
[i
+tempmin
]);
2789 RDEBUG(("Build done\n"));
2791 RDEBUG(("MkWorklist done\n"));
2793 if (!WLISTEMPTY(simplifyWorklist
))
2795 else if (!WLISTEMPTY(worklistMoves
))
2797 else if (!WLISTEMPTY(freezeWorklist
))
2799 else if (!WLISTEMPTY(spillWorklist
))
2801 } while (!WLISTEMPTY(simplifyWorklist
) || !WLISTEMPTY(worklistMoves
) ||
2802 !WLISTEMPTY(freezeWorklist
) || !WLISTEMPTY(spillWorklist
));
2803 AssignColors(ipole
);
2805 RDEBUG(("After AssignColors\n"));
2808 if (!WLISTEMPTY(spilledNodes
)) {
2809 switch (RewriteProgram(ipole
)) {
2814 if (beenhere
++ == MAXLOOP
)
2815 comperr("cannot color graph - COLORMAP() bug?");
2820 /* fill in regs to save */
2821 memset(p2e
->ipp
->ipp_regs
, 0, sizeof(p2e
->ipp
->ipp_regs
));
2822 for (i
= 0; i
< NPERMREG
-1; i
++) {
2826 BITSET(p2e
->ipp
->ipp_regs
, permregs
[i
]);
2827 continue; /* Spilled */
2829 if (nblock
[i
+tempmin
].r_color
== permregs
[i
])
2830 continue; /* Coalesced */
2832 * If the original color of this permreg is used for
2833 * coloring another register, swap them to avoid
2834 * unnecessary moves.
2836 for (j
= i
+1; j
< NPERMREG
-1; j
++) {
2837 if (nblock
[j
+tempmin
].r_color
!= permregs
[i
])
2839 nblock
[j
+tempmin
].r_color
= nblock
[i
+tempmin
].r_color
;
2842 if (j
!= NPERMREG
-1)
2845 /* Generate reg-reg move nodes for save */
2846 type
= PERMTYPE(permregs
[i
]);
2848 if (PERMTYPE(nblock
[i
+tempmin
].r_color
) != type
)
2849 comperr("permreg botch");
2851 p
= mkbinode(ASSIGN
,
2852 mklnode(REG
, 0, nblock
[i
+tempmin
].r_color
, type
),
2853 mklnode(REG
, 0, permregs
[i
], type
), type
);
2854 p
->n_reg
= p
->n_left
->n_reg
= p
->n_right
->n_reg
= -1;
2855 p
->n_left
->n_su
= p
->n_right
->n_su
= 0;
2858 DLIST_INSERT_AFTER(ipole
->qelem
.q_forw
, ip
, qelem
);
2859 p
= mkbinode(ASSIGN
, mklnode(REG
, 0, permregs
[i
], type
),
2860 mklnode(REG
, 0, nblock
[i
+tempmin
].r_color
, type
), type
);
2861 p
->n_reg
= p
->n_left
->n_reg
= p
->n_right
->n_reg
= -1;
2862 p
->n_left
->n_su
= p
->n_right
->n_su
= 0;
2865 DLIST_INSERT_BEFORE(ipole
->qelem
.q_back
, ip
, qelem
);
2867 memcpy(p2e
->epp
->ipp_regs
, p2e
->ipp
->ipp_regs
, sizeof(p2e
->epp
->ipp_regs
));