changeset 394:988f3fb861e4

c3 code generator rewrite
author Windel Bouwman
date Thu, 22 May 2014 08:14:12 +0200
parents 6ae782a085e0
children 3b0c495e3008
files python/ppci/buildfunctions.py python/ppci/c3/astnodes.py python/ppci/c3/codegenerator.py python/ppci/c3/parser.py python/ppci/c3/scope.py python/ppci/codegen/canon.py python/ppci/ir.py python/ppci/ir2tree.py python/ppci/irutils.py python/ppci/target/token.py python/ppci/transform.py test/testir.py
diffstat 12 files changed, 289 insertions(+), 196 deletions(-) [+]
line wrap: on
line diff
--- 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:
--- 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)
 
--- 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))
--- a/python/ppci/c3/parser.py	Sat May 17 21:17:40 2014 +0200
+++ b/python/ppci/c3/parser.py	Thu May 22 08:14:12 2014 +0200
@@ -23,7 +23,7 @@
         self.tokens = tokens
         self.token = self.tokens.__next__()
         try:
-            self.parsePackage()
+            self.parse_package()
             self.mod.ok = True  # Valid until proven wrong :)
             return self.mod
         except CompilerError as e:
@@ -68,26 +68,28 @@
         self.mod.imports.append(name)
         self.Consume(';')
 
-    def parsePackage(self):
+    def parse_package(self):
+        """ Parse a package definition """
         self.Consume('module')
         name = self.Consume('ID')
         self.Consume(';')
         self.mod = Package(name.val, name.loc)
         self.currentPart = self.mod
         while self.Peak != 'END':
-            self.parseTopLevel()
+            self.parse_top_level()
         self.Consume('END')
 
-    def parseTopLevel(self):
+    def parse_top_level(self):
+        """ Parse toplevel declaration """
         if self.Peak == 'function':
             self.parse_function_def()
         elif self.Peak == 'var':
-            self.parseVarDef()
+            self.parse_variable_def()
             # TODO handle variable initialization
         elif self.Peak == 'const':
             self.parseConstDef()
         elif self.Peak == 'type':
-            self.parseTypeDef()
+            self.parse_type_def()
         elif self.Peak == 'import':
             self.parseImport()
         else:
@@ -155,7 +157,7 @@
                 raise Exception()
         return theT
 
-    def parseTypeDef(self):
+    def parse_type_def(self):
         self.Consume('type')
         newtype = self.parse_type_spec()
         typename = self.Consume('ID')
@@ -164,7 +166,8 @@
         self.addDeclaration(df)
 
     # Variable declarations:
-    def parseVarDef(self):
+    def parse_variable_def(self):
+        """ Parse variable declaration """
         self.Consume('var')
         t = self.parse_type_spec()
         for name in self.parseIdSequence():
@@ -172,7 +175,6 @@
             v.loc = name.loc
             self.addDeclaration(v)
         self.Consume(';')
-        return Empty()
 
     def parseConstDef(self):
         self.Consume('const')
@@ -234,7 +236,7 @@
         self.Consume(')')
         return Switch(condition, loc)
 
-    def parseWhile(self):
+    def parse_while(self):
         loc = self.Consume('while').loc
         self.Consume('(')
         condition = self.Expression()
@@ -275,7 +277,7 @@
         if self.Peak == 'if':
             return self.parse_if()
         elif self.Peak == 'while':
-            return self.parseWhile()
+            return self.parse_while()
         elif self.Peak == 'for':
             return self.parse_for()
         elif self.Peak == 'switch':
@@ -285,7 +287,8 @@
         elif self.hasConsumed(';'):
             return Empty()
         elif self.Peak == 'var':
-            return self.parseVarDef()
+            self.parse_variable_def()
+            return Empty()
         elif self.Peak == 'return':
             return self.parseReturn()
         else:
@@ -391,6 +394,7 @@
             return self.UnaryExpression()
 
     def sizeof_expression(self):
+        """ Compiler internal function to determine size of a type """
         loc = self.Consume('sizeof').loc
         self.Consume('(')
         typ = self.parse_type_spec()
--- a/python/ppci/c3/scope.py	Sat May 17 21:17:40 2014 +0200
+++ b/python/ppci/c3/scope.py	Thu May 22 08:14:12 2014 +0200
@@ -16,6 +16,7 @@
 
     @property
     def Syms(self):
+        """ Get all the symbols defined in this scope """
         syms = self.symbols.values()
         return sorted(syms, key=lambda v: v.name)
 
--- a/python/ppci/codegen/canon.py	Sat May 17 21:17:40 2014 +0200
+++ b/python/ppci/codegen/canon.py	Thu May 22 08:14:12 2014 +0200
@@ -60,7 +60,7 @@
         return frame.parMap[exp]
     elif isinstance(exp, ir.LocalVariable):
         offset = frame.allocVar(exp)
