changeset 268:5ec7580976d9

Op naar tree-IR
author Windel Bouwman
date Wed, 14 Aug 2013 20:12:40 +0200
parents e7c8f7eb3f59
children 5f8c04a8d26b
files python/c3/codegenerator.py python/codegenarm.py python/cortexm3.py python/ir/__init__.py python/ir/basicblock.py python/ir/builder.py python/ir/function.py python/ir/instruction.py python/ir/module.py python/irmach.py python/optimize.py python/stm32f4/burn2.c3 python/testc3.py python/testcg.py python/testir.py
diffstat 15 files changed, 351 insertions(+), 601 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/codegenerator.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/c3/codegenerator.py	Wed Aug 14 20:12:40 2013 +0200
@@ -5,203 +5,154 @@
 from ppci import CompilerError
 from .typecheck import theType
 
-tmpnames = {'+':'add', '-':'sub', '*': 'mul', '/':'div', '|':'or', \
-    '&':'and', '>>':'shl', '<<':'shr'}
 
-class CodeGenerator:
+class CodeGenerator(ir.Builder):
     """ Generates intermediate code from a package """
     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.builder = ir.Builder()
-        m = ir.Module(pkg.name)
-        self.builder.setModule(m)
+        self.m = ir.Module(pkg.name)
         self.genModule(pkg)
-        return m
+        return self.m
 
     # inner helpers:
     def genModule(self, pkg):
-       # Take care of forward declarations:
-       for s in pkg.innerScope.Functions:
-            f = self.builder.newFunction(s.name)
+        # Take care of forward declarations:
+        for s in pkg.innerScope.Functions:
+            f = self.newFunction(s.name)
             self.funcMap[s] = f
-       for s in pkg.innerScope:
-         if type(s) is astnodes.Variable:
-              v = self.builder.newTmp(s.name)
-              #self.builder.addIns(ir.Alloc(v))
-              self.varMap[s] = v
-         elif type(s) is astnodes.Function:
-            # TODO: handle arguments
-            f = self.funcMap[s]
-            self.builder.setFunction(f)
-            bb = self.builder.newBB()
-            f.entry = bb
-            self.builder.setBB(bb)
-            # generate room for locals:
+        for s in pkg.innerScope:
+            if type(s) is astnodes.Variable:
+                #v = self.builder.newTmp(s.name)
+                self.varMap[s] = self.newTemp()
+                pass
+            elif type(s) is astnodes.Function:
+                self.genFunction(s)
+            else:
+                raise NotImplementedError(str(s))
 
-            for sym in s.innerScope:
-               #print(sym, sym.isParameter)
-               # TODO: handle parameters different
-               v = self.builder.newTmp(sym.name)
-               self.builder.addIns(ir.Alloc(v))
-               self.varMap[sym] = v
+    def genFunction(self, fn):
+        # TODO: handle arguments
+        f = self.funcMap[fn]
+        self.setFunction(f)
+        # generate room for locals:
 
-            self.genCode(s.body)
-            # TODO handle return?
-            self.builder.addIns(ir.Return())
-            self.builder.setFunction(None)
-         else:
-            print(s)
+        for sym in fn.innerScope:
+            # TODO: handle parameters different
+            v = self.newTemp()
+            # TODO: make this ssa here??
+            self.varMap[sym] = v
+
+        self.genCode(fn.body)
+        # TODO handle return?
+        self.emit(ir.Return(ir.Const(0)))
+        self.setFunction(None)
 
     def genCode(self, code):
         assert isinstance(code, astnodes.Statement)
-        self.builder.setLoc(code.loc)
+        self.setLoc(code.loc)
         if type(code) is astnodes.CompoundStatement:
             for s in code.statements:
                 self.genCode(s)
         elif type(code) is astnodes.Assignment:
-            re = self.genExprCode(code.rval)
-            loc = self.genExprCode(code.lval)
-            self.builder.addIns(ir.Store(loc, re))
+            rval = self.genExprCode(code.rval)
+            lval = self.genExprCode(code.lval)
+            self.emit(ir.Move(lval, rval))
         elif type(code) is astnodes.ExpressionStatement:
             self.genExprCode(code.ex)
         elif type(code) is astnodes.IfStatement:
-             bbtrue = self.builder.newBB()
-             bbfalse = self.builder.newBB()
-             te = self.builder.newBB()
-             self.genCondCode(code.condition, bbtrue, bbfalse)
-             self.builder.setBB(bbtrue)
-             self.genCode(code.truestatement)
-             self.builder.addIns(ir.Branch(te))
-             self.builder.setBB(bbfalse)
-             if code.falsestatement:
-                 self.genCode(code.falsestatement)
-             self.builder.addIns(ir.Branch(te))
-             self.builder.setBB(te)
+            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.builder.addIns(ir.Return(re))
+                self.emit(ir.Return(re))
             else:
                 self.builder.addIns(ir.Return())
         elif type(code) is astnodes.WhileStatement:
-            bbdo = self.builder.newBB()
-            bbtest = self.builder.newBB()
-            te = self.builder.newBB()
-            self.builder.addIns(ir.Branch(bbtest))
-            self.builder.setBB(bbtest)
+            bbdo = self.newBlock()
+            bbtest = self.newBlock()
+            te = self.newBlock()
+            self.emit(ir.Jump(bbtest))
+            self.setBlock(bbtest)
             self.genCondCode(code.condition, bbdo, te)
