Mercurial > lcfOS
comparison python/ir.py @ 277:046017431c6a
Started register allocator
author | Windel Bouwman |
---|---|
date | Thu, 26 Sep 2013 21:14:25 +0200 |
parents | |
children | 2ccd57b1d78c |
comparison
equal
deleted
inserted
replaced
276:56d37ed4b4d2 | 277:046017431c6a |
---|---|
1 """ | |
2 Intermediate representation (IR) code classes. | |
3 """ | |
4 | |
5 | |
6 def dumpgv(m, outf): | |
7 print('digraph G ', file=outf) | |
8 print('{', file=outf) | |
9 for f in m.Functions: | |
10 print('{} [label="{}" shape=box3d]'.format(id(f), f),file=outf) | |
11 for bb in f.Blocks: | |
12 contents = str(bb) + '\n' | |
13 contents += '\n'.join([str(i) for i in bb.Instructions]) | |
14 outf.write('{0} [shape=note label="{1}"];\n'.format(id(bb), contents)) | |
15 for successor in bb.Successors: | |
16 print('"{}" -> "{}"\n'.format(id(bb), id(successor)), file=outf) | |
17 | |
18 outf.write('"{}" -> "{}" [label="entry"]\n'.format(id(f), id(f.entry))) | |
19 print('}', file=outf) | |
20 | |
21 | |
22 class Module: | |
23 """ Main container of variables and functions. """ | |
24 def __init__(self, name): | |
25 self.name = name | |
26 self.funcs = [] | |
27 self.variables = [] | |
28 | |
29 def __repr__(self): | |
30 return 'IR-module [{0}]'.format(self.name) | |
31 | |
32 def addFunc(self, f): | |
33 self.funcs.append(f) | |
34 | |
35 addFunction = addFunc | |
36 | |
37 def addVariable(self, v): | |
38 self.variables.append(v) | |
39 | |
40 def getVariables(self): | |
41 return self.variables | |
42 | |
43 Variables = property(getVariables) | |
44 | |
45 def getFunctions(self): | |
46 return self.funcs | |
47 | |
48 Functions = property(getFunctions) | |
49 | |
50 def findFunction(self, name): | |
51 for f in self.funcs: | |
52 if f.name == name: | |
53 return f | |
54 raise KeyError(name) | |
55 | |
56 getFunction = findFunction | |
57 | |
58 def dump(self, indent=' '): | |
59 print(self) | |
60 for v in self.Variables: | |
61 print(indent, v) | |
62 for fn in self.Functions: | |
63 fn.dump(indent=indent+' ') | |
64 | |
65 # Analysis functions: | |
66 def check(self): | |
67 """ Perform sanity check on module """ | |
68 for f in self.Functions: | |
69 f.check() | |
70 | |
71 | |
72 class Function: | |
73 """ | |
74 Function definition. Contains an entry block. | |
75 """ | |
76 def __init__(self, name): | |
77 self.name = name | |
78 self.entry = Block('{}_entry'.format(name)) | |
79 self.epiloog = Block('{}_epilog'.format(name)) | |
80 self.epiloog.addInstruction(Terminator()) | |
81 self.return_value = Temp('{}_retval'.format(name)) | |
82 self.arguments = [] | |
83 self.localvars = [] | |
84 | |
85 def __repr__(self): | |
86 args = ','.join(str(a) for a in self.arguments) | |
87 return 'Function {}({})'.format(self.name, args) | |
88 | |
89 def addBB(self, bb): | |
90 self.bbs.append(bb) | |
91 bb.parent = self | |
92 addBlock = addBB | |
93 | |
94 def removeBasicBlock(self, bb): | |
95 self.bbs.remove(bb) | |
96 bb.parent = None | |
97 | |
98 def getBBs(self): | |
99 bbs = [self.entry] | |
100 worklist = [self.entry] | |
101 while worklist: | |
102 b = worklist.pop() | |
103 for sb in b.Successors: | |
104 if sb not in bbs: | |
105 bbs.append(sb) | |
106 worklist.append(sb) | |
107 bbs.remove(self.entry) | |
108 if self.epiloog in bbs: | |
109 bbs.remove(self.epiloog) | |
110 bbs.insert(0, self.entry) | |
111 bbs.append(self.epiloog) | |
112 return bbs | |
113 | |
114 def findBasicBlock(self, name): | |
115 for bb in self.bbs: | |
116 if bb.name == name: | |
117 return bb | |
118 raise KeyError(name) | |
119 | |
120 Blocks = property(getBBs) | |
121 | |
122 @property | |
123 def Entry(self): | |
124 return self.entry | |
125 | |
126 def check(self): | |
127 for b in self.Blocks: | |
128 b.check() | |
129 | |
130 def addParameter(self, p): | |
131 assert type(p) is Parameter | |
132 p.num = len(self.arguments) | |
133 self.arguments.append(p) | |
134 | |
135 def addLocal(self, l): | |
136 assert type(l) is LocalVariable | |
137 self.localvars.append(l) | |
138 | |
139 def dump(self, indent=''): | |
140 print(indent+str(self)) | |
141 for bb in self.Blocks: | |
142 print(indent+' '+str(bb)) | |
143 for ins in bb.Instructions: | |
144 print(indent +' '*2 + str(ins)) | |
145 | |
146 | |
147 class Block: | |
148 """ | |
149 Uninterrupted sequence of instructions with a label at the start. | |
150 """ | |
151 def __init__(self, name): | |
152 self.name = name | |
153 self.instructions = [] | |
154 | |
155 def __repr__(self): | |
156 return 'Block {0}'.format(self.name) | |
157 | |
158 def addInstruction(self, i): | |
159 i.parent = self | |
160 assert not isinstance(self.LastInstruction, LastStatement) | |
161 self.instructions.append(i) | |
162 | |
163 def replaceInstruction(self, i1, i2): | |
164 idx = self.instructions.index(i1) | |
165 i1.parent = None | |
166 i1.delete() | |
167 i2.parent = self | |
168 self.instructions[idx] = i2 | |
169 | |
170 def removeInstruction(self, i): | |
171 i.parent = None | |
172 i.delete() | |
173 self.instructions.remove(i) | |
174 | |
175 def getInstructions(self): | |
176 return self.instructions | |
177 Instructions = property(getInstructions) | |
178 | |
179 def getLastIns(self): | |
180 if not self.Empty: | |
181 return self.instructions[-1] | |
182 LastInstruction = property(getLastIns) | |
183 | |
184 @property | |
185 def Empty(self): | |
186 return len(self.instructions) == 0 | |
187 | |
188 @property | |
189 def FirstInstruction(self): | |
190 return self.instructions[0] | |
191 | |
192 def getSuccessors(self): | |
193 if not self.Empty: | |
194 return self.LastInstruction.Targets | |
195 return [] | |
196 Successors = property(getSuccessors) | |
197 | |
198 def getPredecessors(self): | |
199 preds = [] | |
200 for bb in self.parent.BasicBlocks: | |
201 if self in bb.Successors: | |
202 preds.append(bb) | |
203 return preds | |
204 Predecessors = property(getPredecessors) | |
205 | |
206 def precedes(self, other): | |
207 raise NotImplementedError() | |
208 | |
209 def check(self): | |
210 assert isinstance(self.LastInstruction, LastStatement) | |
211 for i in self.instructions[:-1]: | |
212 assert not isinstance(i, LastStatement) | |
213 | |
214 | |
215 # Instructions: | |
216 class Term: | |
217 def __init__(self, x): | |
218 self.x = x | |
219 | |
220 def match_tree(tree, pattern): | |
221 if type(pattern) is Term: | |
222 return True, {pattern: tree} | |
223 elif type(pattern) is Binop and type(tree) is Binop and tree.operation == pattern.operation: | |
224 res_a, mp_a = match_tree(tree.a, pattern.a) | |
225 res_b, mp_b = match_tree(tree.b, pattern.b) | |
226 assert not (mp_a.keys() & mp_b.keys()) | |
227 mp_a.update(mp_b) | |
228 return res_a and res_b, mp_a | |
229 elif type(pattern) is Const and type(tree) is Const and pattern.value == tree.value: | |
230 return True, {} | |
231 else: | |
232 return False, {} | |
233 | |
234 | |
235 class Expression: | |
236 pass | |
237 | |
238 | |
239 class Const(Expression): | |
240 def __init__(self, value): | |
241 self.value = value | |
242 | |
243 def __repr__(self): | |
244 return 'Const {}'.format(self.value) | |
245 | |
246 | |
247 # Function calling: | |
248 class Call(Expression): | |
249 def __init__(self, f, arguments): | |
250 self.f = f | |
251 assert type(f) is Function | |
252 self.arguments = arguments | |
253 | |
254 def __repr__(self): | |
255 args = ', '.join([str(arg) for arg in self.arguments]) | |
256 return '{}({})'.format(self.f.name, args) | |
257 | |
258 | |
259 # Data operations | |
260 class Binop(Expression): | |
261 ops = ['+', '-', '*', '/', '|', '&', '<<', '>>'] | |
262 def __init__(self, value1, operation, value2): | |
263 assert operation in Binop.ops | |
264 self.a = value1 | |
265 self.b = value2 | |
266 self.operation = operation | |
267 | |
268 def __repr__(self): | |
269 a, b = self.a, self.b | |
270 return '({} {} {})'.format(a, self.operation, b) | |
271 | |
272 | |
273 def Add(a, b): | |
274 """ Convenience call """ | |
275 return Binop(a, '+', b) | |
276 | |
277 | |
278 class Eseq(Expression): | |
279 """ Sequence of instructions where the last is an expression """ | |
280 def __init__(self, stmt, e): | |
281 self.stmt = stmt | |
282 self.e = e | |
283 | |
284 def __repr__(self): | |
285 return '({}, {})'.format(self.stmt, self.e) | |
286 | |
287 | |
288 class Alloc(Expression): | |
289 """ Allocates space on the stack """ | |
290 def __init__(self): | |
291 super().__init__() | |
292 | |
293 def __repr__(self): | |
294 return 'Alloc' | |
295 | |
296 | |
297 class Variable(Expression): | |
298 def __init__(self, name): | |
299 self.name = name | |
300 | |
301 def __repr__(self): | |
302 return 'Var {}'.format(self.name) | |
303 | |
304 | |
305 class LocalVariable(Variable): | |
306 def __repr__(self): | |
307 return 'Local {}'.format(self.name) | |
308 | |
309 | |
310 class Parameter(Variable): | |
311 def __repr__(self): | |
312 return 'Param {}'.format(self.name) | |
313 | |
314 | |
315 class Temp(Expression): | |
316 """ Temporary storage, same as register """ | |
317 def __init__(self, name): | |
318 self.name = name | |
319 | |
320 def __repr__(self): | |
321 return 'TMP_{}'.format(self.name) | |
322 | |
323 | |
324 class Mem(Expression): | |
325 def __init__(self, e): | |
326 self.e = e | |
327 | |
328 def __repr__(self): | |
329 return '[{}]'.format(self.e) | |
330 | |
331 | |
332 class Statement: | |
333 """ Base class for all instructions. """ | |
334 pass | |
335 | |
336 | |
337 class Move(Statement): | |
338 def __init__(self, dst, src): | |
339 self.dst = dst | |
340 self.src = src | |
341 | |
342 def __repr__(self): | |
343 return '{} = {}'.format(self.dst, self.src) | |
344 | |
345 | |
346 class Exp(Statement): | |
347 def __init__(self, e): | |
348 self.e = e | |
349 | |
350 def __repr__(self): | |
351 return '{}'.format(self.e) | |
352 | |
353 | |
354 class Label(Statement): | |
355 # TODO: is this duplicate with block? | |
356 def __init__(self, name): | |
357 self.name = name | |
358 self.statements = [] | |
359 | |
360 def __repr__(self): | |
361 return 'LABEL {}:'.format(self.name) | |
362 | |
363 | |
364 # Branching: | |
365 class LastStatement(Statement): | |
366 pass | |
367 | |
368 | |
369 class Terminator(LastStatement): | |
370 """ Instruction that terminates the terminal block """ | |
371 Targets = [] | |
372 def __repr__(self): | |
373 return 'Terminator' | |
374 | |
375 | |
376 class Jump(LastStatement): | |
377 def __init__(self, target): | |
378 self.target = target | |
379 self.Targets = [target] | |
380 | |
381 def __repr__(self): | |
382 return 'BRANCH {}'.format(self.target.name) | |
383 | |
384 | |
385 class CJump(LastStatement): | |
386 conditions = ['==', '<', '>', '>=', '<=', '!='] | |
387 def __init__(self, a, cond, b, lab_yes, lab_no): | |
388 assert cond in CJump.conditions | |
389 self.a = a | |
390 self.cond = cond | |
391 self.b = b | |
392 self.lab_yes = lab_yes | |
393 self.lab_no = lab_no | |
394 self.Targets = [lab_yes, lab_no] | |
395 | |
396 def __repr__(self): | |
397 return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no) | |
398 | |
399 | |
400 class NamedClassGenerator: | |
401 def __init__(self, prefix, cls): | |
402 self.prefix = prefix | |
403 self.cls = cls | |
404 def NumGen(): | |
405 a = 0 | |
406 while True: | |
407 yield a | |
408 a = a + 1 | |
409 self.nums = NumGen() | |
410 | |
411 def gen(self, prefix=None): | |
412 if not prefix: | |
413 prefix = self.prefix | |
414 return self.cls('{0}{1}'.format(prefix, self.nums.__next__())) | |
415 | |
416 | |
417 class Builder: | |
418 """ Base class for ir code generators """ | |
419 def __init__(self): | |
420 self.prepare() | |
421 | |
422 def prepare(self): | |
423 self.newTemp = NamedClassGenerator('reg', Temp).gen | |
424 self.newBlock = NamedClassGenerator('block', Block).gen | |
425 self.bb = None | |
426 self.m = None | |
427 self.fn = None | |
428 self.loc = None | |
429 | |
430 # Helpers: | |
431 def setModule(self, m): | |
432 self.m = m | |
433 | |
434 def newFunction(self, name): | |
435 f = Function(name) | |
436 self.m.addFunc(f) | |
437 return f | |
438 | |
439 def setFunction(self, f): | |
440 self.fn = f | |
441 self.bb = f.entry if f else None | |
442 | |
443 def setBlock(self, b): | |
444 self.bb = b | |
445 | |
446 def setLoc(self, l): | |
447 self.loc = l | |
448 | |
449 def emit(self, i): | |
450 assert isinstance(i, Statement) | |
451 i.debugLoc = self.loc | |
452 if not self.bb: | |
453 raise Exception('No basic block') | |
454 self.bb.addInstruction(i) | |
455 | |
456 |