Mercurial > lcfOS
annotate python/ppci/c3/codegenerator.py @ 362:c05ab629976a
Added CPUID for arm
author | Windel Bouwman |
---|---|
date | Sat, 15 Mar 2014 10:56:34 +0100 |
parents | 42343d189e14 |
children | 396e5cefba13 |
rev | line source |
---|---|
255 | 1 import logging |
354 | 2 import struct |
301 | 3 from .. import ir |
307 | 4 from .. import irutils |
308 | 5 from . import astnodes as ast |
230 | 6 |
228 | 7 |
307 | 8 class SemanticError(Exception): |
308 | 9 """ Error thrown when a semantic issue is observed """ |
307 | 10 def __init__(self, msg, loc): |
308 | 11 super().__init__() |
307 | 12 self.msg = msg |
13 self.loc = loc | |
14 | |
15 | |
16 class CodeGenerator(irutils.Builder): | |
288 | 17 """ |
274 | 18 Generates intermediate (IR) code from a package. The entry function is |
19 'genModule'. The main task of this part is to rewrite complex control | |
20 structures, such as while and for loops into simple conditional | |
21 jump statements. Also complex conditional statements are simplified. | |
22 Such as 'and' and 'or' statements are rewritten in conditional jumps. | |
23 And structured datatypes are rewritten. | |
307 | 24 |
25 Type checking is done in one run with code generation. | |
274 | 26 """ |
307 | 27 def __init__(self, diag): |
261 | 28 self.logger = logging.getLogger('c3cgen') |
307 | 29 self.diag = diag |
261 | 30 |
217 | 31 def gencode(self, pkg): |
308 | 32 """ Generate code for a single module """ |
268 | 33 self.prepare() |
308 | 34 assert type(pkg) is ast.Package |
307 | 35 self.pkg = pkg |
36 self.intType = pkg.scope['int'] | |
37 self.boolType = pkg.scope['bool'] | |
334 | 38 self.logger.debug('Generating ir-code for {}'.format(pkg.name), extra={'c3_ast':pkg}) |
288 | 39 self.varMap = {} # Maps variables to storage locations. |
217 | 40 self.funcMap = {} |
268 | 41 self.m = ir.Module(pkg.name) |
307 | 42 try: |
362 | 43 # Only generate function if function contains a body: |
44 real_functions = list(filter(lambda f: f.body, pkg.innerScope.Functions)) | |
45 #real_functions = list(filter(None, pkg.innerScope.Functions)) | |
46 for s in real_functions: | |
307 | 47 f = self.newFunction(s.name) |
48 self.funcMap[s] = f | |
49 for v in pkg.innerScope.Variables: | |
50 self.varMap[v] = self.newTemp() | |
362 | 51 for s in real_functions: |
308 | 52 self.gen_function(s) |
307 | 53 except SemanticError as e: |
54 self.error(e.msg, e.loc) | |
313 | 55 if self.pkg.ok: |
56 return self.m | |
308 | 57 |
58 def error(self, msg, loc=None): | |
59 self.pkg.ok = False | |
60 self.diag.error(msg, loc) | |
307 | 61 |
308 | 62 def gen_function(self, fn): |
268 | 63 # TODO: handle arguments |
64 f = self.funcMap[fn] | |
272 | 65 f.return_value = self.newTemp() |
268 | 66 self.setFunction(f) |
269 | 67 l2 = self.newBlock() |
68 self.emit(ir.Jump(l2)) | |
69 self.setBlock(l2) | |
268 | 70 # generate room for locals: |
174 | 71 |
268 | 72 for sym in fn.innerScope: |
316 | 73 self.the_type(sym.typ) |
272 | 74 if sym.isParameter: |
316 | 75 p = ir.Parameter(sym.name) |
76 variable = ir.LocalVariable(sym.name + '_copy') | |
77 f.addParameter(p) | |
78 f.addLocal(variable) | |
79 # Move parameter into local copy: | |
80 self.emit(ir.Move(ir.Mem(variable), p)) | |
274 | 81 elif sym.isLocal: |
308 | 82 variable = ir.LocalVariable(sym.name) |
83 f.addLocal(variable) | |
84 elif isinstance(sym, ast.Variable): | |
85 variable = ir.LocalVariable(sym.name) | |
86 f.addLocal(variable) | |
274 | 87 else: |
275 | 88 raise NotImplementedError('{}'.format(sym)) |
308 | 89 self.varMap[sym] = variable |
268 | 90 |
91 self.genCode(fn.body) | |
272 | 92 self.emit(ir.Move(f.return_value, ir.Const(0))) |
269 | 93 self.emit(ir.Jump(f.epiloog)) |
268 | 94 self.setFunction(None) |
158 | 95 |
217 | 96 def genCode(self, code): |
308 | 97 """ Wrapper around gen_stmt to catch errors """ |
307 | 98 try: |
308 | 99 self.gen_stmt(code) |
307 | 100 except SemanticError as e: |
101 self.error(e.msg, e.loc) | |
102 | |
308 | 103 def gen_stmt(self, code): |
104 """ Generate code for a statement """ | |
105 assert isinstance(code, ast.Statement) | |
268 | 106 self.setLoc(code.loc) |
308 | 107 if type(code) is ast.Compound: |
221 | 108 for s in code.statements: |
109 self.genCode(s) | |
308 | 110 elif type(code) is ast.Empty: |
306 | 111 pass |
308 | 112 elif type(code) is ast.Assignment: |
268 | 113 lval = self.genExprCode(code.lval) |
307 | 114 rval = self.genExprCode(code.rval) |
115 if not self.equalTypes(code.lval.typ, code.rval.typ): | |
315 | 116 msg = 'Cannot assign {} to {}'.format(code.rval.typ, code.lval.typ) |
307 | 117 raise SemanticError(msg, code.loc) |
118 if not code.lval.lvalue: | |
119 raise SemanticError('No valid lvalue {}'.format(code.lval), code.lval.loc) | |
268 | 120 self.emit(ir.Move(lval, rval)) |
308 | 121 elif type(code) is ast.ExpressionStatement: |
275 | 122 self.emit(ir.Exp(self.genExprCode(code.ex))) |
308 | 123 elif type(code) is ast.If: |
268 | 124 bbtrue = self.newBlock() |
125 bbfalse = self.newBlock() | |
126 te = self.newBlock() | |
308 | 127 self.gen_cond_code(code.condition, bbtrue, bbfalse) |
268 | 128 self.setBlock(bbtrue) |
129 self.genCode(code.truestatement) | |
130 self.emit(ir.Jump(te)) | |
131 self.setBlock(bbfalse) | |
306 | 132 self.genCode(code.falsestatement) |
268 | 133 self.emit(ir.Jump(te)) |
134 self.setBlock(te) | |
308 | 135 elif type(code) is ast.Return: |
303 | 136 re = self.genExprCode(code.expr) |
137 self.emit(ir.Move(self.fn.return_value, re)) | |
138 self.emit(ir.Jump(self.fn.epiloog)) | |
139 b = self.newBlock() | |
140 self.setBlock(b) | |
308 | 141 elif type(code) is ast.While: |
268 | 142 bbdo = self.newBlock() |
143 bbtest = self.newBlock() | |
144 te = self.newBlock() | |
145 self.emit(ir.Jump(bbtest)) | |
146 self.setBlock(bbtest) | |
308 | 147 self.gen_cond_code(code.condition, bbdo, te) |
268 | 148 self.setBlock(bbdo) |
228 | 149 self.genCode(code.statement) |
268 | 150 self.emit(ir.Jump(bbtest)) |
151 self.setBlock(te) | |
315 | 152 elif type(code) is ast.For: |
153 bbdo = self.newBlock() | |
154 bbtest = self.newBlock() | |
155 te = self.newBlock() | |
156 self.genCode(code.init) | |
157 self.emit(ir.Jump(bbtest)) | |
158 self.setBlock(bbtest) | |
159 self.gen_cond_code(code.condition, bbdo, te) | |
160 self.setBlock(bbdo) | |
161 self.genCode(code.statement) | |
360 | 162 self.genCode(code.final) |
315 | 163 self.emit(ir.Jump(bbtest)) |
164 self.setBlock(te) | |
222 | 165 else: |
268 | 166 raise NotImplementedError('Unknown stmt {}'.format(code)) |
230 | 167 |
308 | 168 def gen_cond_code(self, expr, bbtrue, bbfalse): |
169 """ Generate conditional logic. | |
170 Implement sequential logical operators. """ | |
171 if type(expr) is ast.Binop: | |
268 | 172 if expr.op == 'or': |
173 l2 = self.newBlock() | |
308 | 174 self.gen_cond_code(expr.a, bbtrue, l2) |
175 if not self.equalTypes(expr.a.typ, self.boolType): | |
307 | 176 raise SemanticError('Must be boolean', expr.a.loc) |
268 | 177 self.setBlock(l2) |
308 | 178 self.gen_cond_code(expr.b, bbtrue, bbfalse) |
179 if not self.equalTypes(expr.b.typ, self.boolType): | |
307 | 180 raise SemanticError('Must be boolean', expr.b.loc) |
268 | 181 elif expr.op == 'and': |
182 l2 = self.newBlock() | |
308 | 183 self.gen_cond_code(expr.a, l2, bbfalse) |
184 if not self.equalTypes(expr.a.typ, self.boolType): | |
307 | 185 self.error('Must be boolean', expr.a.loc) |
268 | 186 self.setBlock(l2) |
308 | 187 self.gen_cond_code(expr.b, bbtrue, bbfalse) |
188 if not self.equalTypes(expr.b.typ, self.boolType): | |
307 | 189 raise SemanticError('Must be boolean', expr.b.loc) |
305 | 190 elif expr.op in ['==', '>', '<', '!=', '<=', '>=']: |
228 | 191 ta = self.genExprCode(expr.a) |
192 tb = self.genExprCode(expr.b) | |
307 | 193 if not self.equalTypes(expr.a.typ, expr.b.typ): |
194 raise SemanticError('Types unequal {} != {}' | |
195 .format(expr.a.typ, expr.b.typ), expr.loc) | |
268 | 196 self.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse)) |
197 else: | |
311 | 198 raise SemanticError('non-bool: {}'.format(expr.op), expr.loc) |
307 | 199 expr.typ = self.boolType |
308 | 200 elif type(expr) is ast.Literal: |
201 self.genExprCode(expr) | |
288 | 202 if expr.val: |
268 | 203 self.emit(ir.Jump(bbtrue)) |
288 | 204 else: |
268 | 205 self.emit(ir.Jump(bbfalse)) |
228 | 206 else: |
288 | 207 raise NotImplementedError('Unknown cond {}'.format(expr)) |
354 | 208 |
209 # Check that the condition is a boolean value: | |
307 | 210 if not self.equalTypes(expr.typ, self.boolType): |
211 self.error('Condition must be boolean', expr.loc) | |
230 | 212 |
217 | 213 def genExprCode(self, expr): |
308 | 214 """ Generate code for an expression. Return the generated ir-value """ |
215 assert isinstance(expr, ast.Expression) | |
216 if type(expr) is ast.Binop: | |
307 | 217 expr.lvalue = False |
218 if expr.op in ['+', '-', '*', '/', '<<', '>>', '|', '&']: | |
219 ra = self.genExprCode(expr.a) | |
220 rb = self.genExprCode(expr.b) | |
221 if self.equalTypes(expr.a.typ, self.intType) and \ | |
222 self.equalTypes(expr.b.typ, self.intType): | |
223 expr.typ = expr.a.typ | |
224 else: | |
225 raise SemanticError('Can only add integers', expr.loc) | |
226 else: | |
227 raise NotImplementedError("Cannot use equality as expressions") | |
268 | 228 return ir.Binop(ra, expr.op, rb) |
308 | 229 elif type(expr) is ast.Unop: |
307 | 230 if expr.op == '&': |
231 ra = self.genExprCode(expr.a) | |
308 | 232 expr.typ = ast.PointerType(expr.a.typ) |
307 | 233 if not expr.a.lvalue: |
234 raise SemanticError('No valid lvalue', expr.a.loc) | |
235 expr.lvalue = False | |
236 assert type(ra) is ir.Mem | |
237 return ra.e | |
238 else: | |
239 raise NotImplementedError('Unknown unop {0}'.format(expr.op)) | |
308 | 240 elif type(expr) is ast.Identifier: |
307 | 241 # Generate code for this identifier. |
242 tg = self.resolveSymbol(expr) | |
243 expr.kind = type(tg) | |
244 expr.typ = tg.typ | |
279 | 245 # This returns the dereferenced variable. |
308 | 246 if isinstance(tg, ast.Variable): |
313 | 247 expr.lvalue = True |
307 | 248 return ir.Mem(self.varMap[tg]) |
313 | 249 elif isinstance(tg, ast.Constant): |
250 c_val = self.genExprCode(tg.value) | |
251 return self.evalConst(c_val) | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
252 else: |
308 | 253 raise NotImplementedError(str(tg)) |
254 elif type(expr) is ast.Deref: | |
222 | 255 # dereference pointer type: |
225 | 256 addr = self.genExprCode(expr.ptr) |
316 | 257 ptr_typ = self.the_type(expr.ptr.typ) |
307 | 258 expr.lvalue = True |
308 | 259 if type(ptr_typ) is ast.PointerType: |
307 | 260 expr.typ = ptr_typ.ptype |
261 return ir.Mem(addr) | |
262 else: | |
263 raise SemanticError('Cannot deref non-pointer', expr.loc) | |
308 | 264 elif type(expr) is ast.Member: |
279 | 265 base = self.genExprCode(expr.base) |
307 | 266 expr.lvalue = expr.base.lvalue |
316 | 267 basetype = self.the_type(expr.base.typ) |
308 | 268 if type(basetype) is ast.StructureType: |
307 | 269 if basetype.hasField(expr.field): |
270 expr.typ = basetype.fieldType(expr.field) | |
271 else: | |
272 raise SemanticError('{} does not contain field {}' | |
308 | 273 .format(basetype, expr.field), expr.loc) |
307 | 274 else: |
308 | 275 raise SemanticError('Cannot select {} of non-structure type {}' |
276 .format(expr.field, basetype), expr.loc) | |
307 | 277 |
279 | 278 assert type(base) is ir.Mem, type(base) |
316 | 279 bt = self.the_type(expr.base.typ) |
268 | 280 offset = ir.Const(bt.fieldOffset(expr.field)) |
308 | 281 return ir.Mem(ir.Add(base.e, offset)) |
354 | 282 elif type(expr) is ast.Index: |
283 """ Array indexing """ | |
284 base = self.genExprCode(expr.base) | |
285 idx = self.genExprCode(expr.i) | |
286 base_typ = self.the_type(expr.base.typ) | |
287 if not isinstance(base_typ, ast.ArrayType): | |
288 raise SemanticError('Cannot index non-array type {}'.format(base_typ), expr.base.loc) | |
289 idx_type = self.the_type(expr.i.typ) | |
290 if not self.equalTypes(idx_type, self.intType): | |
291 raise SemanticError('Index must be int not {}'.format(idx_type), expr.i.loc) | |
292 assert type(base) is ir.Mem | |
293 element_type = self.the_type(base_typ.element_type) | |
294 element_size = self.size_of(element_type) | |
295 expr.typ = base_typ.element_type | |
296 expr.lvalue = True | |
297 | |
298 return ir.Mem(ir.Add(base.e, ir.Mul(idx, ir.Const(element_size)))) | |
308 | 299 elif type(expr) is ast.Literal: |
307 | 300 expr.lvalue = False |
313 | 301 typemap = {int: 'int', float: 'double', bool: 'bool', str:'string'} |
307 | 302 if type(expr.val) in typemap: |
303 expr.typ = self.pkg.scope[typemap[type(expr.val)]] | |
304 else: | |
312 | 305 raise SemanticError('Unknown literal type {}'.format(expr.val), expr.loc) |
354 | 306 # Construct correct const value: |
307 if type(expr.val) is str: | |
308 cval = struct.pack('<I', len(expr.val)) + expr.val.encode('ascii') | |
309 return ir.Addr(ir.Const(cval)) | |
310 else: | |
311 return ir.Const(expr.val) | |
308 | 312 elif type(expr) is ast.TypeCast: |
313 return self.gen_type_cast(expr) | |
314 elif type(expr) is ast.FunctionCall: | |
315 return self.gen_function_call(expr) | |
225 | 316 else: |
259 | 317 raise NotImplementedError('Unknown expr {}'.format(expr)) |
307 | 318 |
308 | 319 def gen_type_cast(self, expr): |
320 """ Generate code for type casting """ | |
321 ar = self.genExprCode(expr.a) | |
316 | 322 from_type = self.the_type(expr.a.typ) |
323 to_type = self.the_type(expr.to_type) | |
308 | 324 if isinstance(from_type, ast.PointerType) and isinstance(to_type, ast.PointerType): |
325 expr.typ = expr.to_type | |
326 return ar | |
327 elif type(from_type) is ast.BaseType and from_type.name == 'int' and \ | |
328 isinstance(to_type, ast.PointerType): | |
329 expr.typ = expr.to_type | |
330 return ar | |
354 | 331 elif type(from_type) is ast.BaseType and from_type.name == 'byte' and \ |
332 type(to_type) is ast.BaseType and to_type.name == 'int': | |
333 expr.typ = expr.to_type | |
334 return ar | |
308 | 335 else: |
336 raise SemanticError('Cannot cast {} to {}' | |
337 .format(from_type, to_type), expr.loc) | |
353 | 338 |
308 | 339 def gen_function_call(self, expr): |
340 """ Generate code for a function call """ | |
341 # Evaluate the arguments: | |
342 args = [self.genExprCode(e) for e in expr.args] | |
343 # Check arguments: | |
344 tg = self.resolveSymbol(expr.proc) | |
345 if type(tg) is not ast.Function: | |
346 raise SemanticError('cannot call {}'.format(tg)) | |
347 ftyp = tg.typ | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
334
diff
changeset
|
348 fname = tg.package.name + '_' + tg.name |
308 | 349 ptypes = ftyp.parametertypes |
350 if len(expr.args) != len(ptypes): | |
351 raise SemanticError('{} requires {} arguments, {} given' | |
352 .format(fname, len(ptypes), len(expr.args)), expr.loc) | |
353 for arg, at in zip(expr.args, ptypes): | |
354 if not self.equalTypes(arg.typ, at): | |
355 raise SemanticError('Got {}, expected {}' | |
356 .format(arg.typ, at), arg.loc) | |
357 # determine return type: | |
358 expr.typ = ftyp.returntype | |
359 return ir.Call(fname, args) | |
360 | |
313 | 361 def evalConst(self, c): |
362 if isinstance(c, ir.Const): | |
363 return c | |
364 else: | |
365 raise SemanticError('Cannot evaluate constant {}'.format(c)) | |
366 | |
307 | 367 def resolveSymbol(self, sym): |
308 | 368 if type(sym) is ast.Member: |
307 | 369 base = self.resolveSymbol(sym.base) |
308 | 370 if type(base) is not ast.Package: |
371 raise SemanticError('Base is not a package', sym.loc) | |
307 | 372 scope = base.innerScope |
373 name = sym.field | |
308 | 374 elif type(sym) is ast.Identifier: |
307 | 375 scope = sym.scope |
376 name = sym.target | |
377 else: | |
378 raise NotImplementedError(str(sym)) | |
379 if name in scope: | |
380 s = scope[name] | |
381 else: | |
382 raise SemanticError('{} undefined'.format(name), sym.loc) | |
308 | 383 assert isinstance(s, ast.Symbol) |
307 | 384 return s |
385 | |
316 | 386 def size_of(self, t): |
387 """ Determine the byte size of a type """ | |
388 t = self.the_type(t) | |
389 if type(t) is ast.BaseType: | |
390 return t.bytesize | |
391 elif type(t) is ast.StructureType: | |
392 return sum(self.size_of(mem.typ) for mem in t.mems) | |
354 | 393 elif type(t) is ast.ArrayType: |
394 return t.size * self.size_of(t.element_type) | |
316 | 395 else: |
396 raise NotImplementedError(str(t)) | |
397 | |
398 def the_type(self, t): | |
307 | 399 """ Recurse until a 'real' type is found """ |
308 | 400 if type(t) is ast.DefinedType: |
316 | 401 t = self.the_type(t.typ) |
308 | 402 elif type(t) in [ast.Identifier, ast.Member]: |
316 | 403 t = self.the_type(self.resolveSymbol(t)) |
404 elif type(t) is ast.StructureType: | |
405 # Setup offsets of fields. Is this the right place?: | |
406 offset = 0 | |
407 for mem in t.mems: | |
408 mem.offset = offset | |
409 offset = offset + self.size_of(mem.typ) | |
308 | 410 elif isinstance(t, ast.Type): |
307 | 411 pass |
412 else: | |
413 raise NotImplementedError(str(t)) | |
308 | 414 assert isinstance(t, ast.Type) |
307 | 415 return t |
416 | |
417 def equalTypes(self, a, b): | |
418 """ Compare types a and b for structural equavalence. """ | |
419 # Recurse into named types: | |
316 | 420 a = self.the_type(a) |
421 b = self.the_type(b) | |
307 | 422 |
423 if type(a) is type(b): | |
308 | 424 if type(a) is ast.BaseType: |
307 | 425 return a.name == b.name |
308 | 426 elif type(a) is ast.PointerType: |
307 | 427 return self.equalTypes(a.ptype, b.ptype) |
308 | 428 elif type(a) is ast.StructureType: |
307 | 429 if len(a.mems) != len(b.mems): |
430 return False | |
431 return all(self.equalTypes(am.typ, bm.typ) for am, bm in | |
432 zip(a.mems, b.mems)) | |
354 | 433 elif type(a) is ast.ArrayType: |
434 return self.equalTypes(a.element_type, b.element_type) | |
307 | 435 else: |
436 raise NotImplementedError('{} not implemented'.format(type(a))) | |
437 return False |