-            self.builder.setBB(bbdo)
+            self.setBlock(bbdo)
             self.genCode(code.statement)
-            self.builder.addIns(ir.Branch(bbtest))
-            self.builder.setBB(te)
+            self.emit(ir.Jump(bbtest))
+            self.setBlock(te)
         else:
-            print('Unknown stmt:', code)
-            raise NotImplementedError()
+            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.builder.newBB()
+            if expr.op == 'or':
+                l2 = self.newBlock()
                 self.genCondCode(expr.a, bbtrue, l2)
-                self.builder.setBB(l2)
+                self.setBlock(l2)
                 self.genCondCode(expr.b, bbtrue, bbfalse)
-             elif expr.op == 'and':
-                l2 = self.builder.newBB()
+            elif expr.op == 'and':
+                l2 = self.newBlock()
                 self.genCondCode(expr.a, l2, bbfalse)
-                self.builder.setBB(l2)
+                self.setBlock(l2)
                 self.genCondCode(expr.b, bbtrue, bbfalse)
-             elif expr.op in ['==', '>', '<']:
+            elif expr.op in ['==', '>', '<']:
                 ta = self.genExprCode(expr.a)
                 tb = self.genExprCode(expr.b)
-                i = ir.ConditionalBranch(ta, expr.op, tb, bbtrue, bbfalse)
-                self.builder.addIns(i)
-             else:
-                raise NotImlementedError('Unknown condition {0}'.format(expr))
+                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.builder.addIns(ir.Branch(bbtrue))
+                self.emit(ir.Jump(bbtrue))
              else:
-                self.builder.addIns(ir.Branch(bbfalse))
+                self.emit(ir.Jump(bbfalse))
         else:
-             print('Unknown cond', expr)
-             raise NotImplementedError()
-
-    def cast_to_rvalue(self, expr, loc):
-        """ Cast lvalue to rvalue if required """
-        if hasattr(expr, 'expect_rvalue'):
-            # Load value from memory location:
-            tmp = self.builder.newTmp()
-            i = ir.Load(loc, tmp)
-            self.builder.addIns(i)
-            return tmp
-        if expr.lvalue:
-            return loc
+             raise NotImplementedError('Unknown cond {}'.format(expr))
 
     def genExprCode(self, expr):
         assert isinstance(expr, astnodes.Expression)
-        if type(expr) is astnodes.Binop:
-             ra = self.genExprCode(expr.a)
-             rb = self.genExprCode(expr.b)
-             ops = ['+', '-', '*', '/', '|', '&', '<<', '>>']
-             if expr.op in ops:
-                tmp = self.builder.newTmp(tmpnames[expr.op])
-                op = expr.op
-                ins = ir.BinaryOperator(tmp, op, ra, rb)
-                self.builder.addIns(ins)
-                return tmp
-             else:
-                raise NotImplementedError('Unknown {0}'.format(expr))
-                tmp = self.builder.newTmp()
-                # TODO
-                return tmp
-        elif type(expr) is astnodes.Unop:
+        if type(expr) is astnodes.Binop and expr.op in ir.Binop.ops:
             ra = self.genExprCode(expr.a)
-            if expr.op == '&':
-                # Address of operator
-                tmp = self.builder.newTmp('addr')
-                return tmp
-                #self.builder.addIns(ins)
-            else:
-                raise NotImplementedError('Unknown {0}'.format(expr))
-        elif type(expr) is astnodes.Constant:
-            tmp = self.builder.newTmp()
-            # TODO
-            return tmp
+            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)
+            # TODO: Make this work?
+            return ra
         elif type(expr) is astnodes.VariableUse:
-            loc = self.varMap[expr.target]
-            return self.cast_to_rvalue(expr, loc)
+            return self.varMap[expr.target]
         elif type(expr) is astnodes.Deref:
             # dereference pointer type:
             addr = self.genExprCode(expr.ptr)
-            tmp = self.builder.newTmp('deref')
-            ins = ir.Load(addr, tmp)
-            self.builder.addIns(ins)
-            return tmp
+            return ir.Mem(addr)
         elif type(expr) is astnodes.FieldRef:
             b = self.genExprCode(expr.base)
-            offset = self.builder.newTmp('off_' + expr.field)
+            #b = b.e
             bt = theType(expr.base.typ)
-            ofs = bt.fieldOffset(expr.field)
-            ins = ir.ImmLoad(offset, ofs)
-            self.builder.addIns(ins)
-            tmp2 = self.builder.newTmp('adr_' + expr.field)
-            ins = ir.BinaryOperator(tmp2, '+', b, offset)
-            self.builder.addIns(ins)
-            return self.cast_to_rvalue(expr, tmp2)
+            offset = ir.Const(bt.fieldOffset(expr.field))
+            return ir.Mem(ir.Binop(b, '+', offset))
         elif type(expr) is astnodes.Literal:
