diff python/ppci/c3/codegenerator.py @ 394:988f3fb861e4

c3 code generator rewrite
author Windel Bouwman
date Thu, 22 May 2014 08:14:12 +0200
parents 6ae782a085e0
children
line wrap: on
line diff
--- 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('<I', len(txt))