Mercurial > lcfOS
annotate python/ir.py @ 281:4496cae24d7f
Improved logview
author | Windel Bouwman |
---|---|
date | Sat, 02 Nov 2013 11:11:40 +0100 |
parents | 02385f62f250 |
children | 534b94b40aa8 |
rev | line source |
---|---|
277 | 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)) | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
79 self.entry.function = self |
277 | 80 self.epiloog = Block('{}_epilog'.format(name)) |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
81 self.epiloog.function = self |
277 | 82 self.epiloog.addInstruction(Terminator()) |
83 self.return_value = Temp('{}_retval'.format(name)) | |
84 self.arguments = [] | |
85 self.localvars = [] | |
86 | |
87 def __repr__(self): | |
88 args = ','.join(str(a) for a in self.arguments) | |
89 return 'Function {}({})'.format(self.name, args) | |
90 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
91 def addBlock(self, bb): |
277 | 92 self.bbs.append(bb) |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
93 bb.function = self |
277 | 94 |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
95 def removeBlock(self, bb): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
96 #self.bbs.remove(bb) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
97 bb.function = None |
277 | 98 |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
99 def getBlocks(self): |
277 | 100 bbs = [self.entry] |
101 worklist = [self.entry] | |
102 while worklist: | |
103 b = worklist.pop() | |
104 for sb in b.Successors: | |
105 if sb not in bbs: | |
106 bbs.append(sb) | |
107 worklist.append(sb) | |
108 bbs.remove(self.entry) | |
109 if self.epiloog in bbs: | |
110 bbs.remove(self.epiloog) | |
111 bbs.insert(0, self.entry) | |
112 bbs.append(self.epiloog) | |
113 return bbs | |
114 | |
115 def findBasicBlock(self, name): | |
116 for bb in self.bbs: | |
117 if bb.name == name: | |
118 return bb | |
119 raise KeyError(name) | |
120 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
121 Blocks = property(getBlocks) |
277 | 122 |
123 @property | |
124 def Entry(self): | |
125 return self.entry | |
126 | |
127 def check(self): | |
128 for b in self.Blocks: | |
129 b.check() | |
130 | |
131 def addParameter(self, p): | |
132 assert type(p) is Parameter | |
133 p.num = len(self.arguments) | |
134 self.arguments.append(p) | |
135 | |
136 def addLocal(self, l): | |
137 assert type(l) is LocalVariable | |
138 self.localvars.append(l) | |
139 | |
140 def dump(self, indent=''): | |
141 print(indent+str(self)) | |
142 for bb in self.Blocks: | |
143 print(indent+' '+str(bb)) | |
144 for ins in bb.Instructions: | |
145 print(indent +' '*2 + str(ins)) | |
146 | |
147 | |
148 class Block: | |
149 """ | |
150 Uninterrupted sequence of instructions with a label at the start. | |
151 """ | |
152 def __init__(self, name): | |
153 self.name = name | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
154 self.function = None |
277 | 155 self.instructions = [] |
156 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
157 parent = property(lambda s: s.function) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
158 |
277 | 159 def __repr__(self): |
160 return 'Block {0}'.format(self.name) | |
161 | |
162 def addInstruction(self, i): | |
163 i.parent = self | |
164 assert not isinstance(self.LastInstruction, LastStatement) | |
165 self.instructions.append(i) | |
166 | |
167 def replaceInstruction(self, i1, i2): | |
168 idx = self.instructions.index(i1) | |
169 i1.parent = None | |
170 i1.delete() | |
171 i2.parent = self | |
172 self.instructions[idx] = i2 | |
173 | |
174 def removeInstruction(self, i): | |
175 i.parent = None | |
176 i.delete() | |
177 self.instructions.remove(i) | |
178 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
179 @property |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
180 def Instructions(self): |
277 | 181 return self.instructions |
182 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
183 @property |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
184 def LastInstruction(self): |
277 | 185 if not self.Empty: |
186 return self.instructions[-1] | |
187 | |
188 @property | |
189 def Empty(self): | |
190 return len(self.instructions) == 0 | |
191 | |
192 @property | |
193 def FirstInstruction(self): | |
194 return self.instructions[0] | |
195 | |
196 def getSuccessors(self): | |
197 if not self.Empty: | |
198 return self.LastInstruction.Targets | |
199 return [] | |
200 Successors = property(getSuccessors) | |
201 | |
202 def getPredecessors(self): | |
203 preds = [] | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
204 for bb in self.parent.Blocks: |
277 | 205 if self in bb.Successors: |
206 preds.append(bb) | |
207 return preds | |
208 Predecessors = property(getPredecessors) | |
209 | |
210 def precedes(self, other): | |
211 raise NotImplementedError() | |
212 | |
213 def check(self): | |
214 assert isinstance(self.LastInstruction, LastStatement) | |
215 for i in self.instructions[:-1]: | |
216 assert not isinstance(i, LastStatement) | |
217 | |
218 | |
219 # Instructions: | |
220 class Term: | |
221 def __init__(self, x): | |
222 self.x = x | |
223 | |
224 def match_tree(tree, pattern): | |
225 if type(pattern) is Term: | |
226 return True, {pattern: tree} | |
227 elif type(pattern) is Binop and type(tree) is Binop and tree.operation == pattern.operation: | |
228 res_a, mp_a = match_tree(tree.a, pattern.a) | |
229 res_b, mp_b = match_tree(tree.b, pattern.b) | |
230 assert not (mp_a.keys() & mp_b.keys()) | |
231 mp_a.update(mp_b) | |
232 return res_a and res_b, mp_a | |
233 elif type(pattern) is Const and type(tree) is Const and pattern.value == tree.value: | |
234 return True, {} | |
235 else: | |
236 return False, {} | |
237 | |
238 | |
239 class Expression: | |
240 pass | |
241 | |
242 | |
243 class Const(Expression): | |
244 def __init__(self, value): | |
245 self.value = value | |
246 | |
247 def __repr__(self): | |
248 return 'Const {}'.format(self.value) | |
249 | |
250 | |
251 # Function calling: | |
252 class Call(Expression): | |
253 def __init__(self, f, arguments): | |
254 self.f = f | |
255 assert type(f) is Function | |
256 self.arguments = arguments | |
257 | |
258 def __repr__(self): | |
259 args = ', '.join([str(arg) for arg in self.arguments]) | |
260 return '{}({})'.format(self.f.name, args) | |
261 | |
262 | |
263 # Data operations | |
264 class Binop(Expression): | |
265 ops = ['+', '-', '*', '/', '|', '&', '<<', '>>'] | |
266 def __init__(self, value1, operation, value2): | |
267 assert operation in Binop.ops | |
268 self.a = value1 | |
269 self.b = value2 | |
270 self.operation = operation | |
271 | |
272 def __repr__(self): | |
273 a, b = self.a, self.b | |
274 return '({} {} {})'.format(a, self.operation, b) | |
275 | |
276 | |
277 def Add(a, b): | |
278 """ Convenience call """ | |
279 return Binop(a, '+', b) | |
280 | |
279 | 281 def Sub(a, b): |
282 return Binop(a, '-', b) | |
283 | |
284 def Mul(a, b): | |
285 return Binop(a, '*', b) | |
286 | |
287 def Div(a, b): | |
288 return Binop(a, '/', b) | |
277 | 289 |
290 class Eseq(Expression): | |
291 """ Sequence of instructions where the last is an expression """ | |
292 def __init__(self, stmt, e): | |
293 self.stmt = stmt | |
294 self.e = e | |
295 | |
296 def __repr__(self): | |
297 return '({}, {})'.format(self.stmt, self.e) | |
298 | |
299 | |
300 class Alloc(Expression): | |
301 """ Allocates space on the stack """ | |
302 def __init__(self): | |
303 super().__init__() | |
304 | |
305 def __repr__(self): | |
306 return 'Alloc' | |
307 | |
308 | |
309 class Variable(Expression): | |
310 def __init__(self, name): | |
311 self.name = name | |
312 | |
313 def __repr__(self): | |
314 return 'Var {}'.format(self.name) | |
315 | |
316 | |
317 class LocalVariable(Variable): | |
318 def __repr__(self): | |
319 return 'Local {}'.format(self.name) | |
320 | |
321 | |
322 class Parameter(Variable): | |
323 def __repr__(self): | |
324 return 'Param {}'.format(self.name) | |
325 | |
326 | |
327 class Temp(Expression): | |
328 """ Temporary storage, same as register """ | |
329 def __init__(self, name): | |
330 self.name = name | |
331 | |
332 def __repr__(self): | |
333 return 'TMP_{}'.format(self.name) | |
334 | |
335 | |
336 class Mem(Expression): | |
337 def __init__(self, e): | |
338 self.e = e | |
339 | |
340 def __repr__(self): | |
341 return '[{}]'.format(self.e) | |
342 | |
343 | |
344 class Statement: | |
345 """ Base class for all instructions. """ | |
346 pass | |
347 | |
348 | |
349 class Move(Statement): | |
350 def __init__(self, dst, src): | |
351 self.dst = dst | |
352 self.src = src | |
353 | |
354 def __repr__(self): | |
355 return '{} = {}'.format(self.dst, self.src) | |
356 | |
357 | |
358 class Exp(Statement): | |
359 def __init__(self, e): | |
360 self.e = e | |
361 | |
362 def __repr__(self): | |
363 return '{}'.format(self.e) | |
364 | |
365 | |
366 # Branching: | |
367 class LastStatement(Statement): | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
368 def changeTarget(self, old, new): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
369 idx = self.Targets.index(old) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
370 self.Targets[idx] = new |
277 | 371 |
372 | |
373 class Terminator(LastStatement): | |
374 """ Instruction that terminates the terminal block """ | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
375 def __init__(self): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
376 self.Targets = [] |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
377 |
277 | 378 def __repr__(self): |
379 return 'Terminator' | |
380 | |
381 | |
382 class Jump(LastStatement): | |
383 def __init__(self, target): | |
384 self.Targets = [target] | |
385 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
386 def setTarget(self, t): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
387 self.Targets[0] = t |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
388 target = property(lambda s: s.Targets[0], setTarget) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
389 |
277 | 390 def __repr__(self): |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
391 return 'JUMP {}'.format(self.target.name) |
277 | 392 |
393 | |
394 class CJump(LastStatement): | |
395 conditions = ['==', '<', '>', '>=', '<=', '!='] | |
396 def __init__(self, a, cond, b, lab_yes, lab_no): | |
397 assert cond in CJump.conditions | |
398 self.a = a | |
399 self.cond = cond | |
400 self.b = b | |
401 self.Targets = [lab_yes, lab_no] | |
402 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
403 lab_yes = property(lambda s: s.Targets[0]) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
404 lab_no = property(lambda s: s.Targets[1]) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
405 |
277 | 406 def __repr__(self): |
407 return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no) | |
408 | |
409 | |
279 | 410 # Constructing IR: |
411 | |
277 | 412 class NamedClassGenerator: |
413 def __init__(self, prefix, cls): | |
414 self.prefix = prefix | |
415 self.cls = cls | |
416 def NumGen(): | |
417 a = 0 | |
418 while True: | |
419 yield a | |
420 a = a + 1 | |
421 self.nums = NumGen() | |
422 | |
423 def gen(self, prefix=None): | |
424 if not prefix: | |
425 prefix = self.prefix | |
426 return self.cls('{0}{1}'.format(prefix, self.nums.__next__())) | |
427 | |
428 | |
429 class Builder: | |
430 """ Base class for ir code generators """ | |
431 def __init__(self): | |
432 self.prepare() | |
433 | |
434 def prepare(self): | |
435 self.newTemp = NamedClassGenerator('reg', Temp).gen | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
436 self.newBlock2 = NamedClassGenerator('block', Block).gen |
277 | 437 self.bb = None |
438 self.m = None | |
439 self.fn = None | |
440 self.loc = None | |
441 | |
442 # Helpers: | |
443 def setModule(self, m): | |
444 self.m = m | |
445 | |
446 def newFunction(self, name): | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
447 f = Function(name) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
448 self.m.addFunc(f) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
449 return f |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
450 |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
451 def newBlock(self): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
452 assert self.fn |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
453 b = self.newBlock2() |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
454 b.function = self.fn |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
455 return b |
277 | 456 |
457 def setFunction(self, f): | |
458 self.fn = f | |
459 self.bb = f.entry if f else None | |
460 | |
461 def setBlock(self, b): | |
462 self.bb = b | |
463 | |
464 def setLoc(self, l): | |
465 self.loc = l | |
466 | |
467 def emit(self, i): | |
468 assert isinstance(i, Statement) | |
469 i.debugLoc = self.loc | |
470 if not self.bb: | |
471 raise Exception('No basic block') | |
472 self.bb.addInstruction(i) | |
473 | |
474 |