-        return ir.Add(frame.fp, ir.Const(offset))
+        return ir.Add(frame.fp, ir.Const(offset), "Offset", ir.i32)
     elif isinstance(exp, ir.GlobalVariable):
         #frame.load_global_address(ir.label_name(exp))
         return exp
--- a/python/ppci/ir.py	Sat May 17 21:17:40 2014 +0200
+++ b/python/ppci/ir.py	Thu May 22 08:14:12 2014 +0200
@@ -4,7 +4,7 @@
 
 
 def label_name(dut):
-    """ Function that returns the assembly code label name """
+    """ Returns the assembly code label name """
     if isinstance(dut, Block):
         f = dut.function
         return label_name(f) + '_' + dut.name
@@ -16,6 +16,14 @@
         raise NotImplementedError(str(dut))
 
 
+class Typ:
+    def __init__(self):
+        pass
+
+
+i32 = Typ()
+i8 = Typ()
+
 class Module:
     """ Container unit for variables and functions. """
     def __init__(self, name):
@@ -46,14 +54,12 @@
 
     Functions = property(get_functions)
 
-    def findFunction(self, name):
+    def find_function(self, name):
         for f in self.funcs:
             if f.name == name:
                 return f
         raise KeyError(name)
 
-    getFunction = findFunction
-
 
 class Function:
     """ Represents a function. """
@@ -195,9 +201,27 @@
 # Instructions:
 
 class Value:
-    pass
+    """ A value has a type and a name """
+    def __init__(self, name, ty):
+        assert isinstance(ty, Typ)
+        self.name = name
+        self.ty = ty
+
 
-class Expression:
+class User(Value):
+    """ Value that uses other values """
+    def __init__(self, name, ty):
+        super().__init__(name, ty)
+        # Create a collection to store the values this value uses.
+        # TODO: think of better naming..
+        self.uses = set()
+
+    def add_use(self, v):
+        assert isinstance(v, Value)
+        self.uses.add(v)
+
+
+class Expression(User):
     """ Base class for an expression """
     pass
 
@@ -228,11 +252,14 @@
     """ Generic binary operation """
     ops = ['+', '-', '*', '/', '|', '&', '<<', '>>']
 
-    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):
--- 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'}
--- 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)
--- 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<<i) & v))
-    #b.reverse()
     return b
 
 
@@ -48,6 +47,7 @@
         elif type(key) is slice:
             assert key.step is None
             bits = key.stop - key.start
+            assert value < (2**bits)
             value_bits = val2bit(value, bits)
             for i in range(key.start, key.stop):
                 self.set_bit(i, value_bits[i - key.start])
--- a/python/ppci/transform.py	Sat May 17 21:17:40 2014 +0200
+++ b/python/ppci/transform.py	Thu May 22 08:14:12 2014 +0200
@@ -125,6 +125,7 @@
 
 child_nodes = {}
 child_nodes[ir.Binop] = ['a', 'b']
+child_nodes[ir.Add] = ['a', 'b']
 child_nodes[ir.Const] = []
 child_nodes[ir.Temp] = []
 child_nodes[ir.Exp] = ['e']
--- a/test/testir.py	Sat May 17 21:17:40 2014 +0200
+++ b/test/testir.py	Thu May 22 08:14:12 2014 +0200
@@ -1,5 +1,4 @@
 import unittest
-import os
 import sys
 import io
 import ppci
@@ -10,7 +9,7 @@
 
 class IrCodeTestCase(unittest.TestCase):
     def testAdd(self):
-        v = ir.Add(ir.Const(1), ir.Const(2))
+        v = ir.Add(ir.Const(1), ir.Const(2), "add", ir.i32)
 
 
 class IrBuilderTestCase(unittest.TestCase):
@@ -20,7 +19,7 @@
         self.b.setModule(self.m)
 
     def testBuilder(self):
-        f = self.b.newFunction('add')
+        f = self.b.new_function('add')
         self.b.setFunction(f)
         bb = self.b.newBlock()
         self.b.emit(ir.Jump(bb))
@@ -65,23 +64,23 @@
         self.b.setModule(self.m)
 
     def testBuilder(self):
-        f = self.b.newFunction('test')
+        f = self.b.new_function('test')
         self.b.setFunction(f)
         bb = self.b.newBlock()
         self.b.emit(ir.Jump(bb))
         self.b.setBlock(bb)
         v1 = ir.Const(5)
         v2 = ir.Const(7)
-        v3 = ir.Add(v1, v2)
+        v3 = ir.Add(v1, v2, "add", ir.i32)
         self.b.emit(ir.Jump(f.epiloog))
         self.cf.run(self.m)
 
     def testAdd0(self):
-        f = self.b.newFunction('test')
+        f = self.b.new_function('test')
         self.b.setFunction(f)
         self.b.setBlock(self.b.newBlock())
-        v1 = ir.Const(0)
-        v3 = ir.Add(v1, ir.Const(0))
+        v1 = ir.Const(12)
+        v3 = ir.Add(v1, ir.Const(0), "add", ir.i32)
 
 
 class TestWriter(unittest.TestCase):