# HG changeset patch # User Windel Bouwman # Date 1400739252 -7200 # Node ID 988f3fb861e4921873cfd44b53d1bb77f2c1ceb3 # Parent 6ae782a085e0a3fa21a3f36affc6fe92cd7c0b75 c3 code generator rewrite diff -r 6ae782a085e0 -r 988f3fb861e4 python/ppci/buildfunctions.py --- a/python/ppci/buildfunctions.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/buildfunctions.py Thu May 22 08:14:12 2014 +0200 @@ -14,7 +14,7 @@ from .linker import Linker from .layout import Layout, load_layout from .target.target_list import targets -from .outstream import BinaryAndLoggingStream +from .outstream import BinaryOutputStream from .objectfile import ObjectFile, load_object from . import DiagnosticsManager from .tasks import TaskError, TaskRunner @@ -91,7 +91,7 @@ output = ObjectFile() assembler = target.assembler logger.debug('Assembling into code section') - ostream = BinaryAndLoggingStream(output) + ostream = BinaryOutputStream(output) ostream.select_section('code') assembler.prepare() assembler.assemble(source, ostream) @@ -111,7 +111,7 @@ c3b = Builder(diag, target) cg = CodeGenerator(target) - output_stream = BinaryAndLoggingStream(output) + output_stream = BinaryOutputStream(output) for ircode in c3b.build(sources, includes): if not ircode: diff -r 6ae782a085e0 -r 988f3fb861e4 python/ppci/c3/astnodes.py --- a/python/ppci/c3/astnodes.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/c3/astnodes.py Thu May 22 08:14:12 2014 +0200 @@ -44,6 +44,10 @@ def Types(self): return self.innerScope.Types + @property + def Functions(self): + return self.innerScope.Functions + def __repr__(self): return 'MODULE {}'.format(self.name) diff -r 6ae782a085e0 -r 988f3fb861e4 python/ppci/c3/codegenerator.py --- a/python/ppci/c3/codegenerator.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/c3/codegenerator.py Thu May 22 08:14:12 2014 +0200 @@ -13,7 +13,7 @@ self.loc = loc -class CodeGenerator(irutils.Builder): +class CodeGenerator: """ Generates intermediate (IR) code from a package. The entry function is 'genModule'. The main task of this part is to rewrite complex control @@ -26,11 +26,12 @@ """ def __init__(self, diag): self.logger = logging.getLogger('c3cgen') + self.builder = irutils.Builder() self.diag = diag def gencode(self, pkg): """ Generate code for a single module """ - self.prepare() + self.builder.prepare() assert type(pkg) is ast.Package self.pkg = pkg self.intType = pkg.scope['int'] @@ -39,24 +40,24 @@ self.logger.debug('Generating ir-code for {}'.format(pkg.name), extra={'c3_ast': pkg}) self.varMap = {} # Maps variables to storage locations. - self.m = ir.Module(pkg.name) + self.builder.m = ir.Module(pkg.name) try: for typ in pkg.Types: self.check_type(typ) # Only generate function if function contains a body: real_functions = list(filter( - lambda f: f.body, pkg.innerScope.Functions)) + lambda f: f.body, pkg.Functions)) for v in pkg.innerScope.Variables: - v2 = ir.GlobalVariable(v.name) + v2 = ir.GlobalVariable(v.name, ir.i32) self.varMap[v] = v2 if not v.isLocal: - self.m.add_variable(v2) + self.builder.m.add_variable(v2) for s in real_functions: self.gen_function(s) except SemanticError as e: self.error(e.msg, e.loc) if self.pkg.ok: - return self.m + return self.builder.m def error(self, msg, loc=None): self.pkg.ok = False @@ -64,133 +65,145 @@ def gen_function(self, fn): # TODO: handle arguments - f = self.newFunction(fn.name) - f.return_value = self.newTemp() - self.setFunction(f) - l2 = self.newBlock() - self.emit(ir.Jump(l2)) - self.setBlock(l2) + f = self.builder.new_function(fn.name) + f.return_value = self.builder.newTemp() + self.builder.setFunction(f) + l2 = self.builder.newBlock() + self.builder.emit(ir.Jump(l2)) + self.builder.setBlock(l2) # generate room for locals: for sym in fn.innerScope: self.check_type(sym.typ) if sym.isParameter: - p = ir.Parameter(sym.name) - variable = ir.LocalVariable(sym.name + '_copy') + p = ir.Parameter(sym.name, ir.i32) + variable = ir.LocalVariable(sym.name + '_copy', ir.i32) f.addParameter(p) f.addLocal(variable) # Move parameter into local copy: - self.emit(ir.Move(ir.Mem(variable), p)) + self.builder.emit(ir.Move(ir.Mem(variable), p)) elif sym.isLocal: - variable = ir.LocalVariable(sym.name) + variable = ir.LocalVariable(sym.name, ir.i32) f.addLocal(variable) elif isinstance(sym, ast.Variable): - variable = ir.LocalVariable(sym.name) + variable = ir.LocalVariable(sym.name, ir.i32) f.addLocal(variable) else: raise NotImplementedError('{}'.format(sym)) self.varMap[sym] = variable - self.genCode(fn.body) - self.emit(ir.Move(f.return_value, ir.Const(0))) - self.emit(ir.Jump(f.epiloog)) - self.setFunction(None) - - def genCode(self, code): - """ Wrapper around gen_stmt to catch errors """ - try: - self.gen_stmt(code) - except SemanticError as e: - self.error(e.msg, e.loc) + self.gen_stmt(fn.body) + self.builder.emit(ir.Move(f.return_value, ir.Const(0))) + self.builder.emit(ir.Jump(f.epiloog)) + self.builder.setFunction(None) def gen_stmt(self, code): """ Generate code for a statement """ - assert isinstance(code, ast.Statement) - self.setLoc(code.loc) - if type(code) is ast.Compound: - for s in code.statements: - self.genCode(s) - elif type(code) is ast.Empty: - pass - elif type(code) is ast.Assignment: - lval = self.gen_expr_code(code.lval) - rval = self.gen_expr_code(code.rval) - if not self.equal_types(code.lval.typ, code.rval.typ): - raise SemanticError('Cannot assign {} to {}' - .format(code.rval.typ, code.lval.typ), - code.loc) - if not code.lval.lvalue: - raise SemanticError('No valid lvalue {}'.format(code.lval), - code.lval.loc) - self.emit(ir.Move(lval, rval)) - elif type(code) is ast.ExpressionStatement: - self.emit(ir.Exp(self.gen_expr_code(code.ex))) - elif type(code) is ast.If: - bbtrue = self.newBlock() - bbfalse = self.newBlock() - te = self.newBlock() - self.gen_cond_code(code.condition, bbtrue, bbfalse) - self.setBlock(bbtrue) - self.genCode(code.truestatement) - self.emit(ir.Jump(te)) - self.setBlock(bbfalse) - self.genCode(code.falsestatement) - self.emit(ir.Jump(te)) - self.setBlock(te) - elif type(code) is ast.Return: - re = self.gen_expr_code(code.expr) - self.emit(ir.Move(self.fn.return_value, re)) - self.emit(ir.Jump(self.fn.epiloog)) - b = self.newBlock() - self.setBlock(b) - elif type(code) is ast.While: - bbdo = self.newBlock() - bbtest = self.newBlock() - te = self.newBlock() - self.emit(ir.Jump(bbtest)) - self.setBlock(bbtest) - self.gen_cond_code(code.condition, bbdo, te) - self.setBlock(bbdo) - self.genCode(code.statement) - self.emit(ir.Jump(bbtest)) - self.setBlock(te) - elif type(code) is ast.For: - bbdo = self.newBlock() - bbtest = self.newBlock() - te = self.newBlock() - self.genCode(code.init) - self.emit(ir.Jump(bbtest)) - self.setBlock(bbtest) - self.gen_cond_code(code.condition, bbdo, te) - self.setBlock(bbdo) - self.genCode(code.statement) - self.genCode(code.final) - self.emit(ir.Jump(bbtest)) - self.setBlock(te) - elif type(code) is ast.Switch: - raise NotImplementedError('Unknown stmt {}'.format(code)) - else: - raise NotImplementedError('Unknown stmt {}'.format(code)) + try: + assert isinstance(code, ast.Statement) + self.builder.setLoc(code.loc) + if type(code) is ast.Compound: + for s in code.statements: + self.gen_stmt(s) + elif type(code) is ast.Empty: + pass + elif type(code) is ast.Assignment: + self.gen_assignment_stmt(code) + elif type(code) is ast.ExpressionStatement: + self.builder.emit(ir.Exp(self.gen_expr_code(code.ex))) + elif type(code) is ast.If: + self.gen_if_stmt(code) + elif type(code) is ast.Return: + re = self.gen_expr_code(code.expr) + self.builder.emit(ir.Move(self.builder.fn.return_value, re)) + self.builder.emit(ir.Jump(self.builder.fn.epiloog)) + b = self.builder.newBlock() + self.builder.setBlock(b) + elif type(code) is ast.While: + self.gen_while(code) + elif type(code) is ast.For: + self.gen_for_stmt(code) + elif type(code) is ast.Switch: + raise NotImplementedError('Unknown stmt {}'.format(code)) + else: + raise NotImplementedError('Unknown stmt {}'.format(code)) + except SemanticError as e: + self.error(e.msg, e.loc) + + def gen_assignment_stmt(self, code): + """ Generate code for assignment statement """ + lval = self.gen_expr_code(code.lval) + rval = self.gen_expr_code(code.rval) + if not self.equal_types(code.lval.typ, code.rval.typ): + raise SemanticError('Cannot assign {} to {}' + .format(code.rval.typ, code.lval.typ), + code.loc) + if not code.lval.lvalue: + raise SemanticError('No valid lvalue {}'.format(code.lval), + code.lval.loc) + self.builder.emit(ir.Move(lval, rval)) + + def gen_if_stmt(self, code): + """ Generate code for if statement """ + true_block = self.builder.newBlock() + bbfalse = self.builder.newBlock() + te = self.builder.newBlock() + self.gen_cond_code(code.condition, true_block, bbfalse) + self.builder.setBlock(true_block) + self.gen_stmt(code.truestatement) + self.builder.emit(ir.Jump(te)) + self.builder.setBlock(bbfalse) + self.gen_stmt(code.falsestatement) + self.builder.emit(ir.Jump(te)) + self.builder.setBlock(te) + + def gen_while(self, code): + """ Generate code for while statement """ + bbdo = self.builder.newBlock() + test_block = self.builder.newBlock() + final_block = self.builder.newBlock() + self.builder.emit(ir.Jump(test_block)) + self.builder.setBlock(test_block) + self.gen_cond_code(code.condition, bbdo, final_block) + self.builder.setBlock(bbdo) + self.gen_stmt(code.statement) + self.builder.emit(ir.Jump(test_block)) + self.builder.setBlock(final_block) + + def gen_for_stmt(self, code): + """ Generate for statement code """ + bbdo = self.builder.newBlock() + test_block = self.builder.newBlock() + final_block = self.builder.newBlock() + self.gen_stmt(code.init) + self.builder.emit(ir.Jump(test_block)) + self.builder.setBlock(test_block) + self.gen_cond_code(code.condition, bbdo, final_block) + self.builder.setBlock(bbdo) + self.gen_stmt(code.statement) + self.gen_stmt(code.final) + self.builder.emit(ir.Jump(test_block)) + self.builder.setBlock(final_block) def gen_cond_code(self, expr, bbtrue, bbfalse): """ Generate conditional logic. Implement sequential logical operators. """ if type(expr) is ast.Binop: if expr.op == 'or': - l2 = self.newBlock() + l2 = self.builder.newBlock() self.gen_cond_code(expr.a, bbtrue, l2) if not self.equal_types(expr.a.typ, self.boolType): raise SemanticError('Must be boolean', expr.a.loc) - self.setBlock(l2) + self.builder.setBlock(l2) self.gen_cond_code(expr.b, bbtrue, bbfalse) if not self.equal_types(expr.b.typ, self.boolType): raise SemanticError('Must be boolean', expr.b.loc) elif expr.op == 'and': - l2 = self.newBlock() + l2 = self.builder.newBlock() self.gen_cond_code(expr.a, l2, bbfalse) if not self.equal_types(expr.a.typ, self.boolType): self.error('Must be boolean', expr.a.loc) - self.setBlock(l2) + self.builder.setBlock(l2) self.gen_cond_code(expr.b, bbtrue, bbfalse) if not self.equal_types(expr.b.typ, self.boolType): raise SemanticError('Must be boolean', expr.b.loc) @@ -201,16 +214,16 @@ raise SemanticError('Types unequal {} != {}' .format(expr.a.typ, expr.b.typ), expr.loc) - self.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse)) + self.builder.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse)) else: raise SemanticError('non-bool: {}'.format(expr.op), expr.loc) expr.typ = self.boolType elif type(expr) is ast.Literal: self.gen_expr_code(expr) if expr.val: - self.emit(ir.Jump(bbtrue)) + self.builder.emit(ir.Jump(bbtrue)) else: - self.emit(ir.Jump(bbfalse)) + self.builder.emit(ir.Jump(bbfalse)) else: raise NotImplementedError('Unknown cond {}'.format(expr)) @@ -237,7 +250,7 @@ raise SemanticError('Can only add integers', expr.loc) else: raise NotImplementedError("Cannot use equality as expressions") - return ir.Binop(ra, expr.op, rb) + return ir.Binop(ra, expr.op, rb, "op", ir.i32) elif type(expr) is ast.Unop: if expr.op == '&': ra = self.gen_expr_code(expr.a) @@ -274,61 +287,11 @@ else: raise SemanticError('Cannot deref non-pointer', expr.loc) elif type(expr) is ast.Member: - base = self.gen_expr_code(expr.base) - expr.lvalue = expr.base.lvalue - basetype = self.the_type(expr.base.typ) - if type(basetype) is ast.StructureType: - if basetype.hasField(expr.field): - expr.typ = basetype.fieldType(expr.field) - else: - raise SemanticError('{} does not contain field {}' - .format(basetype, expr.field), - expr.loc) - else: - raise SemanticError('Cannot select {} of non-structure type {}' - .format(expr.field, basetype), expr.loc) - - assert type(base) is ir.Mem, type(base) - bt = self.the_type(expr.base.typ) - offset = ir.Const(bt.fieldOffset(expr.field)) - return ir.Mem(ir.Add(base.e, offset)) + return self.gen_member_expr(expr) elif type(expr) is ast.Index: - """ Array indexing """ - base = self.gen_expr_code(expr.base) - idx = self.gen_expr_code(expr.i) - base_typ = self.the_type(expr.base.typ) - if not isinstance(base_typ, ast.ArrayType): - raise SemanticError('Cannot index non-array type {}' - .format(base_typ), - expr.base.loc) - idx_type = self.the_type(expr.i.typ) - if not self.equal_types(idx_type, self.intType): - raise SemanticError('Index must be int not {}' - .format(idx_type), expr.i.loc) - assert type(base) is ir.Mem - element_type = self.the_type(base_typ.element_type) - element_size = self.size_of(element_type) - expr.typ = base_typ.element_type - expr.lvalue = True - - return ir.Mem(ir.Add(base.e, ir.Mul(idx, ir.Const(element_size)))) + return self.gen_index_expr(expr) elif type(expr) is ast.Literal: - expr.lvalue = False - typemap = {int: 'int', - float: 'double', - bool: 'bool', - str: 'string'} - if type(expr.val) in typemap: - expr.typ = self.pkg.scope[typemap[type(expr.val)]] - else: - raise SemanticError('Unknown literal type {}' - .format(expr.val), expr.loc) - # Construct correct const value: - if type(expr.val) is str: - cval = self.pack_string(expr.val) - return ir.Addr(ir.Const(cval)) - else: - return ir.Const(expr.val) + return self.gen_literal_expr(expr) elif type(expr) is ast.TypeCast: return self.gen_type_cast(expr) elif type(expr) is ast.Sizeof: @@ -342,6 +305,69 @@ else: raise NotImplementedError('Unknown expr {}'.format(expr)) + def gen_member_expr(self, expr): + base = self.gen_expr_code(expr.base) + expr.lvalue = expr.base.lvalue + basetype = self.the_type(expr.base.typ) + if type(basetype) is ast.StructureType: + if basetype.hasField(expr.field): + expr.typ = basetype.fieldType(expr.field) + else: + raise SemanticError('{} does not contain field {}' + .format(basetype, expr.field), + expr.loc) + else: + raise SemanticError('Cannot select {} of non-structure type {}' + .format(expr.field, basetype), expr.loc) + + assert type(base) is ir.Mem, type(base) + bt = self.the_type(expr.base.typ) + offset = ir.Const(bt.fieldOffset(expr.field)) + addr = ir.Add(base.e, offset, "mem_addr", ir.i32) + return ir.Mem(addr) + + def gen_index_expr(self, expr): + """ Array indexing """ + base = self.gen_expr_code(expr.base) + idx = self.gen_expr_code(expr.i) + base_typ = self.the_type(expr.base.typ) + if not isinstance(base_typ, ast.ArrayType): + raise SemanticError('Cannot index non-array type {}' + .format(base_typ), + expr.base.loc) + idx_type = self.the_type(expr.i.typ) + if not self.equal_types(idx_type, self.intType): + raise SemanticError('Index must be int not {}' + .format(idx_type), expr.i.loc) + assert type(base) is ir.Mem + element_type = self.the_type(base_typ.element_type) + element_size = self.size_of(element_type) + expr.typ = base_typ.element_type + expr.lvalue = True + + offset = ir.Mul(idx, ir.Const(element_size), "element_offset", ir.i32) + addr = ir.Add(base.e, offset, "element_address", ir.i32) + return ir.Mem(addr) + + def gen_literal_expr(self, expr): + """ Generate code for literal """ + expr.lvalue = False + typemap = {int: 'int', + float: 'double', + bool: 'bool', + str: 'string'} + if type(expr.val) in typemap: + expr.typ = self.pkg.scope[typemap[type(expr.val)]] + else: + raise SemanticError('Unknown literal type {}' + .format(expr.val), expr.loc) + # Construct correct const value: + if type(expr.val) is str: + cval = self.pack_string(expr.val) + return ir.Addr(ir.Const(cval)) + else: + return ir.Const(expr.val) + def pack_string(self, txt): """ Pack a string using 4 bytes length followed by text data """ length = struct.pack('>'] - def __init__(self, value1, operation, value2): + def __init__(self, a, operation, b, name, ty): + super().__init__(name, ty) assert operation in Binop.ops #assert type(value1) is type(value2) - self.a = value1 - self.b = value2 + assert isinstance(a, Value), str(a) + assert isinstance(b, Value), str(b) + self.a = a + self.b = b self.operation = operation def __repr__(self): @@ -240,9 +267,10 @@ return '({} {} {})'.format(a, self.operation, b) -def Add(a, b): +class Add(Binop): """ Add a and b """ - return Binop(a, '+', b) + def __init__(self, a, b, name, ty): + super().__init__(a, '+', b, name, ty) def Sub(a, b): @@ -250,9 +278,9 @@ return Binop(a, '-', b) -def Mul(a, b): +def Mul(a, b, name, ty): """ Multiply a by b """ - return Binop(a, '*', b) + return Binop(a, '*', b, name, ty) def Div(a, b): @@ -260,6 +288,16 @@ return Binop(a, '/', b) +def Phi(User): + """ Imaginary phi instruction to make SSA possible. """ + def __init__(self, name, ty): + super().__init__(name, ty) + self.inputs = [] + + def add_input(self, value, block): + self.inputs.append((value, block)) + + class Eseq(Expression): """ Sequence of instructions where the last is an expression """ def __init__(self, stmt, e): @@ -280,7 +318,8 @@ class Variable(Expression): - def __init__(self, name): + def __init__(self, name, ty): + super().__init__(name, ty) self.name = name def __repr__(self): @@ -320,6 +359,23 @@ return '[{}]'.format(self.e) +class Load(Value): + """ Load a value from memory """ + def __init__(self, address, name, ty): + super().__init__(name, ty) + assert isinstance(address, Value) + self.address = address + + def __repr__(self): + return 'load {}'.format(self.address) + + +class Store: + """ Store a value into memory """ + def __init__(self, address, value): + self.address = address + + class Addr(Expression): """ Address of label """ def __init__(self, e): diff -r 6ae782a085e0 -r 988f3fb861e4 python/ppci/ir2tree.py --- a/python/ppci/ir2tree.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/ir2tree.py Thu May 22 08:14:12 2014 +0200 @@ -13,6 +13,7 @@ return reg_f @register(ir.Binop) +@register(ir.Add) def binop_to_tree(e): names = {'+':'ADDI32', '-':'SUBI32', '|':'ORI32', '<<':'SHLI32', '*':'MULI32', '&':'ANDI32', '>>':'SHRI32'} diff -r 6ae782a085e0 -r 988f3fb861e4 python/ppci/irutils.py --- a/python/ppci/irutils.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/irutils.py Thu May 22 08:14:12 2014 +0200 @@ -210,7 +210,7 @@ def setModule(self, m): self.m = m - def newFunction(self, name): + def new_function(self, name): f = ir.Function(name) self.m.add_function(f) return f @@ -240,6 +240,7 @@ class Verifier: + """ Checks an ir module for correctness """ def verify(self, module): """ Verifies a module for some sanity """ assert isinstance(module, ir.Module) diff -r 6ae782a085e0 -r 988f3fb861e4 python/ppci/target/token.py --- a/python/ppci/target/token.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/target/token.py Thu May 22 08:14:12 2014 +0200 @@ -13,7 +13,6 @@ b = [] for i in range(bits): b.append(bool((1<