comparison 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
comparison
equal deleted inserted replaced
300:158068af716c 301:6753763d3bec
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.entry.function = self
80 self.epiloog = Block('{}_epilog'.format(name))
81 self.epiloog.function = self
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
91 def addBlock(self, bb):
92 self.bbs.append(bb)
93 bb.function = self
94
95 def removeBlock(self, bb):
96 #self.bbs.remove(bb)
97 bb.function = None
98
99 def getBlocks(self):
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
121 Blocks = property(getBlocks)
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
154 self.function = None
155 self.instructions = []
156
157 parent = property(lambda s: s.function)
158
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
179 @property
180 def Instructions(self):
181 return self.instructions
182
183 @property
184 def LastInstruction(self):
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 = []
204 for bb in self.parent.Blocks:
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
281
282 def Sub(a, b):
283 return Binop(a, '-', b)
284
285
286 def Mul(a, b):
287 return Binop(a, '*', b)
288
289
290 def Div(a, b):
291 return Binop(a, '/', b)
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):
371 def changeTarget(self, old, new):
372 idx = self.Targets.index(old)
373 self.Targets[idx] = new
374
375
376 class Terminator(LastStatement):
377 """ Instruction that terminates the terminal block """
378 def __init__(self):
379 self.Targets = []
380
381 def __repr__(self):
382 return 'Terminator'
383
384
385 class Jump(LastStatement):
386 def __init__(self, target):
387 self.Targets = [target]
388
389 def setTarget(self, t):
390 self.Targets[0] = t
391 target = property(lambda s: s.Targets[0], setTarget)
392
393 def __repr__(self):
394 return 'JUMP {}'.format(self.target.name)
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
406 lab_yes = property(lambda s: s.Targets[0])
407 lab_no = property(lambda s: s.Targets[1])
408
409 def __repr__(self):
410 return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no)
411
412
413 # Constructing IR:
414
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
439 self.newBlock2 = NamedClassGenerator('block', Block).gen
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):
450 f = Function(name)
451 self.m.addFunc(f)
452 return f
453
454 def newBlock(self):
455 assert self.fn
456 b = self.newBlock2()
457 b.function = self.fn
458 return b
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