comparison python/ppci/codegen/registerallocator.py @ 301:6753763d3bec

merge codegen into ppci package
author Windel Bouwman
date Thu, 05 Dec 2013 17:02:38 +0100
parents python/codegen/registerallocator.py@158068af716c
children 0615b5308710
comparison
equal deleted inserted replaced
300:158068af716c 301:6753763d3bec
1 from .flowgraph import FlowGraph
2 from .interferencegraph import InterferenceGraph
3
4 # Nifty first function:
5 first = lambda x: next(iter(x))
6
7
8 class RegisterAllocator:
9 """
10 Target independent register allocator.
11
12 Algorithm is iterated register coalescing by Appel and George.
13
14 Chaitin's algorithm: remove all nodes with less than K neighbours.
15 These nodes can be colored when added back.
16
17 The process consists of the following steps:
18 - build interference graph from the instruction list
19 - remove low degree non move related nodes.
20 - (optional) coalesc registers to remove redundant moves
21 - (optional) spill registers
22 - select registers
23 """
24
25 def InitData(self, f):
26 self.f = f
27 # Register information:
28 self.regs = set(f.regs)
29 self.K = len(self.regs)
30
31 # Move related sets:
32 self.coalescedMoves = set()
33 self.constrainedMoves = set()
34 self.frozenMoves = set()
35 self.activeMoves = set()
36 self.worklistMoves = set()
37
38 def printLive(self):
39 print('Liveness:')
40 for i in self.f.instructions:
41 cfgn = self.f.cfg._map[i]
42 print(i, cfgn.live_in)
43
44 def Build(self):
45 """ 1. Construct interference graph from instruction list """
46 self.f.cfg = FlowGraph(self.f.instructions)
47 self.f.ig = InterferenceGraph(self.f.cfg)
48
49 self.Node = self.f.ig.getNode
50
51 # Divide nodes into pre-colored and initial:
52 pre_tmp = list(self.f.tempMap.keys())
53 self.precolored = set(self.Node(tmp) for tmp in pre_tmp)
54 self.workSet = set(self.f.ig.nodes - self.precolored)
55
56 for n in self.precolored:
57 n.addDegree = 100 + len(self.f.ig.nodes) + self.K
58
59 # Initialize color map:
60 self.color = {}
61 for tmp, c in self.f.tempMap.items():
62 self.color[self.Node(tmp)] = c
63
64 self.moves = [i for i in self.f.instructions if i.ismove]
65 for mv in self.moves:
66 self.Node(mv.src[0]).moves.add(mv)
67 self.Node(mv.dst[0]).moves.add(mv)
68
69 def NodeMoves(self, n):
70 return n.moves & (self.activeMoves | self.worklistMoves)
71
72 def MoveRelated(self, n):
73 return bool(self.NodeMoves(n))
74
75 @property
76 def SpillWorkSet(self):
77 c = lambda n: n.Degree >= self.K
78 return set(filter(c, self.workSet))
79
80 @property
81 def FreezeWorkSet(self):
82 c = lambda n: n.Degree < self.K and self.MoveRelated(n)
83 return set(filter(c, self.workSet))
84
85 @property
86 def SimplifyWorkSet(self):
87 c = lambda n: n.Degree < self.K and not self.MoveRelated(n)
88 return set(filter(c, self.workSet))
89
90 def makeWorkList(self):
91 """ Divide initial nodes into worklists """
92 self.selectStack = []
93
94 # Fill initial move set:
95 for m in self.moves:
96 self.worklistMoves.add(m)
97
98 def Simplify(self):
99 """ 2. Remove nodes from the graph """
100 n = first(self.SimplifyWorkSet)
101 self.workSet.remove(n)
102 self.selectStack.append(n)
103 # Pop out of graph:
104 self.f.ig.delNode(n)
105
106 def EnableMoves(self, nodes):
107 for n in nodes:
108 for m in self.NodeMoves(n):
109 if m in self.activeMoves:
110 self.activeMoves.remove(m)
111 self.worklistMoves.add(m)
112
113 def Coalesc(self):
114 """ Coalesc conservative. """
115 m = first(self.worklistMoves)
116 x = self.Node(m.dst[0])
117 y = self.Node(m.src[0])
118 u, v = (y, x) if y in self.precolored else (x, y)
119 self.worklistMoves.remove(m)
120 if u is v:
121 self.coalescedMoves.add(m)
122 elif v in self.precolored or self.f.ig.hasEdge(u, v):
123 self.constrainedMoves.add(m)
124 elif u not in self.precolored and self.Conservative(u, v):
125 self.coalescedMoves.add(m)
126 self.workSet.remove(v)
127 self.f.ig.Combine(u, v)
128 else:
129 self.activeMoves.add(m)
130
131 def Conservative(self, u, v):
132 """ Briggs conservative criteria for coalesc """
133 nodes = u.Adjecent | v.Adjecent
134 c = lambda n: n.Degree >= self.K
135 k = len(list(filter(c, nodes)))
136 return k < self.K
137
138 def Freeze(self):
139 """ Give up coalescing on some node """
140 u = first(self.FreezeWorkSet)
141 self.freezeMoves(u)
142
143 def freezeMoves(self, u):
144 """ Freeze moves for node u """
145 for m in self.NodeMoves(u):
146 if m in self.activeMoves:
147 self.activeMoves.remove(m)
148 else:
149 sekf.worklistMoves.remove(m)
150 self.frozenMoves.add(m)
151 # Check other part of the move for still being move related:
152 v = m.src[0] if u is m.dst[0] else m.dst[0]
153
154 def SelectSpill(self):
155 # TODO
156 pass
157
158 def AssignColors(self):
159 """ Add nodes back to the graph to color it. """
160 # Add nodes back to the graph:
161 while self.selectStack:
162 n = self.selectStack.pop(-1)
163 self.f.ig.addNode(n)
164 takenregs = set(self.color[m] for m in n.Adjecent)
165 okColors = self.regs - takenregs
166 if okColors:
167 self.color[n] = first(okColors)
168 n.color = self.color[n]
169 else:
170 raise NotImplementedError('Spill required here!')
171
172 def ApplyColors(self):
173 # Remove coalesced moves:
174 for mv in self.coalescedMoves:
175 self.f.instructions.remove(mv)
176
177 # Use allocated registers:
178 lookup = lambda t: self.color[self.Node(t)]
179 for i in self.f.instructions:
180 i.src = tuple(map(lookup, i.src))
181 i.dst = tuple(map(lookup, i.dst))
182
183 def allocFrame(self, f):
184 """ Do iterated register allocation for a single stack frame. """
185 self.InitData(f)
186 self.Build()
187 self.makeWorkList()
188 while True:
189 if self.SimplifyWorkSet:
190 self.Simplify()
191 elif self.worklistMoves:
192 self.Coalesc()
193 elif self.FreezeWorkSet:
194 self.Freeze()
195 elif self.SpillWorkSet:
196 raise NotImplementedError('Spill not implemented')
197 else:
198 break # Done!
199 self.AssignColors()
200 self.ApplyColors()
201