changeset 279:2ccd57b1d78c

Fix register allocator to do burn2 OK
author Windel Bouwman
date Sat, 12 Oct 2013 09:56:23 +0200
parents 9fca39eebe50
children 02385f62f250
files python/c3/codegenerator.py python/c3/examples/burn2.c3 python/canon.py python/codeedit.py python/codegenarm.py python/cortexm3.py python/hexedit.py python/ide.py python/instructionselector.py python/interferencegraph.py python/ir.py python/optimize.py python/registerallocator.py python/st-util.py python/tcodegen.py python/testgraph.py python/testir.py python/testregalloc.py python/transform.py python/trunner2.sh
diffstat 20 files changed, 284 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/codegenerator.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/c3/codegenerator.py	Sat Oct 12 09:56:23 2013 +0200
@@ -155,20 +155,22 @@
             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
+            assert type(ra) is ir.Mem
+            return ra.e
         elif type(expr) is astnodes.VariableUse:
-            return self.varMap[expr.target]
+            # This returns the dereferenced variable.
+            return ir.Mem(self.varMap[expr.target])
         elif type(expr) is astnodes.Deref:
             # dereference pointer type:
             addr = self.genExprCode(expr.ptr)
             return ir.Mem(addr)
         elif type(expr) is astnodes.FieldRef:
-            b = self.genExprCode(expr.base)
-            #b = b.e
+            base = self.genExprCode(expr.base)
+            assert type(base) is ir.Mem, type(base)
+            base = base.e
             bt = theType(expr.base.typ)
             offset = ir.Const(bt.fieldOffset(expr.field))
-            return ir.Mem(ir.Binop(b, '+', offset))
+            return ir.Mem(ir.Add(base, offset))
         elif type(expr) is astnodes.Literal:
             return ir.Const(expr.val)
         elif type(expr) is astnodes.TypeCast:
--- a/python/c3/examples/burn2.c3	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/c3/examples/burn2.c3	Sat Oct 12 09:56:23 2013 +0200
@@ -24,7 +24,7 @@
     var int pin;
     pin = 15;
     // PD13 == output (01)
-    GPIOD->MODER = (1 << (pin * 2));
+    GPIOD->MODER = (1 << (pin << 1));
     GPIOD->ODR = (1 << pin);
 }
 
--- a/python/canon.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/canon.py	Sat Oct 12 09:56:23 2013 +0200
@@ -58,7 +58,7 @@
         return frame.parMap[exp]
     elif isinstance(exp, ir.LocalVariable):
         offset = frame.allocVar(exp)
-        return ir.Mem(ir.Binop(frame.fp, '+', ir.Const(offset)))
+        return ir.Add(frame.fp, ir.Const(offset))
     elif isinstance(exp, ir.Mem):
         exp.e = rewriteExp(exp.e, frame)
         return exp
--- a/python/codeedit.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/codeedit.py	Sat Oct 12 09:56:23 2013 +0200
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 
 import sys
+import os
 from PyQt4.QtCore import *
 from PyQt4.QtGui import *
 import inspect
@@ -262,7 +263,9 @@
 
     def setFileName(self, fn):
         self.filename = fn
-        if not fn:
+        if fn:
+            fn = os.path.basename(fn)
+        else:
             fn = 'Untitled'
         self.setWindowTitle(fn)
 
