Mercurial > lcfOS
annotate python/ppci/ir.py @ 303:be7f60545368
Final fixups
author | Windel Bouwman |
---|---|
date | Fri, 06 Dec 2013 12:37:48 +0100 |
parents | 6753763d3bec |
children | fa99f36fabb5 |
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 | |
292 | 281 |
279 | 282 def Sub(a, b): |
283 return Binop(a, '-', b) | |
284 | |
292 | 285 |
279 | 286 def Mul(a, b): |
287 return Binop(a, '*', b) | |
288 | |
292 | 289 |
279 | 290 def Div(a, b): |
291 return Binop(a, '/', b) | |
277 | 292 |
303 | 293 |
277 | 294 class Eseq(Expression): |
295 """ Sequence of instructions where the last is an expression """ | |
296 def __init__(self, stmt, e): | |
297 self.stmt = stmt | |
298 self.e = e | |
299 | |
300 def __repr__(self): | |
301 return '({}, {})'.format(self.stmt, self.e) | |
302 | |
303 | |
304 class Alloc(Expression): | |
305 """ Allocates space on the stack """ | |
306 def __init__(self): | |
307 super().__init__() | |
308 | |
309 def __repr__(self): | |
310 return 'Alloc' | |
311 | |
312 | |
313 class Variable(Expression): | |
314 def __init__(self, name): | |
315 self.name = name | |
316 | |
317 def __repr__(self): | |
318 return 'Var {}'.format(self.name) | |
319 | |
320 | |
321 class LocalVariable(Variable): | |
322 def __repr__(self): | |
323 return 'Local {}'.format(self.name) | |
324 | |
325 | |
326 class Parameter(Variable): | |
327 def __repr__(self): | |
328 return 'Param {}'.format(self.name) | |
329 | |
330 | |
331 class Temp(Expression): | |
332 """ Temporary storage, same as register """ | |
333 def __init__(self, name): | |
334 self.name = name | |
335 | |
336 def __repr__(self): | |
337 return 'TMP_{}'.format(self.name) | |
338 | |
339 | |
340 class Mem(Expression): | |
341 def __init__(self, e): | |
342 self.e = e | |
343 | |
344 def __repr__(self): | |
345 return '[{}]'.format(self.e) | |
346 | |
347 | |
348 class Statement: | |
349 """ Base class for all instructions. """ | |
350 pass | |
351 | |
352 | |
353 class Move(Statement): | |
354 def __init__(self, dst, src): | |
355 self.dst = dst | |
356 self.src = src | |
357 | |
358 def __repr__(self): | |
359 return '{} = {}'.format(self.dst, self.src) | |
360 | |
361 | |
362 class Exp(Statement): | |
363 def __init__(self, e): | |
364 self.e = e | |
365 | |
366 def __repr__(self): | |
367 return '{}'.format(self.e) | |
368 | |
369 | |
370 # Branching: | |
371 class LastStatement(Statement): | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
372 def changeTarget(self, old, new): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
373 idx = self.Targets.index(old) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
374 self.Targets[idx] = new |
277 | 375 |
376 | |
377 class Terminator(LastStatement): | |
378 """ Instruction that terminates the terminal block """ | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
379 def __init__(self): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
380 self.Targets = [] |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
381 |
277 | 382 def __repr__(self): |
383 return 'Terminator' | |
384 | |
385 | |
386 class Jump(LastStatement): | |
387 def __init__(self, target): | |
388 self.Targets = [target] | |
389 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
390 def setTarget(self, t): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
391 self.Targets[0] = t |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
392 target = property(lambda s: s.Targets[0], setTarget) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
393 |
277 | 394 def __repr__(self): |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
395 return 'JUMP {}'.format(self.target.name) |
277 | 396 |
397 | |
398 class CJump(LastStatement): | |
399 conditions = ['==', '<', '>', '>=', '<=', '!='] | |
400 def __init__(self, a, cond, b, lab_yes, lab_no): | |
401 assert cond in CJump.conditions | |
402 self.a = a | |
403 self.cond = cond | |
404 self.b = b | |
405 self.Targets = [lab_yes, lab_no] | |
406 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
407 lab_yes = property(lambda s: s.Targets[0]) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
408 lab_no = property(lambda s: s.Targets[1]) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
409 |
277 | 410 def __repr__(self): |
411 return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no) | |
412 | |
413 | |
279 | 414 # Constructing IR: |
415 | |
277 | 416 class NamedClassGenerator: |
417 def __init__(self, prefix, cls): | |
418 self.prefix = prefix | |
419 self.cls = cls | |
420 def NumGen(): | |
421 a = 0 | |
422 while True: | |
423 yield a | |
424 a = a + 1 | |
425 self.nums = NumGen() | |
426 | |
427 def gen(self, prefix=None): | |
428 if not prefix: | |
429 prefix = self.prefix | |
430 return self.cls('{0}{1}'.format(prefix, self.nums.__next__())) | |
431 | |
432 | |
433 class Builder: | |
434 """ Base class for ir code generators """ | |
435 def __init__(self): | |
436 self.prepare() | |
437 | |
438 def prepare(self): | |
439 self.newTemp = NamedClassGenerator('reg', Temp).gen | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
440 self.newBlock2 = NamedClassGenerator('block', Block).gen |
277 | 441 self.bb = None |
442 self.m = None | |
443 self.fn = None | |
444 self.loc = None | |
445 | |
446 # Helpers: | |
447 def setModule(self, m): | |
448 self.m = m | |
449 | |
450 def newFunction(self, name): | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
451 f = Function(name) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
452 self.m.addFunc(f) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
453 return f |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
454 |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
455 def newBlock(self): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
456 assert self.fn |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
457 b = self.newBlock2() |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
458 b.function = self.fn |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
459 return b |
277 | 460 |
461 def setFunction(self, f): | |
462 self.fn = f | |
463 self.bb = f.entry if f else None | |
464 | |
465 def setBlock(self, b): | |
466 self.bb = b | |
467 | |
468 def setLoc(self, l): | |
469 self.loc = l | |
470 | |
471 def emit(self, i): | |
472 assert isinstance(i, Statement) | |
473 i.debugLoc = self.loc | |
474 if not self.bb: | |
475 raise Exception('No basic block') | |
476 self.bb.addInstruction(i) |