Mercurial > lcfOS
diff python/ppci/c3/codegenerator.py @ 300:158068af716c
yafm
author | Windel Bouwman |
---|---|
date | Tue, 03 Dec 2013 18:00:22 +0100 |
parents | python/c3/codegenerator.py@a747a45dcd78 |
children | 6753763d3bec |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/c3/codegenerator.py Tue Dec 03 18:00:22 2013 +0100 @@ -0,0 +1,198 @@ +import logging +import ir +from . import astnodes +from .scope import boolType, intType +from ppci import CompilerError +from .analyse import theType + + +class CodeGenerator(ir.Builder): + """ + Generates intermediate (IR) code from a package. The entry function is + 'genModule'. The main task of this part is to rewrite complex control + structures, such as while and for loops into simple conditional + jump statements. Also complex conditional statements are simplified. + Such as 'and' and 'or' statements are rewritten in conditional jumps. + And structured datatypes are rewritten. + """ + def __init__(self): + self.logger = logging.getLogger('c3cgen') + + def gencode(self, pkg): + self.prepare() + assert type(pkg) is astnodes.Package + self.logger.info('Generating ir-code for {}'.format(pkg.name)) + self.varMap = {} # Maps variables to storage locations. + self.funcMap = {} + self.m = ir.Module(pkg.name) + self.genModule(pkg) + return self.m + + # inner helpers: + def genModule(self, pkg): + # Take care of forward declarations: + for s in pkg.innerScope.Functions: + f = self.newFunction(s.name) + self.funcMap[s] = f + for v in pkg.innerScope.Variables: + self.varMap[v] = self.newTemp() + for s in pkg.innerScope.Functions: + self.genFunction(s) + + def genFunction(self, fn): + # TODO: handle arguments + f = self.funcMap[fn] + f.return_value = self.newTemp() + # TODO reserve room for stack, this can be done at later point? + self.setFunction(f) + l2 = self.newBlock() + self.emit(ir.Jump(l2)) + self.setBlock(l2) + # generate room for locals: + + for sym in fn.innerScope: + # TODO: handle parameters different + if sym.isParameter: + v = ir.Parameter(sym.name) + f.addParameter(v) + elif sym.isLocal: + v = ir.LocalVariable(sym.name) + f.addLocal(v) + else: + #v = self.newTemp() + raise NotImplementedError('{}'.format(sym)) + # TODO: make this ssa here?? + self.varMap[sym] = v + + self.genCode(fn.body) + # Set the default return value to zero: + # TBD: this may not be required? + self.emit(ir.Move(f.return_value, ir.Const(0))) + self.emit(ir.Jump(f.epiloog)) + self.setFunction(None) + + def genCode(self, code): + assert isinstance(code, astnodes.Statement) + self.setLoc(code.loc) + if type(code) is astnodes.CompoundStatement: + for s in code.statements: + self.genCode(s) + elif type(code) is astnodes.Assignment: + rval = self.genExprCode(code.rval) + lval = self.genExprCode(code.lval) + self.emit(ir.Move(lval, rval)) + elif type(code) is astnodes.ExpressionStatement: + self.emit(ir.Exp(self.genExprCode(code.ex))) + elif type(code) is astnodes.IfStatement: + bbtrue = self.newBlock() + bbfalse = self.newBlock() + te = self.newBlock() + self.genCondCode(code.condition, bbtrue, bbfalse) + self.setBlock(bbtrue) + self.genCode(code.truestatement) + self.emit(ir.Jump(te)) + self.setBlock(bbfalse) + if code.falsestatement: + self.genCode(code.falsestatement) + self.emit(ir.Jump(te)) + self.setBlock(te) + elif type(code) is astnodes.ReturnStatement: + if code.expr: + re = self.genExprCode(code.expr) + self.emit(ir.Move(self.fn.return_value, re)) + self.emit(ir.Jump(self.fn.epiloog)) + b = self.newBlock() + self.setBlock(b) + else: + self.builder.addIns(ir.Return()) + elif type(code) is astnodes.WhileStatement: + bbdo = self.newBlock() + bbtest = self.newBlock() + te = self.newBlock() + self.emit(ir.Jump(bbtest)) + self.setBlock(bbtest) + self.genCondCode(code.condition, bbdo, te) + self.setBlock(bbdo) + self.genCode(code.statement) + self.emit(ir.Jump(bbtest)) + self.setBlock(te) + else: + raise NotImplementedError('Unknown stmt {}'.format(code)) + + def genCondCode(self, expr, bbtrue, bbfalse): + # Implement sequential logical operators + assert expr.typ == boolType + if type(expr) is astnodes.Binop: + if expr.op == 'or': + l2 = self.newBlock() + self.genCondCode(expr.a, bbtrue, l2) + self.setBlock(l2) + self.genCondCode(expr.b, bbtrue, bbfalse) + elif expr.op == 'and': + l2 = self.newBlock() + self.genCondCode(expr.a, l2, bbfalse) + self.setBlock(l2) + self.genCondCode(expr.b, bbtrue, bbfalse) + elif expr.op in ['==', '>', '<']: + ta = self.genExprCode(expr.a) + tb = self.genExprCode(expr.b) + self.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse)) + else: + raise NotImplementedError('Unknown condition {}'.format(expr)) + elif type(expr) is astnodes.Literal: + if expr.val: + self.emit(ir.Jump(bbtrue)) + else: + self.emit(ir.Jump(bbfalse)) + else: + raise NotImplementedError('Unknown cond {}'.format(expr)) + + def genExprCode(self, expr): + assert isinstance(expr, astnodes.Expression) + if type(expr) is astnodes.Binop and expr.op in ir.Binop.ops: + ra = self.genExprCode(expr.a) + rb = self.genExprCode(expr.b) + return ir.Binop(ra, expr.op, rb) + elif type(expr) is astnodes.Unop and expr.op == '&': + ra = self.genExprCode(expr.a) + assert type(ra) is ir.Mem + return ra.e + elif type(expr) is astnodes.VariableUse: + # This returns the dereferenced variable. + if expr.target.isParameter: + # TODO: now parameters are handled different. Not nice? + return self.varMap[expr.target] + else: + return ir.Mem(self.varMap[expr.target]) + elif type(expr) is astnodes.Deref: + # dereference pointer type: + addr = self.genExprCode(expr.ptr) + return ir.Mem(addr) + elif type(expr) is astnodes.FieldRef: + base = self.genExprCode(expr.base) + assert type(base) is ir.Mem, type(base) + base = base.e + bt = theType(expr.base.typ) + offset = ir.Const(bt.fieldOffset(expr.field)) + return ir.Mem(ir.Add(base, offset)) + elif type(expr) is astnodes.Literal: + return ir.Const(expr.val) + elif type(expr) is astnodes.TypeCast: + # TODO: improve this mess: + ar = self.genExprCode(expr.a) + tt = theType(expr.to_type) + if isinstance(tt, astnodes.PointerType): + if expr.a.typ is intType: + return ar + elif isinstance(expr.a.typ, astnodes.PointerType): + return ar + else: + raise Exception() + else: + raise NotImplementedError("not implemented") + elif type(expr) is astnodes.FunctionCall: + args = [self.genExprCode(e) for e in expr.args] + fn = self.funcMap[expr.proc] + return ir.Call(fn, args) + else: + raise NotImplementedError('Unknown expr {}'.format(expr))