--- a/python/codegenarm.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/codegenarm.py	Sat Oct 12 09:56:23 2013 +0200
@@ -70,11 +70,15 @@
         """
         self.instructions.insert(0, makeIns('{}:'.format(self.name)))
         self.instructions.insert(1, makeIns('push {lr, r7}'))
-        self.instructions.insert(2, makeIns('mov r7, sp'))
-        self.instructions.insert(3, makeIns('add sp, sp, {}'.format(self.stacksize)))
-        self.instructions.append(makeIns('sub sp, sp, {}'.format(self.stacksize)))
+        # Reserve stack space for locals:
+        self.instructions.insert(2, makeIns('sub sp, sp, {}'.format(self.stacksize)))
+        # Setup frame pointer:
+        self.instructions.insert(3, makeIns('mov r7, sp'))
+        # Stack grows downwards
+        self.instructions.append(makeIns('add sp, sp, {}'.format(self.stacksize)))
         self.instructions.append(makeIns('pop {pc,r7}'))
         # Add constant literals:
+        self.instructions.append(makeIns('align 4')) # Align at 4 bytes
         for ln, v in self.constants:
             self.instructions.append(makeIns('{}:'.format(ln)))
             self.instructions.append(makeIns('dcd {}'.format(v)))
@@ -86,7 +90,8 @@
     def munchExpr(self, e):
         if isinstance(e, ir.Alloc):
             return 0
-        elif isinstance(e, ir.Binop) and e.operation == '+' and isinstance(e.b, ir.Const) and e.b.value < 8:
+        elif isinstance(e, ir.Binop) and e.operation == '+' and \
+            isinstance(e.b, ir.Const) and e.b.value < 8:
             a = self.munchExpr(e.a)
             d = self.newTmp()
             self.emit('add %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a])
@@ -97,7 +102,8 @@
             d = self.newTmp()
             self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b])
             return d
-        elif isinstance(e, ir.Binop) and e.operation == '-' and isinstance(e.b, ir.Const) and e.b.value < 8:
+        elif isinstance(e, ir.Binop) and e.operation == '-' and \
+            isinstance(e.b, ir.Const) and e.b.value < 8:
             a = self.munchExpr(e.a)
             d = self.newTmp()
             self.emit('sub %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a])
@@ -112,22 +118,23 @@
             a = self.munchExpr(e.a)
             b = self.munchExpr(e.b)
             d = self.newTmp()
-            self.emit('mov %d0, %s0', src=[a], dst=[d])
-            self.emit('orr %d0, %s0', dst=[d], src=[b, d])
+            self.move(d, a)
+            self.emit('orr %s1, %s0', dst=[], src=[b, d])
             return d
         elif isinstance(e, ir.Binop) and e.operation == '<<':
             a = self.munchExpr(e.a)
             b = self.munchExpr(e.b)
             d = self.newTmp()
-            self.emit('mov %d0, %s0', src=[a], dst=[d])
-            self.emit('lsl %d0, %s0', dst=[d], src=[b, d]) # TODO: is d a source variable?
+            self.move(d, a)
+            self.emit('lsl %s1, %s0', dst=[], src=[b, d]) # TODO: is d a source variable?
             return d
         elif isinstance(e, ir.Binop) and e.operation == '*':
             a = self.munchExpr(e.a)
             b = self.munchExpr(e.b)
             d = self.newTmp()
-            self.emit('mov %d0, %s0', src=[a], dst=[d])
-            self.emit('mul %d0, %s0', dst=[d], src=[b, d])
+            self.move(d, a)
+            # this mul instruction has operands swapped:
+            self.emit('mul %s0, %d0', dst=[d], src=[b, d])
             return d
         elif isinstance(e, ir.Const) and e.value < 256:
             d = self.newTmp()
@@ -142,7 +149,8 @@
                 e.e.operation == '+' and isinstance(e.e.b, ir.Const):
             base = self.munchExpr(e.e.a)
             d = self.newTmp()
-            self.emit('ldr %d0, [%s0 + {}]'.format(e.e.b.value), src=[base], dst=[d])
+            c = e.e.b.value
+            self.emit('ldr %d0, [%s0 + {}]'.format(c), src=[base], dst=[d])
             return d
         elif isinstance(e, ir.Mem):
             # Load from memory
@@ -171,9 +179,13 @@
     def munchStm(self, s):
         if isinstance(s, ir.Terminator):
             pass
-        elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and isinstance(s.dst.e.a, ir.Temp) and isinstance(s.dst.e.b, ir.Const):
+        elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and \
+            isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \
+            isinstance(s.dst.e.b, ir.Const):
+            a = self.munchExpr(s.dst.e.a)
             val = self.munchExpr(s.src)
-            self.emit('str %s1, [%s0 + {}]'.format(s.dst.e.b.value), src=[s.dst.e.a, val])
+            c = s.dst.e.b.value
+            self.emit('str %s1, [%s0 + {}]'.format(c), src=[a, val])
         elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
             memloc = self.munchExpr(s.dst.e)
             val = self.munchExpr(s.src)
@@ -185,7 +197,7 @@
         elif isinstance(s, ir.Exp):
             # Generate expression code and discard the result.
             x = self.munchExpr(s.e)
-            self.emit('mov r0, r0', src=[x])
+            self.emit('nop', src=[x])
         elif isinstance(s, ir.Jump):
             tgt = self.targets[s.target]
             self.emit('b {}'.format(s.target.name), jumps=[tgt])
@@ -248,6 +260,10 @@
         # another interface?
         assembler = asm.Assembler(target=arm.armtarget, stream=self.outs)
         self.outs.selectSection('code')
+        # assembly glue to make it work:
+        self.outs.emit(arm.dcd_ins(Imm32(0x20000678))) # initial SP
+        self.outs.emit(arm.dcd_ins(Imm32(0x08000009))) # reset vector
+        self.outs.emit(arm.b_ins(LabelRef('main')))
         for frame in self.frames:
             for i in frame.instructions:
                 assembler.assemble_line(str(i))
--- a/python/cortexm3.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/cortexm3.py	Sat Oct 12 09:56:23 2013 +0200
@@ -218,6 +218,16 @@
     def __repr__(self):
         return 'DCD 0x{0:X}'.format(self.expr)
 
+@armtarget.instruction
+class nop_ins(ArmInstruction):
+    mnemonic = 'nop'
+    operands = tuple()
+
+    def encode(self):
+        return bytes()
+
+    def __repr__(self):
+        return 'NOP'
 
 
 # Memory related
@@ -299,6 +309,7 @@
     def encode(self):
         rt = self.rt.num
         assert rt < 8
+        assert self.offset % 4 == 0
         imm8 = self.offset >> 2
         assert imm8 < 256
         assert imm8 >= 0
@@ -434,7 +445,7 @@
 class mulregreg_ins(ArmInstruction):
     """ mul Rn, Rdm """
     operands = (Reg8Op, Reg8Op)
-    mnemonic = 'mul'
+    mnemonic = 'MUL'
     def __init__(self, rn, rdm):
         self.rn = rn
         self.rdm = rdm
--- a/python/hexedit.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/hexedit.py	Sat Oct 12 09:56:23 2013 +0200
@@ -5,7 +5,7 @@
 from PyQt4.QtGui import *
 from PyQt4 import uic
 
-BYTES_PER_LINE, GAP = 16, 12
+BYTES_PER_LINE, GAP = 8, 12
 
 def clamp(minimum, x, maximum):
    return max(minimum, min(x, maximum))
--- a/python/ide.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/ide.py	Sat Oct 12 09:56:23 2013 +0200
@@ -282,15 +282,18 @@
         self.builderrors.setErrorList(self.diag.diags)
         ce.setErrors(self.diag.diags)
         self.astViewer.setAst(pkg)
+        c3.AstPrinter().printAst(pkg)
         self.logger.info('Done!')
 
     def buildFile(self):
         ce = self.activeMdiChild()
         if not ce:
             return
+        fn = ce.FileName
+        wd = os.path.dirname(fn)
         self.diag.clear()
         outs = outstream.TextOutputStream()
-        if not zcc.zcc(ce.Source, outs, self.diag):
+        if not zcc.zcc(ce.Source, outs, self.diag, pack_dir=wd):
             # Set errors:
             self.builderrors.setErrorList(self.diag.diags)
             ce.setErrors(self.diag.diags)
@@ -300,14 +303,17 @@
         ce = self.activeMdiChild()
         if not ce:
             return
+        fn = ce.FileName
+        wd = os.path.dirname(fn)
         self.diag.clear()
         outs = outstream.TextOutputStream()
-        if not zcc.zcc(ce.Source, outs, self.diag, do_optimize=True):
+        if not zcc.zcc(ce.Source, outs, self.diag, do_optimize=True, pack_dir=wd):
             # Set errors:
             self.builderrors.setErrorList(self.diag.diags)
             ce.setErrors(self.diag.diags)
             return
 
+        outs.dump()
         code_s = outs.getSection('code')
         self.debugInfo = code_s.debugInfos()
         if self.ctrlToolbar.device:
--- a/python/instructionselector.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/instructionselector.py	Sat Oct 12 09:56:23 2013 +0200
@@ -1,4 +1,3 @@
-
 import ir
 import irmach
 from irmach import makeIns
@@ -36,7 +35,6 @@
             for i in bb.Instructions:
                 self.munchStm(i)
         self.munchStm(ir.Move(self.frame.rv, f.return_value))
-        self.emit('mov %s0, %s0', src=[self.frame.rv])
 
     def move(self, dst, src):
         self.emit('mov %d0, %s0', src=[src], dst=[dst])
--- a/python/interferencegraph.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/interferencegraph.py	Sat Oct 12 09:56:23 2013 +0200
@@ -6,9 +6,10 @@
         super().__init__(g)
         self.temps = [varname]
         self.moves = set()
+        self.color = None
 
     def __repr__(self):
-        return 'IGN<{}>'.format(self.temps)
+        return '{}({})'.format(self.temps, self.color)
 
 
 class InterferenceGraph(graph.Graph):
@@ -52,12 +53,24 @@
                     n2 = self.getNode(tmp2)
                     self.addEdge(n1, n2)
 
+    def to_dot(self, f):
+        """ Generate graphviz dot representation """
+        for node in self.nodes:
+            print('{} [label="{}" shape=box3d];'.format(id(node), node), file=f)
+        for n, m in self.edges:
+            print('{} -> {};'.format(id(n), id(m)), file=f)
+
+    def to_txt(self):
+        for node in self.nodes:
+            print('{} interferes: {}'.format(node, node.Adjecent))
+
     def getNode(self, tmp):
         # Linear search
         # TODO: can be improved for speed!
         for n in self.nodes:
             if tmp in n.temps:
                 return n
+        print('new one!')
         n = InterferenceGraphNode(self, tmp)
         self.addNode(n)
         return n
@@ -66,7 +79,15 @@
         """ Combine n and m into n """
         n.temps.extend(m.temps)
         n.moves.update(m.moves)
-        for t in m.Adjecent:
-            self.addEdge(n, t)
+        # Reroute all edges:
+        e1 = [e for e in self.edges if e[0] is m]
+        e2 = [e for e in self.edges if e[1] is m]
+        for e in e1:
+            self.edges.remove(e)
+            self.addEdge(n, e[1])
+        for e in e2:
+            self.edges.remove(e)
+            self.addEdge(n, e[0])
+        # Remove node m:
         self.delNode(m)
 
--- a/python/ir.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/ir.py	Sat Oct 12 09:56:23 2013 +0200
@@ -274,6 +274,14 @@
     """ Convenience call """
     return Binop(a, '+', b)
 
+def Sub(a, b):
+    return Binop(a, '-', b)
+
+def Mul(a, b):
+    return Binop(a, '*', b)
+
+def Div(a, b):
+    return Binop(a, '/', b)
 
 class Eseq(Expression):
     """ Sequence of instructions where the last is an expression """
@@ -397,6 +405,8 @@
         return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no)
 
 
+# Constructing IR:
+
 class NamedClassGenerator:
    def __init__(self, prefix, cls):
       self.prefix = prefix
--- a/python/optimize.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/optimize.py	Sat Oct 12 09:56:23 2013 +0200
@@ -3,13 +3,14 @@
 from transform import DeadCodeDeleter, ConstantFolder
 
 def optimize(ir):
+    return 
+    cf = ConstantFolder()
+    cf.run(ir)
     return
-    cf = ConstantFolder()
     dcd = DeadCodeDeleter()
     m2r = Mem2RegPromotor()
     clr = CleanPass()
     cse = CommonSubexpressionElimination()
-    cf.run(ir)
     dcd.run(ir)
     clr.run(ir)
     m2r.run(ir)
--- a/python/registerallocator.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/registerallocator.py	Sat Oct 12 09:56:23 2013 +0200
@@ -34,10 +34,18 @@
         self.activeMoves = set()
         self.worklistMoves = set()
 
+    def printLive(self):
+        print('Liveness:')
+        for i in self.f.instructions:
+            cfgn = self.f.cfg._map[i]
+            print(i, cfgn.live_in)
+
     def Build(self):
         """ 1. Construct interference graph from instruction list """
         self.f.cfg = FlowGraph(self.f.instructions)
         self.f.ig = InterferenceGraph(self.f.cfg)
+        self.printLive()
+
         self.Node = self.f.ig.getNode
 
         # Divide nodes into pre-colored and initial:
@@ -56,6 +64,7 @@
         dict(self.f.tempMap) # start with pre-colored
 
         self.moves = [i for i in self.f.instructions if i.ismove]
+        print(self.moves)
         for mv in self.moves:
             self.Node(mv.src[0]).moves.add(mv)
             self.Node(mv.dst[0]).moves.add(mv)
@@ -159,6 +168,7 @@
             okColors = self.regs - takenregs
             if okColors:
                 self.color[n] = first(okColors)
+                n.color = self.color[n]
             else:
                 raise NotImplementedError('Spill required here!')
         
@@ -166,6 +176,7 @@
         # Remove coalesced moves:
         for mv in self.coalescedMoves:
             self.f.instructions.remove(mv)
+
         # Use allocated registers:
         lookup = lambda t: self.color[self.Node(t)]
         for i in self.f.instructions:
@@ -173,7 +184,7 @@
             i.dst = tuple(map(lookup, i.dst))
 
     def allocFrame(self, f):
-        """ Do register allocation for a single stack frame. """
+        """ Do iterated register allocation for a single stack frame. """
         self.InitData(f)
         self.Build()
         self.makeWorkList()
--- a/python/st-util.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/st-util.py	Sat Oct 12 09:56:23 2013 +0200
@@ -19,34 +19,46 @@
          fl.addRow('Status:', QLabel(parent.stl.StatusString))
 
 class RegisterModel(QAbstractTableModel):
-   def __init__(self):
+    def __init__(self):
       super().__init__()
       self.regCount = 15
       self.device = None
-   def rowCount(self, parent):
+
+    def rowCount(self, parent):
       if parent.isValid():
          return 0
       if self.device:
          return 21 # TODO make variable
       else:
          return 0
-   def setDevice(self, dev):
+
+    def setDevice(self, dev):
       self.device = dev
       self.modelReset.emit()
-   def columnCount(self, parent):
+
+    def columnCount(self, parent):
       if parent.isValid():
          return 0
       return 2
-   def data(self, index, role):
+
+    def data(self, index, role):
       if index.isValid():
          row, col = index.row(), index.column()
          if role == Qt.DisplayRole:
             if col == 0:
-               return 'R{0}'.format(row)
+                if row == 15:
+                    return 'PC'
+                elif row == 14:
+                    return 'LR'
+                elif row == 13:
+                    return 'SP'
+                else:
+                    return 'R{0}'.format(row)
             elif col == 1:
                v = self.device.iface.read_reg(row)
                return '0x{0:X}'.format(v)
-   def setData(self, index, value, role):
+
+    def setData(self, index, value, role):
       if index.isValid():
          row = index.row()
          col = index.column()
@@ -55,14 +67,16 @@
             self.device.iface.write_reg(row, value)
             return True
       return False
-   def flags(self, index):
+
+    def flags(self, index):
       if index.isValid():
          row = index.row()
          col = index.column()
          if col == 1:
             return super().flags(index) | Qt.ItemIsEditable
       return super().flags(index)
-   def refresh(self):
+
+    def refresh(self):
       if self.device:
          fromIndex = self.index(0, 1)
          toIndex = self.index(21, 1)
@@ -70,15 +84,17 @@
 
 
 class RegisterView(QTableView):
-   def __init__(self):
+    def __init__(self):
       super().__init__()
       self.mdl = RegisterModel()
       self.setModel(self.mdl)
-   def refresh(self):
+
+    def refresh(self):
       if self.mdl.device:
          self.setEnabled(not self.mdl.device.Running)
       self.mdl.refresh()
 
+
 class MemoryView(QWidget):
     BlockSize = 0x100
     def __init__(self):
--- a/python/tcodegen.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/tcodegen.py	Sat Oct 12 09:56:23 2013 +0200
@@ -82,6 +82,10 @@
 function int ab(int a, int b)
 {
   var int c;
+  var int *a2;
+  a2 = cast<int*>(2);
+  *a2 = 2;
+  *a2 = *a2 + 2;
   c = 0;
   c = c + a + b;
   return c; 
@@ -127,16 +131,11 @@
     cga = codegenarm.ArmCodeGenerator(outs)
     ir2 = cga.generate(irc)
 
-    #with open('cfg.gv', 'w') as cfg_file:
-    #    dump_cfg(cga, cfg_file)
+    with open('cfg.gv', 'w') as cfg_file:
+        dump_cfg(cga, cfg_file)
 
-    #with open('ig.gv', 'w') as ig_file:
-    #    dump_ig(cga, ig_file)
+    with open('ig.gv', 'w') as ig_file:
+        dump_ig(cga, ig_file)
         
-    #for f in ir2:
-    #    print(f)
-    #    for i in f.instructions:
-    #        print('   {}'.format(i))
-
     outs.dump()
 
--- a/python/testgraph.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/testgraph.py	Sat Oct 12 09:56:23 2013 +0200
@@ -2,8 +2,14 @@
 
 import unittest
 import graph
+import interferencegraph
+import flowgraph
+import ir
+import irmach
+
 
 class GraphTestCase(unittest.TestCase):
+
     def testEdge(self):
         g = graph.Graph()
         n1 = graph.Node(g)
@@ -31,10 +37,48 @@
         g.delNode(n2)
         self.assertEqual(1, n1.Degree)
 
+
 class DigraphTestCase(unittest.TestCase):
     pass
         
 
+class InterferenceGraphTestCase(unittest.TestCase):
+    def testNormalUse(self):
+        t1 = ir.Temp('t1')
+        t2 = ir.Temp('t2')
+        t3 = ir.Temp('t3')
+        t4 = ir.Temp('t4')
+        t5 = ir.Temp('t5')
+        t6 = ir.Temp('t6')
+        instrs = []
+        instrs.append(irmach.makeIns('ld %d', dst=[t1]))
+        instrs.append(irmach.makeIns('ld %d', dst=[t2]))
+        instrs.append(irmach.makeIns('ld %d', dst=[t3]))
+        cfg = flowgraph.FlowGraph(instrs)
+        ig = interferencegraph.InterferenceGraph(cfg)
+
+    def testCombine(self):
+        t1 = ir.Temp('t1')
+        t2 = ir.Temp('t2')
+        t3 = ir.Temp('t3')
+        t4 = ir.Temp('t4')
+        instrs = []
+        instrs.append(irmach.makeIns('ld %d0', dst=[t1]))
+        instrs.append(irmach.makeIns('ld %d0', dst=[t2]))
+        instrs.append(irmach.makeIns('ld %d0', dst=[t3]))
+        instrs.append(irmach.makeIns('mov %d0, %s0', dst=[t4], src=[t3]))
+        instrs.append(irmach.makeIns('st %s0', src=[t4]))
+        instrs.append(irmach.makeIns('st %s0', src=[t1]))
+        instrs.append(irmach.makeIns('st %s0', src=[t2]))
+        cfg = flowgraph.FlowGraph(instrs)
+        ig = interferencegraph.InterferenceGraph(cfg)
+        ig.to_txt()
+        ig.Combine(ig.getNode(t4), ig.getNode(t3))
+        self.assertIs(ig.getNode(t4), ig.getNode(t3))
+        print('after')
+        ig.to_txt()
+
+
 if __name__ == '__main__':
     unittest.main()
 
--- a/python/testir.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/testir.py	Sat Oct 12 09:56:23 2013 +0200
@@ -66,7 +66,7 @@
         v2 = ir.Const(7)
         v3 = ir.Add(v1, v2)
         self.b.emit(ir.Jump(f.epiloog))
-        #self.cf.run(self.m)
+        self.cf.run(self.m)
 
     def testAdd0(self):
         f = self.b.newFunction('test')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/testregalloc.py	Sat Oct 12 09:56:23 2013 +0200
@@ -0,0 +1,63 @@
+import unittest
+import os
+import sys
+import irmach
+import registerallocator
+import ir
+
+
+class RegAllocTestCase(unittest.TestCase):
+    def setUp(self):
+        self.ra = registerallocator.RegisterAllocator()
+
+    def testRegAlloc(self):
+        f = irmach.Frame('tst')
+        f.regs = [1,2,3,4,5,6] # for test use numbers!
+        f.tempMap = {}
+        t1 = ir.Temp('t1')
+        t2 = ir.Temp('t2')
+        t3 = ir.Temp('t3')
+        t4 = ir.Temp('t4')
+        t5 = ir.Temp('t5')
+        f.instructions.append(irmach.makeIns('ld %d0', dst=[t1]))
+        f.instructions.append(irmach.makeIns('ld %d0', dst=[t2]))
+        f.instructions.append(irmach.makeIns('ld %d0', dst=[t3]))
+        f.instructions.append(irmach.makeIns('add %d0, %s0, %s1', dst=[t4], src=[t1, t2]))
+        f.instructions.append(irmach.makeIns('add %d0, %s0, %s1', dst=[t5], src=[t4, t3]))
+        f.instructions.append(irmach.makeIns('st %s0', src=[t5]))
+        self.ra.allocFrame(f)
+        self.conflict(t1, t2)
+        self.conflict(t2, t3)
+
+    def conflict(self, ta, tb):
+        self.assertNotEqual(self.ra.Node(ta).color, self.ra.Node(tb).color)
+
+    def testRegCoalesc(self):
+        f = irmach.Frame('tst')
+        f.regs = [1,2,3,4,5,6] # for test use numbers!
+        f.tempMap = {}
+        t1 = ir.Temp('t1')
+        t2 = ir.Temp('t2')
+        t3 = ir.Temp('t3')
+        t4 = ir.Temp('t4')
+        t5 = ir.Temp('t5')
+        t6 = ir.Temp('t6')
+        f.instructions.append(irmach.makeIns('ld %d0', dst=[t1]))
+        f.instructions.append(irmach.makeIns('ld %d0', dst=[t2]))
+        f.instructions.append(irmach.makeIns('ld %d0', dst=[t3]))
+        f.instructions.append(irmach.makeIns('lsl %s0, %s1', dst=[t4], src=[t2, t1]))
+        f.instructions.append(irmach.makeIns('mov %d0, %s0', dst=[t5], src=[t3]))
+        f.instructions.append(irmach.makeIns('orr %s0, %s1', dst=[t5], src=[t4, t5]))
+        f.instructions.append(irmach.makeIns('mov %d0, %s0', dst=[t6], src=[t5]))
+        f.instructions.append(irmach.makeIns('st %s0', src=[t6]))
+        self.ra.allocFrame(f)
+        f.ig.to_txt()
+        for i in f.instructions:
+            print(i)
+        self.conflict(t1, t2)
+        self.conflict(t2, t3)
+        self.conflict(t1, t3)
+
+if __name__ == '__main__':
+    unittest.main()
+
--- a/python/transform.py	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/transform.py	Sat Oct 12 09:56:23 2013 +0200
@@ -3,7 +3,7 @@
 """
 
 import logging
