Mercurial > lcfOS
annotate python/ppci/ir.py @ 409:8fe299cd2d55 devel
Close devel branch
author | Windel Bouwman |
---|---|
date | Sat, 21 Feb 2015 12:20:10 +0100 |
parents | d1ecc493384e |
children | 5477e499b039 |
rev | line source |
---|---|
277 | 1 """ |
2 Intermediate representation (IR) code classes. | |
3 """ | |
4 | |
310 | 5 |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
6 def label_name(dut): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
7 """ Function that returns the assembly code label name """ |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
8 if isinstance(dut, Block): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
9 f = dut.function |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
10 return label_name(f) + '_' + dut.name |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
11 elif isinstance(dut, Function): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
12 return label_name(dut.module) + '_' + dut.name |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
13 elif isinstance(dut, Module): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
14 return dut.name |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
15 else: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
16 raise NotImplementedError(str(dut)) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
17 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
18 |
277 | 19 class Module: |
305 | 20 """ Container unit for variables and functions. """ |
277 | 21 def __init__(self, name): |
22 self.name = name | |
309 | 23 self.functions = [] |
277 | 24 self.variables = [] |
25 | |
26 def __repr__(self): | |
309 | 27 return 'module {0}'.format(self.name) |
277 | 28 |
309 | 29 def add_function(self, f): |
30 """ Add a function to this module """ | |
31 self.functions.append(f) | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
32 f.module = self |
277 | 33 |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
34 def add_variable(self, v): |
277 | 35 self.variables.append(v) |
36 | |
37 def getVariables(self): | |
38 return self.variables | |
39 | |
40 Variables = property(getVariables) | |
41 | |
42 def getFunctions(self): | |
309 | 43 return self.functions |
277 | 44 |
45 Functions = property(getFunctions) | |
46 | |
47 def findFunction(self, name): | |
48 for f in self.funcs: | |
49 if f.name == name: | |
50 return f | |
51 raise KeyError(name) | |
52 | |
53 getFunction = findFunction | |
54 | |
55 | |
56 class Function: | |
305 | 57 """ Represents a function. """ |
309 | 58 def __init__(self, name, module=None): |
277 | 59 self.name = name |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
60 self.entry = Block('entry') |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
61 self.entry.function = self |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
62 self.epiloog = Block('epilog') |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
63 self.epiloog.function = self |
277 | 64 self.epiloog.addInstruction(Terminator()) |
65 self.return_value = Temp('{}_retval'.format(name)) | |
66 self.arguments = [] | |
67 self.localvars = [] | |
309 | 68 if module: |
69 module.add_function(self) | |
277 | 70 |
71 def __repr__(self): | |
72 args = ','.join(str(a) for a in self.arguments) | |
309 | 73 return 'function i32 {}({})'.format(self.name, args) |
277 | 74 |
309 | 75 def add_block(self, bb): |
76 #self.bbs.append(bb) | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
77 bb.function = self |
277 | 78 |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
79 def removeBlock(self, bb): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
80 #self.bbs.remove(bb) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
81 bb.function = None |
277 | 82 |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
83 def getBlocks(self): |
277 | 84 bbs = [self.entry] |
85 worklist = [self.entry] | |
86 while worklist: | |
87 b = worklist.pop() | |
88 for sb in b.Successors: | |
89 if sb not in bbs: | |
90 bbs.append(sb) | |
91 worklist.append(sb) | |
92 bbs.remove(self.entry) | |
93 if self.epiloog in bbs: | |
94 bbs.remove(self.epiloog) | |
95 bbs.insert(0, self.entry) | |
96 bbs.append(self.epiloog) | |
97 return bbs | |
98 | |
99 def findBasicBlock(self, name): | |
100 for bb in self.bbs: | |
101 if bb.name == name: | |
102 return bb | |
103 raise KeyError(name) | |
104 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
105 Blocks = property(getBlocks) |
277 | 106 |
107 @property | |
108 def Entry(self): | |
109 return self.entry | |
110 | |
111 def check(self): | |
112 for b in self.Blocks: | |
113 b.check() | |
114 | |
115 def addParameter(self, p): | |
116 assert type(p) is Parameter | |
117 p.num = len(self.arguments) | |
118 self.arguments.append(p) | |
119 | |
120 def addLocal(self, l): | |
121 assert type(l) is LocalVariable | |
122 self.localvars.append(l) | |
123 | |
124 | |
125 class Block: | |
305 | 126 """ |
277 | 127 Uninterrupted sequence of instructions with a label at the start. |
128 """ | |
317 | 129 def __init__(self, name, function=None): |
277 | 130 self.name = name |
317 | 131 self.function = function |
277 | 132 self.instructions = [] |
133 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
134 parent = property(lambda s: s.function) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
135 |
277 | 136 def __repr__(self): |
309 | 137 return '{0}:'.format(self.name) |
277 | 138 |
139 def addInstruction(self, i): | |
140 i.parent = self | |
141 assert not isinstance(self.LastInstruction, LastStatement) | |
142 self.instructions.append(i) | |
143 | |
144 def replaceInstruction(self, i1, i2): | |
145 idx = self.instructions.index(i1) | |
146 i1.parent = None | |
147 i1.delete() | |
148 i2.parent = self | |
149 self.instructions[idx] = i2 | |
150 | |
151 def removeInstruction(self, i): | |
152 i.parent = None | |
317 | 153 #i.delete() |
277 | 154 self.instructions.remove(i) |
155 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
156 @property |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
157 def Instructions(self): |
277 | 158 return self.instructions |
159 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
160 @property |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
161 def LastInstruction(self): |
277 | 162 if not self.Empty: |
163 return self.instructions[-1] | |
164 | |
165 @property | |
166 def Empty(self): | |
167 return len(self.instructions) == 0 | |
168 | |
169 @property | |
170 def FirstInstruction(self): | |
171 return self.instructions[0] | |
172 | |
173 def getSuccessors(self): | |
174 if not self.Empty: | |
175 return self.LastInstruction.Targets | |
176 return [] | |
312 | 177 |
277 | 178 Successors = property(getSuccessors) |
179 | |
180 def getPredecessors(self): | |
181 preds = [] | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
182 for bb in self.parent.Blocks: |
277 | 183 if self in bb.Successors: |
184 preds.append(bb) | |
185 return preds | |
312 | 186 |
277 | 187 Predecessors = property(getPredecessors) |
188 | |
189 def precedes(self, other): | |
190 raise NotImplementedError() | |
191 | |
192 | |
193 # Instructions: | |
194 | |
195 class Expression: | |
304 | 196 """ Base class for an expression """ |
277 | 197 pass |
198 | |
199 | |
200 class Const(Expression): | |
304 | 201 """ Represents a constant value """ |
277 | 202 def __init__(self, value): |
203 self.value = value | |
204 | |
205 def __repr__(self): | |
206 return 'Const {}'.format(self.value) | |
207 | |
208 | |
209 class Call(Expression): | |
305 | 210 """ Call a function with some arguments """ |
277 | 211 def __init__(self, f, arguments): |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
317
diff
changeset
|
212 assert type(f) is str |
277 | 213 self.f = f |
214 self.arguments = arguments | |
215 | |
216 def __repr__(self): | |
217 args = ', '.join([str(arg) for arg in self.arguments]) | |
305 | 218 return '{}({})'.format(self.f, args) |
277 | 219 |
220 | |
221 # Data operations | |
222 class Binop(Expression): | |
304 | 223 """ Generic binary operation """ |
277 | 224 ops = ['+', '-', '*', '/', '|', '&', '<<', '>>'] |
305 | 225 |
277 | 226 def __init__(self, value1, operation, value2): |
227 assert operation in Binop.ops | |
228 self.a = value1 | |
229 self.b = value2 | |
230 self.operation = operation | |
231 | |
232 def __repr__(self): | |
233 a, b = self.a, self.b | |
234 return '({} {} {})'.format(a, self.operation, b) | |
235 | |
236 | |
237 def Add(a, b): | |
305 | 238 """ Add a and b """ |
277 | 239 return Binop(a, '+', b) |
240 | |
292 | 241 |
279 | 242 def Sub(a, b): |
305 | 243 """ Substract b from a """ |
279 | 244 return Binop(a, '-', b) |
245 | |
292 | 246 |
279 | 247 def Mul(a, b): |
309 | 248 """ Multiply a by b """ |
279 | 249 return Binop(a, '*', b) |
250 | |
292 | 251 |
279 | 252 def Div(a, b): |
309 | 253 """ Divide a in b pieces """ |
279 | 254 return Binop(a, '/', b) |
277 | 255 |
303 | 256 |
277 | 257 class Eseq(Expression): |
258 """ Sequence of instructions where the last is an expression """ | |
259 def __init__(self, stmt, e): | |
260 self.stmt = stmt | |
261 self.e = e | |
262 | |
263 def __repr__(self): | |
264 return '({}, {})'.format(self.stmt, self.e) | |
265 | |
266 | |
267 class Alloc(Expression): | |
268 """ Allocates space on the stack """ | |
269 def __init__(self): | |
270 super().__init__() | |
271 | |
272 def __repr__(self): | |
273 return 'Alloc' | |
274 | |
275 | |
276 class Variable(Expression): | |
277 def __init__(self, name): | |
278 self.name = name | |
279 | |
280 def __repr__(self): | |
281 return 'Var {}'.format(self.name) | |
282 | |
283 | |
284 class LocalVariable(Variable): | |
285 def __repr__(self): | |
286 return 'Local {}'.format(self.name) | |
287 | |
288 | |
289 class Parameter(Variable): | |
290 def __repr__(self): | |
291 return 'Param {}'.format(self.name) | |
292 | |
293 | |
294 class Temp(Expression): | |
295 """ Temporary storage, same as register """ | |
296 def __init__(self, name): | |
297 self.name = name | |
298 | |
299 def __repr__(self): | |
300 return 'TMP_{}'.format(self.name) | |
301 | |
302 | |
303 class Mem(Expression): | |
305 | 304 """ Memory access """ |
277 | 305 def __init__(self, e): |
306 self.e = e | |
307 | |
308 def __repr__(self): | |
309 return '[{}]'.format(self.e) | |
310 | |
311 | |
312 class Statement: | |
313 """ Base class for all instructions. """ | |
312 | 314 @property |
315 def IsTerminator(self): | |
316 return isinstance(self, LastStatement) | |
277 | 317 |
318 | |
319 class Move(Statement): | |
305 | 320 """ Move source to destination """ |
277 | 321 def __init__(self, dst, src): |
322 self.dst = dst | |
323 self.src = src | |
324 | |
325 def __repr__(self): | |
326 return '{} = {}'.format(self.dst, self.src) | |
327 | |
328 | |
329 class Exp(Statement): | |
330 def __init__(self, e): | |
331 self.e = e | |
332 | |
333 def __repr__(self): | |
334 return '{}'.format(self.e) | |
335 | |
336 | |
337 # Branching: | |
338 class LastStatement(Statement): | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
339 def changeTarget(self, old, new): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
340 idx = self.Targets.index(old) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
341 self.Targets[idx] = new |
277 | 342 |
343 | |
344 class Terminator(LastStatement): | |
345 """ Instruction that terminates the terminal block """ | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
346 def __init__(self): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
347 self.Targets = [] |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
348 |
277 | 349 def __repr__(self): |
350 return 'Terminator' | |
351 | |
352 | |
353 class Jump(LastStatement): | |
304 | 354 """ Jump statement to some target location """ |
277 | 355 def __init__(self, target): |
356 self.Targets = [target] | |
357 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
358 def setTarget(self, t): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
359 self.Targets[0] = t |
310 | 360 |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
361 target = property(lambda s: s.Targets[0], setTarget) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
362 |
277 | 363 def __repr__(self): |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
364 return 'JUMP {}'.format(self.target.name) |
277 | 365 |
366 | |
367 class CJump(LastStatement): | |
305 | 368 """ Conditional jump to true or false labels. """ |
277 | 369 conditions = ['==', '<', '>', '>=', '<=', '!='] |
305 | 370 |
277 | 371 def __init__(self, a, cond, b, lab_yes, lab_no): |
305 | 372 assert cond in CJump.conditions |
277 | 373 self.a = a |
374 self.cond = cond | |
375 self.b = b | |
376 self.Targets = [lab_yes, lab_no] | |
377 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
378 lab_yes = property(lambda s: s.Targets[0]) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
379 lab_no = property(lambda s: s.Targets[1]) |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
380 |
277 | 381 def __repr__(self): |
305 | 382 return 'IF {} {} {} THEN {} ELSE {}'\ |
383 .format(self.a, self.cond, self.b, self.lab_yes, self.lab_no) |