-            tmp = self.builder.newTmp('const')
-            ins = ir.ImmLoad(tmp, expr.val)
-            self.builder.addIns(ins)
-            return tmp
+            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):
@@ -214,15 +165,9 @@
             else:
                 raise NotImplementedError("not implemented")
         elif type(expr) is astnodes.FunctionCall:
-            tmp = self.builder.newTmp("res")
-            args = []
-            for arg in expr.args:
-                ar = self.genExprCode(arg)
-                args.append(ar)
+            args = [self.genExprCode(e) for e in expr.args]
             fn = self.funcMap[expr.proc]
-            ins = ir.Call(fn, args, tmp)
-            self.builder.addIns(ins)
-            return tmp
+            return ir.Call(fn, args)
         else:
             raise NotImplementedError('Unknown expr {}'.format(expr))
 
--- a/python/codegenarm.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/codegenarm.py	Wed Aug 14 20:12:40 2013 +0200
@@ -7,14 +7,113 @@
 
 
 class InstructionSelector:
-    pass
+    def newTmp(self):
+        return 't999'
+
+    def munchProgram(self, p):
+        assert isinstance(p, ir.Module)
+        self.result = []
+        for f in p.Functions:
+            for bb in f.BasicBlocks:
+                for i in bb.Instructions:
+                    self.munchStm(i)
+        return self.result
+
+    def emit(self, *args, **kwargs):
+        """ Abstract instruction emitter """
+        i = irmach.AbstractInstruction(*args, **kwargs)
+        self.result.append(i)
+
+    def munchStm(self, s):
+        raise NotImplementedError()
+
+    def munchExpr(self, e):
+        raise NotImplementedError()
 
 
 class RegisterAllocator:
+    """ Target independent register allocator """
     pass
 
 
+class ArmInstructionSelector(InstructionSelector):
+    def munchExpr(self, e):
+        if isinstance(e, ir.Alloc):
+            return 0
+        elif isinstance(e, ir.Binop) and e.operation == '+':
+            a = self.munchExpr(e.value1)
+            b = self.munchExpr(e.value2)
+            d = self.newTmp()
+            self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b])
+            return d
+        elif isinstance(e, ir.Binop) and e.operation == '|':
+            a = self.munchExpr(e.value1)
+            b = self.munchExpr(e.value2)
+            d = self.newTmp()
+            self.emit('orrrr %d0, %s0, %s1', dst=[d], src=[a, b])
+            return d
+        elif isinstance(e, ir.Binop) and e.operation == '<<':
+            a = self.munchExpr(e.value1)
+            b = self.munchExpr(e.value2)
+            d = self.newTmp()
+            self.emit('lsl %d0, %s0, %s1', dst=[d], src=[a, b])
+            return d
+        elif isinstance(e, ir.Binop) and e.operation == '*':
+            a = self.munchExpr(e.value1)
+            b = self.munchExpr(e.value2)
+            d = self.newTmp()
+            self.emit('mylll %d0, %s0, %s1', dst=[d], src=[a, b])
+            return d
+        elif isinstance(e, ir.Const):
+            d = self.newTmp()
+            if e.value < 256:
+                self.emit('ldr %d0, {}'.format(e.value), dst=[d])
+            else:
+                self.emit('ldrpcrel TODO')
+            return d
+        elif isinstance(e, ir.Mem):
+            # Load from memory
+            loc = self.munchExpr(e.e)
+            d = self.newTmp()
+            self.emit('ldr %d0, [%s0]', src=[loc], dst=[d])
+            return d
+        elif isinstance(e, ir.Temp):
+            return e
+        else:
+            raise NotImplementedError('--> {}'.format(e))
+
+    def munchStm(self, s):
+        if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
+            memloc = self.munchExpr(s.dst.e)
+            val = self.munchExpr(s.src)
+            self.emit('str [%s0], %s1')
+        elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
+            val = self.munchExpr(s.src)
+            self.emit('str %d0, %s0', dst=[s.dst], src=[val])
+        elif isinstance(s, ir.Return):
+            self.emit('ret')
+        elif isinstance(s, ir.Jump):
+            self.emit('jmp {}'.format(s))
+        elif isinstance(s, ir.CJump):
+            self.munchExpr(s.a)
+            self.munchExpr(s.b)
+            self.emit('jmp {}'.format(s))
+        else:
+            raise NotImplementedError('--> {}'.format(s))
+
+
 class ArmCodeGenerator:
+    def __init__(self, outs):
+        self.ins_sel = ArmInstructionSelector()
+        self.outs = outs
+        self.outs.getSection('code').address = 0x08000000
+        self.outs.getSection('data').address = 0x20000000
+
+    def generate(self, ircode):
+        self.ins_sel.munchProgram(ircode)
+
+
+class ArmCodeGenerator_old:
     """
         Simple code generator
         Ad hoc implementation
--- a/python/cortexm3.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/cortexm3.py	Wed Aug 14 20:12:40 2013 +0200
@@ -327,7 +327,6 @@
     mnemonic = 'mov'
     opcode = 4 # 00100 Rd(3) imm8
     operands = (RegOp, Imm8)
-    irpattern = ir.ImmLoad
     def __init__(self, rd, imm):
         self.imm = imm.imm
         self.r = rd.num
--- a/python/ir/__init__.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/ir/__init__.py	Wed Aug 14 20:12:40 2013 +0200
@@ -2,5 +2,5 @@
 from .instruction import *
 from .function import Function
 from .builder import Builder
-from .basicblock import BasicBlock
+from .basicblock import Block
 
--- a/python/ir/basicblock.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/ir/basicblock.py	Wed Aug 14 20:12:40 2013 +0200
@@ -1,14 +1,19 @@
 
-class BasicBlock:
-    """ Uninterrupted sequence of instructions. """
+# from .instruction import Statement
+
+class Block:
+    """ 
+        Uninterrupted sequence of instructions with a label at the start.
+    """
     def __init__(self, name):
         self.name = name
         self.instructions = []
 
     def __repr__(self):
-        return 'BasicBlock {0}'.format(self.name)
+        return 'Block {0}'.format(self.name)
 
     def addInstruction(self, i):
+        #assert isinstance(i, Statement)
         i.parent = self
         self.instructions.append(i)
 
@@ -42,8 +47,7 @@
 
     def getSuccessors(self):
         if not self.Empty:
-            i = self.LastInstruction
-            return i.Targets
+            return self.LastInstruction.Targets
         return []
     Successors = property(getSuccessors)
 
@@ -59,6 +63,5 @@
         raise NotImplementedError()
 
     def check(self):
-        for ins in self.Instructions:
-            ins.check()
+        pass
 
--- a/python/ir/builder.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/ir/builder.py	Wed Aug 14 20:12:40 2013 +0200
@@ -1,71 +1,56 @@
-from . import Value, BasicBlock, Function, Variable
+from . import Block, Function, Statement, Temp
 
-class NameGenerator:
-   def __init__(self, prefix):
+class NamedClassGenerator:
+   def __init__(self, prefix, cls):
       self.prefix = prefix
+      self.cls = cls
       def NumGen():
          a = 0
          while True:
             yield a
             a = a + 1
       self.nums = NumGen()
+
    def gen(self, prefix=None):
       if not prefix:
          prefix = self.prefix
-      return '{0}{1}'.format(prefix, self.nums.__next__())
+      return self.cls('{0}{1}'.format(prefix, self.nums.__next__()))
 
-class ValueGenerator(NameGenerator):
-   def __init__(self):
-      super().__init__('t')
-   def gen(self, prefix=None):
-      v = Value(super().gen(prefix))
-      return v
-
-class BBGenerator(NameGenerator):
-   def __init__(self):
-      super().__init__('lab')
-   def gen(self):
-      v = BasicBlock(super().gen())
-      return v
 
 class Builder:
+    """ Base class for ir code generators """
     def __init__(self):
-      self.newTmp = ValueGenerator().gen
-      self.newBBint = BBGenerator().gen
-      self.bb = None
-      self.m = None
-      self.fn = None
-      self.loc = None
+        self.prepare()
+
+    def prepare(self):
+        self.newTemp = NamedClassGenerator('reg', Temp).gen
+        self.newBlock = NamedClassGenerator('block', Block).gen
+        self.bb = None
+        self.m = None
+        self.fn = None
+        self.loc = None
 
     # Helpers:
-    def newBB(self):
-      bb = self.newBBint()
-      self.fn.addBB(bb)
-      return bb
-
     def setModule(self, m):
-      self.m = m
+        self.m = m
 
     def newFunction(self, name):
       f = Function(name)
       self.m.addFunc(f)
       return f
 
-    def newVariable(self, name):
-        v = Variable(name)
-        self.m.addVariable(v)
-        return v
+    def setFunction(self, f):
+        self.fn = f
+        self.bb = f.entry if f else None
 
-    def setFunction(self, f):
-      self.fn = f
-
-    def setBB(self, bb):
-      self.bb = bb
+    def setBlock(self, b):
+        self.bb = b
 
     def setLoc(self, l):
         self.loc = l
 
-    def addIns(self, i):
+    def emit(self, i):
+        assert isinstance(i, Statement)
         i.debugLoc = self.loc
         if not self.bb:
             raise Exception('No basic block')
--- a/python/ir/function.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/ir/function.py	Wed Aug 14 20:12:40 2013 +0200
@@ -1,10 +1,9 @@
-from .basicblock import BasicBlock
+from .basicblock import Block
 
 class Function:
     def __init__(self, name):
       self.name = name
-      self.bbs = []
-      self.entry = None
+      self.entry = Block('entry')
 
     def __repr__(self):
         return 'Function {0}'.format(self.name)
@@ -19,7 +18,15 @@
         bb.parent = None
 
     def getBBs(self):
-        return self.bbs
+        bbs = [self.entry]
+        worklist = [self.entry]
+        while worklist:
+            b = worklist.pop()
+            for sb in b.Successors:
+                if sb not in bbs:
+                    bbs.append(sb)
+                    worklist.append(sb)
+        return bbs
 
     def findBasicBlock(self, name):
         for bb in self.bbs:
--- a/python/ir/instruction.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/ir/instruction.py	Wed Aug 14 20:12:40 2013 +0200
@@ -1,325 +1,129 @@
-from .basicblock import BasicBlock
 from .function import Function
 
-
-class Value:
-    """ Temporary SSA value (value that is assigned only once! """
-    def __init__(self, name):
-        # TODO: add typing? for now only handle integers
-        self.name = name
-        self.used_by = []
-        self.Setter = None
-
-    def __repr__(self):
-        return '{0}'.format(self.name) # + str(self.IsUsed)
-
-    @property
-    def UsedInBlocks(self):
-        bbs = [i.parent for i in self.used_by + [self.Setter]]
-        assert all(isinstance(bb, BasicBlock) for bb in bbs)
-        return set(bbs)
-
-    @property
-    def IsUsed(self):
-        return len(self.used_by) > 0
-
-    Used = IsUsed
-
-    def onlyUsedInBlock(self, bb):
-        return all(use.Block is bb for use in self.used_by)
-
-    def lastUse(self, ins):
-        assert ins in self.used_by
-        return all(not ins.precedes(ub) for ub in self.used_by)
-
-    def replaceby(self, v2):
-        for use_ins in self.used_by:
-            use_ins.replaceValue(self, v2.value)
-        assert not self.Used
-
-
-class Variable(Value):
+class Expression:
     pass
 
 
-class Use:
-    def __init__(self, user, val):
-        self.user = user
-        assert isinstance(val, Value)
-        self.val = val
-        self.val.used_by.append(self.user)
-
-    def delete(self):
-        self.val.used_by.remove(self.user)
-
-
-class Instruction:
-    """ Base class for all instructions. """
-    def __init__(self):
-        # live variables at this node:
-        self.live_in = set()
-        self.live_out = set()
-        # What variables this instruction uses and defines:
-        self.defs = []
-        self.uses = []
-
-    def delete(self):
-        while self.uses:
-            use = self.uses.pop()
-            use.delete()
-        while self.defs:
-            d = self.defs.pop()
-            d.Setter = None
-
-    def addUse(self, val):
-        self.uses.append(Use(self, val))
-
-    def removeUse(self, val):
-        for u in self.uses:
-            if u.val is val:
-                theUse = u
-        theUse.delete()
-        self.uses.remove(theUse)
-
-    def addDef(self, v):
-        self.defs.append(v)
-        assert v.Setter == None
-        v.Setter = self
+class Const(Expression):
+    def __init__(self, value):
+        self.value = value
 
-    def removeDef(self, v):
-        assert v.Setter is self
-        v.Setter = None
-        self.defs.remove(v)
-
-    def getParent(self):
-        return self.parent
-
-    def setParent(self, p):
-        self.parent = p
-    Parent = property(getParent, setParent)
-
-    def replaceValue(self, old, new):
-        # TODO: make this a generic function
-        raise NotImplementedError('{}'.format(type(self)))
-
-    @property
-    def Position(self):
-        return self.Block.Instructions.index(self)
-
-    def precedes(self, other):
-        assert isinstance(other, Instruction)
-        if self.Block is other.Block:
-            return other.Position > self.Position
-        else:
-            return self.Block.precedes(other.Block)
-
-    def follows(self, other):
-        pass
-
-    @property
-    def Function(self):
-        return self.Block.parent
-
-    @property
-    def Block(self):
-        return self.Parent
-
-    def check(self):
-        # Check that the variables defined by this instruction 
-        # are only used in the same block
-        for v in self.defs:
-            assert v.Setter is self
-            for ub in v.used_by:
-                assert ub.Function == self.Function
-
-        # Check that variables used are defined earlier:
-        for u in self.uses:
-            v = u.val
-            #assert self.Position > v.Setter.Position
-
+    def __repr__(self):
+        return 'Constant {}'.format(self.value)
 
 
 # Function calling:
-class Call(Instruction):
-   def __init__(self, callee, arguments, result=None):
-      super().__init__()
-      self.callee = callee
-      assert type(callee) is Function
-      self.arguments = arguments
-      for arg in arguments:
-         assert type(arg) is Value
-         self.addUse(arg)
-      self.result = result
-      if result:
-         assert type(result) is Value
-         self.addDef(result)
-
-   def __repr__(self):
-      if self.result:
-         pfx = '{0} = '.format(self.result)
-      else:
-         pfx = ''
-      args = ','.join([str(arg) for arg in self.arguments])
-      return pfx + '{0}({1})'.format(self.callee.name, args)
-
-
-class Alloc(Instruction):
-    """ Allocates space on the stack """
-    def __init__(self, value):
-        super().__init__()
-        assert isinstance(value, Value)
-        self.value = value
-        self.addDef(value)
+class Call(Expression):
+    def __init__(self, f, arguments):
+        self.f = f
+        assert type(f) is Function
+        self.arguments = arguments
 
     def __repr__(self):
-        return '{0} = alloc'.format(self.value)
-
-
-class ImmLoad(Instruction):
-    def __init__(self, target, value):
-        super().__init__()
-        assert type(target) is Value
-        self.target = target
-        self.value = value
-        self.addDef(target)
-
-    def __repr__(self):
-        return '{} = {}'.format(self.target, self.value)
+        args = ','.join([str(arg) for arg in self.arguments])
+        return '{}({})'.format(self.f.name, args)
 
 
 # Data operations
-class BinaryOperator(Instruction):
-    def __init__(self, result, operation, value1, value2):
-        super().__init__()
-        assert type(value1) is Value, str(value1) + str(type(value1))
-        assert type(value2) is Value, value2
-        self.result = result
-        self.addDef(result)
+class Binop(Expression):
+    ops = ['+', '-', '*', '/', '|', '&', '<<', '>>']
+    def __init__(self, value1, operation, value2):
+        assert operation in Binop.ops
         self.value1 = value1
         self.value2 = value2
-        self.addUse(value1)
-        self.addUse(value2)
         self.operation = operation
 
     def __repr__(self):
         a, b = self.value1, self.value2
-        return '{} = {} {} {}'.format(self.result, a, self.operation, b)
+        return '({} {} {})'.format(a, self.operation, b)
+
+
+def Add(a, b):
+    return Binop(a, '+', b)
+
+
+class Alloc(Expression):
+    """ Allocates space on the stack """
+    def __init__(self):
+        super().__init__()
 
-    def replaceValue(self, old, new):
-        if old is self.value1:
-            self.value1 = new
-        elif old is self.value2:
-            self.value2 = new
-        elif old is self.result:
-            self.result = new
-        else:
-            raise Exception()
-        self.removeUse(old)
-        self.addUse(new)
+    def __repr__(self):
+        return 'Alloc'
+
+
+class Temp(Expression):
+    """ Temporary storage, same as register """
+    def __init__(self, name):
+        self.name = name
+
+    def __repr__(self):
+        return 'T_{}_'.format(self.name)
 
 
-# Memory functions:
-class Load(Instruction):
-    def __init__(self, location, value):
-        super().__init__()
-        assert type(value) is Value
-        assert isinstance(location, Value), "Location must be a value"
-        self.value = value
-        self.addDef(value)
-        self.location = location
-        self.addUse(self.location)
+class Mem(Expression):
+    def __init__(self, e):
+        self.e = e
 
     def __repr__(self):
-        return '{} = [{}]'.format(self.value, self.location)
+        return '[{}]'.format(self.e)
+
+
+class Statement:
+    """ Base class for all instructions. """
+    pass
 
 
-class Store(Instruction):
-    def __init__(self, location, value):
-        super().__init__()
-        assert type(value) is Value, value
-        assert isinstance(location, Value), "Location must be a value"
-        self.location = location
-        self.value = value
-        self.addUse(value)
-        self.addUse(location)
+class Move(Statement):
+    def __init__(self, dst, src):
+        self.dst = dst
+        self.src = src
 
     def __repr__(self):
-        return '[{}] = {}'.format(self.location, self.value)
+        return '{} = {}'.format(self.dst, self.src)
+
+
+class Exp(Statement):
+    def __init__(self, e):
+        self.e = e
+
 
-    def replaceValue(self, old, new):
-        if old is self.value:
-            self.value = new
-        elif old is self.location:
-            self.location = new
-        else:
-            raise Exception()
-        self.removeUse(old)
-        self.addUse(new)
+class Label(Statement):
+    def __init__(self, name):
+        self.name = name
+        self.statements = []
+
+    def __repr__(self):
+        return 'LABEL {}:'.format(self.name)
 
 
 # Branching:
-class Terminator(Instruction):
-    @property
-    def Targets(self):
-        return self.getTargets()
-
-    def changeTarget(self, tfrom, tto):
-        pass
-
-
-class Branch(Terminator):
+class Jump(Statement):
     def __init__(self, target):
-        super().__init__()
-        assert type(target) is BasicBlock
         self.target = target
+        self.Targets = [target]
 
     def __repr__(self):
-        return 'BRANCH {0}'.format(self.target)
-
-    def getTargets(self):
-        return [self.target]
-
-    def changeTarget(self, tfrom, tto):
-        assert tfrom is self.target
-        self.target = tto
+        return 'BRANCH {}'.format(self.target.name)
 
 
-class ConditionalBranch(Terminator):
-    def __init__(self, a, cond, b, lab1, lab2):
-      super().__init__()
-      self.a = a
-      assert type(a) is Value
-      self.cond = cond
-      assert cond in ['==', '<', '>']
-      self.b = b
-      self.addUse(a)
-      self.addUse(b)
-      assert type(b) is Value
-      assert type(lab1) is BasicBlock
-      self.lab1 = lab1
-      assert type(lab2) is BasicBlock
-      self.lab2 = lab2
+class CJump(Statement):
+    def __init__(self, a, cond, b, lab_yes, lab_no):
+        assert cond in ['==', '<', '>', '>=', '<=', '!=']
+        self.a = a
+        self.cond = cond
+        self.b = b
+        self.lab_yes = lab_yes
+        self.lab_no = lab_no
+        self.Targets = [lab_yes, lab_no]
 
     def __repr__(self):
-        return 'IF {0} {1} {2} THEN {3} ELSE {4}'.format(self.a, self.cond, self.b, self.lab1, self.lab2)
-
-    def getTargets(self):
-        return [self.lab1, self.lab2]
-
-    def changeTarget(self, tfrom, tto):
-        assert tfrom is self.lab1 or tfrom is self.lab2
-        if tfrom is self.lab1:
-            self.lab1 = tto
-        elif tfrom is self.lab2:
-            self.lab2 = tto
+        return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no)
 
 
-class Return(Terminator):
-    def __init__(self, value=None):
-        super().__init__()
+class Return(Statement):
+    def __init__(self, value):
         self.value = value
-        if value:
-            self.addUse(value)
+        self.Targets = [] # TODO: Do this in another way
 
     def __repr__(self):
         if self.value:
@@ -327,15 +131,4 @@
         else:
             return 'ret'
 
-    def getTargets(self):
-        return []
 
-
-class PhiNode(Instruction):
-    def __init__(self):
-        super().__init__()
-        self.incBB = []
-
-    def addIncoming(self, bb):
-        self.incBB.append(bb)
-
--- a/python/ir/module.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/ir/module.py	Wed Aug 14 20:12:40 2013 +0200
@@ -1,6 +1,6 @@
 # IR-Structures:
 from .instruction import *
-from .basicblock import BasicBlock
+from .basicblock import Block
 
 class Module:
     """ Main container for a piece of code. """
@@ -81,10 +81,7 @@
     def check(self):
         """ Perform sanity check on module """
         for i in self.Instructions:
-            for t in i.defs:
-                assert type(t) is Value, "def must be Value, not {0}".format(type(t))
-            for t in i.uses:
-                assert type(t) is Use, "use must be Value, not {0}".format(type(t))
+            pass
         for f in self.Functions:
             f.check()
             
--- a/python/irmach.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/irmach.py	Wed Aug 14 20:12:40 2013 +0200
@@ -15,9 +15,15 @@
         self.instructions = []
 
 
-class MachIns:
+class AbstractInstruction:
     """ Absract machine instruction """
-    def __init__(self, mi):
-        self.mi = mi
+    def __init__(self, assem, src=(), dst=(), jumps=()):
+        self.assem = assem
+        self.src = tuple(src)
+        self.dst = tuple(dst)
+        self.jumps = tuple(jumps)
+
+    def __repr__(self):
+        return self.assem + str(self.src) + str(self.dst)
         
 
--- a/python/optimize.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/optimize.py	Wed Aug 14 20:12:40 2013 +0200
@@ -3,6 +3,7 @@
 from transform import DeadCodeDeleter, ConstantFolder
 
 def optimize(ir):
+    return
     cf = ConstantFolder()
     dcd = DeadCodeDeleter()
     m2r = Mem2RegPromotor()
--- a/python/stm32f4/burn2.c3	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/stm32f4/burn2.c3	Wed Aug 14 20:12:40 2013 +0200
@@ -24,7 +24,7 @@
     var int pin;
     pin = 15;
     // PD13 == output (01)
-    GPIOD->MODER = (1 << (pin << 1));
+    GPIOD->MODER = (1 << (pin * 2));
     GPIOD->ODR = (1 << pin);
 }
 
--- a/python/testc3.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/testc3.py	Wed Aug 14 20:12:40 2013 +0200
@@ -126,11 +126,11 @@
         p1 = """package p1;
         type int A;
         """
+        self.assertTrue(self.builder.build(p1))
         p2 = """package p2;
         import p1;
         var A b;
         """
-        self.assertTrue(self.builder.build(p1))
         self.expectOK(p2)
 
     def testFunctArgs(self):
@@ -171,27 +171,7 @@
             c = b * a - 3;
          }
       """
-      block_code = """ a0 = alloc
-        b1 = alloc
-        c2 = alloc
-        const3 = 1
-        [a0] = const3
-        t4 = [a0]
-        const5 = 2
-        mul6 = t4 * const5
-        t7 = [a0]
-        t8 = [a0]
-        mul9 = t7 * t8
-        add10 = mul6 + mul9
-        [b1] = add10
-        t11 = [b1]
-        t12 = [a0]
-        mul13 = t11 * t12
-        const14 = 3
-        sub15 = mul13 - const14
-        [c2] = sub15
-      ret """
-      self.expectIR(snippet, block_code)
+      self.expectOK(snippet)
 
     def testEmpty(self):
       snippet = """
@@ -284,16 +264,7 @@
             b = a + 2;
          }
         """
-        block_code = """a0 = alloc
-         b1 = alloc
-         const2 = 2
-         [a0] = const2
-         t3 = [a0]
-         const4 = 2
-         add5 = t3 + const4
-         [b1] = add5
-         ret  """
-        self.expectIR(snippet, block_code)
+        self.expectOK(snippet)
 
     def testUnknownType(self):
         snippet = """package testlocalvar;
@@ -314,21 +285,7 @@
             a.y = a.x + 2;
          }
         """
-        block_code = """a0 = alloc
-         const1 = 2
-         off_x2 = 0
-         adr_x3 = a0 + off_x2
-         [adr_x3] = const1
-         off_x4 = 0
-         adr_x5 = a0 + off_x4
-         t6 = [adr_x5]
-         const7 = 2
-         add8 = t6 + const7
-         off_y9 = 4
-         adr_y10 = a0 + off_y9
-         [adr_y10] = add8
-         ret  """
-        self.expectIR(snippet, block_code)
+        self.expectOK(snippet)
 
     def testPointerType1(self):
         snippet = """
@@ -381,14 +338,7 @@
             *a = 2;
          }
         """
-        block_code = """a0 = alloc
-         const1 = 40
-         [a0] = const1
-         const2 = 2
-         deref3 = [a0]
-         [deref3] = const2
-         ret  """
-        self.expectIR(snippet, block_code)
+        self.expectOK(snippet)
 
     def testPointerTypeIr2(self):
         snippet = """
@@ -402,26 +352,7 @@
             a->y = a->x - 14;
          }
         """
-        block_code = """a0 = alloc
-         const1 = 40
-         [a0] = const1
-         const2 = 2
-         deref3 = [a0]
-         off_x4 = 0
-         adr_x5 = deref3 + off_x4
-         [adr_x5] = const2
-         deref6 = [a0]
-         off_x7 = 0
-         adr_x8 = deref6 + off_x7
-         t9 = [adr_x8]
-         const10 = 14
-         sub11 = t9 - const10
-         deref12 = [a0]
-         off_y13 = 4
-         adr_y14 = deref12 + off_y13
-         [adr_y14] = sub11
-         ret  """
-        self.expectIR(snippet, block_code)
+        self.expectOK(snippet)
 
     def testWrongCast(self):
         snippet = """
--- a/python/testcg.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/testcg.py	Wed Aug 14 20:12:40 2013 +0200
@@ -8,9 +8,7 @@
     m = ir.Module('tst')
     f = ir.Function('tst')
     m.addFunction(f)
-    bb = ir.BasicBlock('entry')
-    f.addBasicBlock(bb)
-    return m, bb
+    return m, f.entry
 
 
 class testCodeGeneration(unittest.TestCase):
@@ -19,8 +17,8 @@
 
     def testFunction(self):
         m, bb = genTestFunction()
-        v = ir.Value('tst')
-        bb.addInstruction(ir.ImmLoad(v, 123))
+        bb.addInstruction(ir.Const(123))
+        bb.addInstruction(ir.Return(ir.Const(0)))
         m.check()
         obj = self.cg.generate(m)
         self.assertTrue(obj)
@@ -31,15 +29,13 @@
         s = outstream.OutputStream()
         cg = codegenarm.ArmCodeGenerator(s)
         m, bb = genTestFunction()
-        v = ir.Value('tst')
-        bb.addInstruction(ir.Alloc(v))
-        v2 = ir.Value('tst2')
-        bb.addInstruction(ir.ImmLoad(v2, 22))
-        bb.addInstruction(ir.Store(v, v2))
+        bb.addInstruction(ir.Move(ir.Mem(ir.Const(1)), ir.Const(22)))
+        bb.addInstruction(ir.Return(ir.Const(0)))
         m.check()
         cg.generate(m)
         #s.dump()
 
+
 if __name__ == '__main__':
     unittest.main()
 
--- a/python/testir.py	Mon Aug 12 20:14:47 2013 +0200
+++ b/python/testir.py	Wed Aug 14 20:12:40 2013 +0200
@@ -14,13 +14,12 @@
     def testBuilder(self):
         f = self.b.newFunction('add')
         self.b.setFunction(f)
-        bb = self.b.newBB()
-        self.b.setBB(bb)
-        v1 = self.b.newTmp('t')
-        self.b.addIns(ir.Return(v1))
+        bb = self.b.newBlock()
+        self.b.setBlock(bb)
+        self.b.emit(ir.Return(ir.Const(0)))
         self.m.check()
         # Run interpreter:
-        r = self.m.getFunction('add').call(1, 2)
+        # r = self.m.getFunction('add').call(1, 2)
         #self.assertEqual(3, r)
 
 class ConstantFolderTestCase(unittest.TestCase):
@@ -33,30 +32,19 @@
     def testBuilder(self):
         f = self.b.newFunction('test')
         self.b.setFunction(f)
-        bb = self.b.newBB()
-        self.b.setBB(bb)
-        v1 = self.b.newTmp('t')
-        v2 = self.b.newTmp('t')
-        v3 = self.b.newTmp('t')
-        self.b.addIns(ir.ImmLoad(v1, 5))
-        self.b.addIns(ir.ImmLoad(v2, 7))
-        self.b.addIns(ir.BinaryOperator(v3, '+', v1, v2))
-        self.assertEqual(3, len(self.m.Instructions))
+        self.b.setBlock(self.b.newBlock())
+        v1 = ir.Const(5)
+        v2 = ir.Const(7)
+        v3 = ir.Add(v1, v2)
         self.cf.run(self.m)
-        self.assertEqual(3, len(self.m.Instructions))
-        self.assertIsInstance(self.m.Instructions[-1], ir.ImmLoad)
-        self.assertEqual(12, self.m.Instructions[-1].value)
 
     def testAdd0(self):
         f = self.b.newFunction('test')
         self.b.setFunction(f)
-        bb = self.b.newBB()
-        self.b.setBB(bb)
-        v1 = self.b.newTmp('t')
-        v2 = self.b.newTmp('t')
-        v3 = self.b.newTmp('t')
-        self.b.addIns(ir.ImmLoad(v2, 0))
-        self.b.addIns(ir.BinaryOperator(v3, '+', v1, v2))
+        self.b.setBlock(self.b.newBlock())
+        v1 = ir.Const(0)
+        v2 = ir.Const(0)
+        v3 = ir.Add(v1, v2)
 
 
 testsrc = """