-from ir import *
+import ir
 # Standard passes:
 
 class FunctionPass:
@@ -46,34 +46,29 @@
         """ Override this virtual method """
         raise NotImplementedError()
 
-# Usefull transforms:
-class ConstantFolder(BasicBlockPass):
+class BasePass(BasicBlockPass):
     def onBasicBlock(self, bb):
-        constMap = {}
-        ins = [i for i in bb.Instructions if type(i) in [ImmLoad, BinaryOperator]]
-        for i in ins:
-            if type(i) is ImmLoad:
-                constMap[i.target] = i.value
-            elif type(i) is BinaryOperator:
-                if i.value1 in constMap and i.value2 in constMap and i.operation in ['+', '-', '*', '<<']:
-                    op = i.operation
-                    va = constMap[i.value1]
-                    vb = constMap[i.value2]
-                    if op == '+':
-                       vr = va + vb
-                    elif op == '*':
-                       vr = va * vb
-                    elif op == '-':
-                       vr = va - vb
-                    elif op == '<<':
-                        vr = va << vb
-                    else:
-                        raise NotImplementedError()
-                    constMap[i.result] = vr
-                    i.removeDef(i.result)
-                    i2 = ImmLoad(i.result, vr)
-                    logging.debug('Replacing {} with {}'.format(i, i2))
-                    i.Parent.replaceInstruction(i, i2)
+        pass
+
+# Usefull transforms:
+class ConstantFolder(BasePass):
+    def __init__(self):
+        super().__init__()
+        self.ops = {}
+        self.ops['+'] = lambda x, y: x + y
+        self.ops['-'] = lambda x, y: x - y
+        self.ops['*'] = lambda x, y: x * y
+        self.ops['<<'] = lambda x, y: x << y
+
+    def postExpr(self, expr):
+        if type(i) is BinaryOperator and i.operation in self.ops.keys() and type(i.a) is Const and type(i.b) is Const:
+            op = i.operation
+            va = i.a.value
+            vb = i.b.value
+            vr = self.ops[i.operation](va, vb)
+            return Const(vr)
+        else:
+            return expr
 
 
 class DeadCodeDeleter(BasicBlockPass):
--- a/python/trunner2.sh	Sun Sep 29 14:08:15 2013 +0200
+++ b/python/trunner2.sh	Sat Oct 12 09:56:23 2013 +0200
@@ -5,9 +5,9 @@
   python tcodegen.py
 
   # Create svg from dot file:
-  # dot -Tpdf -o ir.pdf ir.gv
-  #dot -Tpdf -o cfg.pdf cfg.gv
-  #dot -Tpdf -o ig.pdf ig.gv
+  #dot -Tpdf -o ir.pdf ir.gv
+  dot -Tpdf -o cfg.pdf cfg.gv
+  dot -Tpdf -o ig.pdf ig.gv
   echo "Awaiting changes in $DIR"
   inotifywait -r -e modify $DIR
 done