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