changeset 275:6f2423df0675

Fixed serve arm-as
author Windel Bouwman
date Sat, 14 Sep 2013 17:29:10 +0200
parents ea93e0a7a31e
children 56d37ed4b4d2
files python/c3/analyse.py python/c3/codegenerator.py python/canon.py python/codegenarm.py python/cortexm3.py python/instructionselector.py python/ir/__init__.py python/ir/module.py python/irmach.py python/registerallocator.py python/serve_arm_as.py python/target.py python/tcodegen.py python/testasm.py util/serve_arm_as.py
diffstat 15 files changed, 598 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/analyse.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/c3/analyse.py	Sat Sep 14 17:29:10 2013 +0200
@@ -124,6 +124,10 @@
             ft = sym.typ
             ft.returntype = self.resolveType(ft.returntype, sym.scope)
             ft.parametertypes = [self.resolveType(pt, sym.scope) for pt in ft.parametertypes]
+            # Mark local variables:
+            for d in sym.declarations:
+                if isinstance(d, Variable):
+                    d.isLocal = True
         elif type(sym) is DefinedType:
             sym.typ = self.resolveType(sym.typ, sym.scope)
 
--- a/python/c3/codegenerator.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/c3/codegenerator.py	Sat Sep 14 17:29:10 2013 +0200
@@ -35,7 +35,6 @@
             f = self.newFunction(s.name)
             self.funcMap[s] = f
         for v in pkg.innerScope.Variables:
-            #print(v)
             self.varMap[v] = self.newTemp()
         for s in pkg.innerScope.Functions:
             self.genFunction(s)
@@ -54,15 +53,14 @@
         for sym in fn.innerScope:
             # TODO: handle parameters different
             if sym.isParameter:
-                print('param', sym)
                 v = ir.Parameter(sym.name)
                 f.addParameter(v)
             elif sym.isLocal:
-                print('local', sym)
-                v = self.newTemp()
+                v = ir.LocalVariable(sym.name)
+                f.addLocal(v)
             else:
-                v = self.newTemp()
-                #raise NotImplementedError('{}'.format(sym))
+                #v = self.newTemp()
+                raise NotImplementedError('{}'.format(sym))
             # TODO: make this ssa here??
             self.varMap[sym] = v
 
@@ -84,7 +82,7 @@
             lval = self.genExprCode(code.lval)
             self.emit(ir.Move(lval, rval))
         elif type(code) is astnodes.ExpressionStatement:
-            self.genExprCode(code.ex)
+            self.emit(ir.Exp(self.genExprCode(code.ex)))
         elif type(code) is astnodes.IfStatement:
             bbtrue = self.newBlock()
             bbfalse = self.newBlock()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/canon.py	Sat Sep 14 17:29:10 2013 +0200
@@ -0,0 +1,128 @@
+
+import ir
+from itertools import chain
+
+def make(function, frame):
+    """
+        Create canonicalized version of the IR-code. This means:
+        - Calls out of expressions.
+        - Other things?
+    """
+    # Change the tree. This modifies the IR-tree!
+    # Move all parameters into registers
+    parmoves = []
+    for p in function.arguments:
+        pt = newTemp()
+        frame.parMap[p] = pt
+        parmoves.append(ir.Move(pt, frame.argLoc(p.num)))
+    function.entry.instructions = parmoves + function.entry.instructions
+
+    for block in function.Blocks:
+        for stmt in block.instructions:
+            rewriteStmt(stmt, frame)
+        linearize(block)
+
+# Visit all nodes with some function:
+# TODO: rewrite into visitor.
+
+# Rewrite rewrites call instructions into Eseq instructions.
+
+def rewriteStmt(stmt, frame):
+    if isinstance(stmt, ir.Jump):
+        pass
+    elif isinstance(stmt, ir.CJump):
+        stmt.a = rewriteExp(stmt.a, frame)
+        stmt.b = rewriteExp(stmt.b, frame)
+    elif isinstance(stmt, ir.Move):
+        stmt.src = rewriteExp(stmt.src, frame)
+        stmt.dst = rewriteExp(stmt.dst, frame)
+    elif isinstance(stmt, ir.Terminator):
+        pass
+    elif isinstance(stmt, ir.Exp):
+        stmt.e = rewriteExp(stmt.e, frame)
+    else:
+        raise NotImplementedError('STMT NI: {}'.format(stmt))
+
+newTemp = ir.NamedClassGenerator('canon_reg', ir.Temp).gen
+
+def rewriteExp(exp, frame):
+    if isinstance(exp, ir.Binop):
+        exp.a = rewriteExp(exp.a, frame)
+        exp.b = rewriteExp(exp.b, frame)
+        return exp
+    elif isinstance(exp, ir.Const):
+        return exp
+    elif isinstance(exp, ir.Temp):
+        return exp
+    elif isinstance(exp, ir.Parameter):
+        return frame.parMap[exp]
+    elif isinstance(exp, ir.LocalVariable):
+        offset = frame.allocVar(exp)
+        return ir.Mem(ir.Binop(frame.fp, '+', ir.Const(offset)))
+    elif isinstance(exp, ir.Mem):
+        exp.e = rewriteExp(exp.e, frame)
+        return exp
+    elif isinstance(exp, ir.Call):
+        exp.arguments = [rewriteExp(p, frame) for p in exp.arguments]
+        # Rewrite call into eseq:
+        t = newTemp()
+        return ir.Eseq(ir.Move(t, exp), t)
+    else:
+        raise NotImplementedError('NI: {}'.format(exp))
+        
+# The flatten functions pull out seq instructions to the sequence list.
+
+def flattenExp(exp):
+    if isinstance(exp, ir.Binop):
+        exp.a, sa = flattenExp(exp.a)
+        exp.b, sb = flattenExp(exp.b)
+        return exp, sa + sb
+    elif isinstance(exp, ir.Temp):
+        return exp, []
+    elif isinstance(exp, ir.Const):
+        return exp, []
+    elif isinstance(exp, ir.Mem):
+        exp.e, s = flattenExp(exp.e)
+        return exp, s
+    elif isinstance(exp, ir.Eseq):
+        s = flattenStmt(exp.stmt)
+        exp.e, se = flattenExp(exp.e)
+        return exp.e, s + se
+    elif isinstance(exp, ir.Call):
+        sp = []
+        p = []
+        for p_, sp_ in (flattenExp(p) for p in exp.arguments):
+            p.append(p_)
+            sp.extend(sp_)
+        exp.arguments = p
+        return exp, sp
+    else:
+        raise NotImplementedError('NI: {}'.format(exp))
+
+def flattenStmt(stmt):
+    if isinstance(stmt, ir.Jump):
+        return [stmt]
+    elif isinstance(stmt, ir.CJump):
+        stmt.a, sa = flattenExp(stmt.a)
+        stmt.b, sb = flattenExp(stmt.b)
+        return sa + sb + [stmt]
+    elif isinstance(stmt, ir.Move):
+        stmt.dst, sd = flattenExp(stmt.dst)
+        stmt.src, ss = flattenExp(stmt.src)
+        return sd + ss + [stmt]
+    elif isinstance(stmt, ir.Terminator):
+        return [stmt]
+    elif isinstance(stmt, ir.Exp):
+        stmt.e, se = flattenExp(stmt.e)
+        return se + [stmt]
+    else:
+        raise NotImplementedError('STMT NI: {}'.format(stmt))
+
+
+def linearize(block):
+    """ 
+      Move seq instructions to top and flatten these in an instruction list
+    """
+    i = list(flattenStmt(s) for s in block.instructions)
+    block.instructions = list(chain.from_iterable(i))
+
--- a/python/codegenarm.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/codegenarm.py	Sat Sep 14 17:29:10 2013 +0200
@@ -7,109 +7,179 @@
 import registerallocator
 from instructionselector import InstructionSelector
 import irmach
-
+from irmach import makeIns
+import canon
+import asm
 
 class ArmFrame(irmach.Frame):
     """
       Arm specific frame for functions.
     """
-    pass
+    def __init__(self, name):
+        # We use r7 as frame pointer.
+        super().__init__(name)
+        self.regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6']
+        self.rv = ir.Temp('special_RV')
+        self.p1 = ir.Temp('special_P1')
+        self.p2 = ir.Temp('special_P2')
+        self.p3 = ir.Temp('special_P3')
+        self.p4 = ir.Temp('special_P4')
+        self.fp = ir.Temp('special_FP')
+        # Pre-colored registers:
+        self.tempMap = {}
+        self.tempMap[self.rv] = 'r0'
+        self.tempMap[self.p1] = 'r1'
+        self.tempMap[self.p2] = 'r2'
+        self.tempMap[self.p3] = 'r3'
+        self.tempMap[self.p4] = 'r4'
+        self.tempMap[self.fp] = 'r7'
+        self.locVars = {}
+        self.parMap = {}
+
+    def argLoc(self, pos):
+        """
+            Gets the function parameter location in IR-code format.
+        """
+        if pos == 0:
+            return self.p1
+        elif pos == 1:
+            return self.p2
+        elif pos == 2:
+            return self.p3
+        elif pos == 3:
+            return self.p4
+        else:
+            raise NotImplementedError('No more than 4 parameters implemented')
+
+    def allocVar(self, lvar):
+        if lvar not in self.locVars:
+            self.locVars[lvar] = self.stacksize
+            self.stacksize = self.stacksize + 4
+        return self.locVars[lvar]
+
+    def EntryExitGlue3(self):
+        """
+            Add code for the prologue and the epilogue. Add a label, the
+            return instruction and the stack pointer adjustment for the frame.
+        """
+        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)))
+        self.instructions.append(makeIns('pop {pc,r7}'))
 
 
 class ArmInstructionSelector(InstructionSelector):
     """ Instruction selector for the arm architecture """
-    def newFrame(self, name):
-        return ArmFrame(name)
-
     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:
+            a = self.munchExpr(e.a)
+            d = self.newTmp()
+            self.emit('add %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a])
+            return d
         elif isinstance(e, ir.Binop) and e.operation == '+':
-            a = self.munchExpr(e.value1)
-            b = self.munchExpr(e.value2)
+            a = self.munchExpr(e.a)
+            b = self.munchExpr(e.b)
             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:
+            a = self.munchExpr(e.a)
+            d = self.newTmp()
+            self.emit('sub %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a])
+            return d
         elif isinstance(e, ir.Binop) and e.operation == '-':
-            a = self.munchExpr(e.value1)
-            b = self.munchExpr(e.value2)
+            a = self.munchExpr(e.a)
+            b = self.munchExpr(e.b)
             d = self.newTmp()
             self.emit('sub %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)
+            a = self.munchExpr(e.a)
+            b = self.munchExpr(e.b)
             d = self.newTmp()
             self.emit('or %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)
+            a = self.munchExpr(e.a)
+            b = self.munchExpr(e.b)
             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)
+            a = self.munchExpr(e.a)
+            b = self.munchExpr(e.b)
             d = self.newTmp()
             self.emit('mul %d0, %s0, %s1', dst=[d], src=[a, b])
             return d
-        elif isinstance(e, ir.Const):
+        elif isinstance(e, ir.Const) and e.value < 256:
             d = self.newTmp()
-            if e.value < 256:
-                self.emit('ldr %d0, {}'.format(e.value), dst=[d])
-            else:
-                self.emit('ldrpcrel TODO', dst=[d])
+            self.emit('mov %d0, {}'.format(e.value), dst=[d])
+            return d
+        elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \
+                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])
             return d
         elif isinstance(e, ir.Mem):
             # Load from memory
-            loc = self.munchExpr(e.e)
+            base = self.munchExpr(e.e)
             d = self.newTmp()
-            self.emit('ldr %d0, [%s0]', src=[loc], dst=[d])
+            self.emit('ldr %d0, [%s0]', src=[base], dst=[d])
             return d
         elif isinstance(e, ir.Temp):
-            return self.getTempReg(e)
-        elif isinstance(e, ir.Parameter):
-            offset = 1337 # TODO: determine offset in frame??
-            d = self.newTmp()
-            self.emit('ldr %d0, [sp + {}]'.format(offset), dst=[d])
-            return d
+            return e
         elif isinstance(e, ir.Call):
-            args = [self.munchExpr(a) for a in e.arguments]
-            frame_size = 222 # TODO: determine frame size?
-            self.emit('add sp, sp, {}'.format(frame_size))
-            # TODO: save frame
-            for a in args:
-                self.emit('push %s0', src=[a])
-            self.emit('bl {}'.format(e.f.name))
-            self.emit('sub sp, sp, 22')
+            # Move arguments into proper locations:
+            reguses = []
+            for i, a in enumerate(e.arguments):
+                loc = self.frame.argLoc(i)
+                m = ir.Move(loc, a)
+                self.munchStm(m)
+                if isinstance(loc, ir.Temp):
+                    reguses.append(loc)
+            self.emit('bl {}'.format(e.f.name), src=reguses, dst=[self.frame.rv])
+            d = self.newTmp()
+            self.move(d, self.frame.rv)
+            return d
         else:
             raise NotImplementedError('Expr --> {}'.format(e))
 
     def munchStm(self, s):
-        if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
+        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):
+            val = self.munchExpr(s.src)
+            self.emit('str %s1, [%s0 + {}]'.format(s.dst.e.b.value), src=[s.dst.e.a, val])
+        elif 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', src=[memloc, val])
+            self.emit('str %s1, [%s0]', src=[memloc, val])
         elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
             val = self.munchExpr(s.src)
-            dreg = self.getTempReg(s.dst)
+            dreg = s.dst
             self.emit('mov %d0, %s0', dst=[dreg], src=[val])
+        elif isinstance(s, ir.Exp):
+            # Generate expression code and discard the result.
+            x = self.munchExpr(s.e)
+            self.emit('mov r0, r0', src=[x])
         elif isinstance(s, ir.Jump):
             tgt = self.targets[s.target]
-            self.emit('jmp %l0', jumps=[tgt])
+            self.emit('b {}'.format(s.target.name), jumps=[tgt])
         elif isinstance(s, ir.CJump):
             a = self.munchExpr(s.a)
             b = self.munchExpr(s.b)
             self.emit('cmp %s0, %s1', src=[a, b])
             ntgt = self.targets[s.lab_no]
             ytgt = self.targets[s.lab_yes]
-            jmp_ins = self.makeIns('jmp %l0', jumps=[ntgt])
+            jmp_ins = makeIns('jmp {}'.format(s.lab_no.name), jumps=[ntgt])
             # Explicitely add fallthrough:
             self.emit('jeq %l0', jumps=[ytgt, jmp_ins])
             self.emit2(jmp_ins)
-        elif isinstance(s, ir.Terminator):
-            pass
         else:
             raise NotImplementedError('Stmt --> {}'.format(s))
 
@@ -136,7 +206,7 @@
         defTemps = set(defTemps)
         useTemps = set(useTemps)
         unUsed = defTemps - useTemps
-        print('Unused:', unUsed)
+        assert not unUsed
         for uu in unUsed:
             inslist.append(irmach.AbstractInstruction('use %s0', src=[uu]))
         #print(useTemps)
@@ -152,26 +222,49 @@
         ig = registerallocator.InterferenceGraph(cfg)
         f.ig = ig
 
-        regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7']
         ra = registerallocator.RegisterAllocator()
-        regMap = ra.registerAllocate(ig, regs)
-        #print(regMap)
+        regMap = ra.registerAllocate(ig, f.regs, f.tempMap)
         # Use allocated registers:
         for i in ilist:
             i.src = tuple(regMap[t] for t in i.src)
             i.dst = tuple(regMap[t] for t in i.dst)
-            #print(i)
+
+    def generateFunc(self, irfunc):
+        # Create a frame for this function:
+        frame = ArmFrame(irfunc.name)
+        # Canonicalize the intermediate language:
+        canon.make(irfunc, frame)
+        # print('after canonicalize:')
+        # irfunc.dump()
+        self.ins_sel.munchFunction(irfunc, frame)
+        # print('Selected instructions:')
+        #for i in frame.instructions:
+        #    print(i)
+        
+        # Do register allocation:
+        self.allocFrame(frame)
+        # TODO: Peep-hole here?
+
+        # Add label and return and stack adjustment:
+        frame.EntryExitGlue3()
+        return frame
 
     def generate(self, ircode):
         # Munch program into a bunch of frames. One frame per function.
         # Each frame has a flat list of abstract instructions.
-        frames = self.ins_sel.munchProgram(ircode)
-        self.frames = frames
-        for f in frames:
-            self.allocFrame(f)
+        # Generate code for all functions:
+        self.frames = [self.generateFunc(func) for func in ircode.Functions]
 
-        # TODO: Peep-hole here
-        # TODO: Materialize assembly
-        return frames
+        # Materialize assembly
+        # Reparse the register allocated instructions into a stream of
+        # real instructions.
+        # TODO: this is ugly via string representations. This could be 
+        # another interface?
+        assembler = asm.Assembler(target=arm.armtarget, stream=self.outs)
+        self.outs.selectSection('code')
+        for frame in self.frames:
+            for i in frame.instructions:
+                assembler.assemble_line(str(i))
 
+        return self.frames
 
--- a/python/cortexm3.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/cortexm3.py	Sat Sep 14 17:29:10 2013 +0200
@@ -1,11 +1,12 @@
 import struct
 import types
-from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef, Imm32
+from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef, Imm32, Imm7
 from asmnodes import ASymbol, ANumber, AUnop, ABinop
 from ppci import CompilerError
 import ir
 
 # TODO: encode this in DSL (domain specific language)
+# TBD: is this required?
 
 def u16(h):
     return struct.pack('<H', h)
@@ -55,6 +56,30 @@
                 if r.num < 8:
                     return cls(r.num)
 
+class Reg16Op:
+    def __init__(self, num):
+        assert num < 16
+        self.num = num
+
+    @classmethod
+    def Create(cls, vop):
+        if type(vop) is ASymbol:
+            name = vop.name
+            regs = {}
+            for r in armtarget.registers:
+                regs[r.name] = r
+            if name in regs:
+                r = regs[name]
+                if r.num < 16:
+                    return cls(r.num)
+
+class RegSpOp:
+    @classmethod
+    def Create(cls, vop):
+        if type(vop) is ASymbol:
+            if vop.name.lower() == 'sp':
+                return cls()
+
 def getRegNum(n):
     for r in armtarget.registers:
         if r.num == n:
@@ -244,6 +269,7 @@
 
         h = (self.opcode << 11) | (imm5 << 6) | (Rn << 3) | Rt
         return u16(h)
+
     def __repr__(self):
         return '{} {}, {}'.format(self.mnemonic, self.rt, self.memloc)
 
@@ -346,6 +372,8 @@
 
 # Arithmatics:
 
+
+
 @armtarget.instruction
 class addregregimm3_ins(ArmInstruction):
     """ add Rd, Rn, imm3 """
@@ -391,6 +419,25 @@
     mnemonic = 'SUB'
     opcode = 0b0001101
 
+
+@armtarget.instruction
+class movregreg_ext_ins(ArmInstruction):
+    operands = (Reg16Op, Reg16Op)
+    mnemonic = 'MOV'
+    def __init__(self, rd, rm):
+        self.rd = rd
+        self.rm = rm
+    def encode(self):
+        Rd = self.rd.num & 0x7
+        D = (self.rd.num >> 3) & 0x1
+        Rm = self.rm.num
+        opcode = 0b01000110
+        return u16((opcode << 8) | (D << 7) |(Rm << 3) | Rd)
+    def __repr__(self):
+        return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm)
+        
+
+
 class regreg_base(ArmInstruction):
     """ ??? Rdn, Rm """
     operands = (Reg8Op, Reg8Op)
@@ -575,5 +622,32 @@
     def encode(self):
         return u16(0xbf10)
 
+# misc:
+
+# add/sub SP:
+@armtarget.instruction
+class addspsp_ins(ArmInstruction):
+    operands = (RegSpOp, RegSpOp, Imm7)
+    mnemonic = 'add'
+    def __init__(self, _sp, _sp2, imm7):
+        self.imm7 = imm7.imm
+        assert self.imm7 % 4 == 0
+        self.imm7 >>= 2
+
+    def encode(self):
+        return u16((0b101100000 << 7) |self.imm7)
+
+@armtarget.instruction
+class subspsp_ins(ArmInstruction):
+    operands = (RegSpOp, RegSpOp, Imm7)
+    mnemonic = 'sub'
+    def __init__(self, _sp, _sp2, imm7):
+        self.imm7 = imm7.imm
+        assert self.imm7 % 4 == 0
+        self.imm7 >>= 2
+
+    def encode(self):
+        return u16((0b101100001 << 7) |self.imm7)
+
 armtarget.check()
 
--- a/python/instructionselector.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/instructionselector.py	Sat Sep 14 17:29:10 2013 +0200
@@ -1,11 +1,12 @@
 
 import ir
 import irmach
+from irmach import makeIns
 
 def genTemps():
     n = 900
     while True:
-        yield 't{}'.format(n)
+        yield ir.Temp('t{}'.format(n))
         n = n + 1
 
 class InstructionSelector:
@@ -13,51 +14,42 @@
         Base instruction selector. This class must be overridden by
         backends.
     """
+    def __init__(self):
+        self.temps = genTemps()
+
     def newTmp(self):
         return self.temps.__next__()
 
-    def getTempReg(self, tmp):
-        if tmp not in self.tempMap:
-            self.tempMap[tmp] = self.newTmp()
-        return self.tempMap[tmp]
-
-    def munchProgram(self, p):
+    def munchFunction(self, f, frame):
         # Entry point for instruction selection
-        self.temps = genTemps()
-        assert isinstance(p, ir.Module)
-        self.frames = []
+        assert isinstance(f, ir.Function)
         self.targets = {}
-        self.tempMap = {} # Mapping from temporaries to infinite register
-        for f in p.Functions:
-            # Enter a frame per function:
-            self.frame = self.newFrame(f.name)
-            self.frames.append(self.frame)
-            # First define labels:
-            for bb in f.Blocks:
-                itgt = self.makeIns('{}:'.format(bb.name))
-                self.targets[bb] = itgt
-            for bb in f.Blocks:
-                self.emit2(self.targets[bb])
-                for i in bb.Instructions:
-                    self.munchStm(i)
-                #bb.machIns = self.result
-        return self.frames
+        # Enter a frame per function:
+        self.frame = frame
+        # First define labels:
+        for bb in f.Blocks:
+            itgt = makeIns('{}:'.format(bb.name))
+            self.targets[bb] = itgt
+        # Generate code for all blocks:
+        for bb in f.Blocks:
+            self.emit2(self.targets[bb])
+            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 makeIns(self, *args, **kwargs):
-        return irmach.AbstractInstruction(*args, **kwargs)
+    def move(self, dst, src):
+        self.emit('mov %d0, %s0', src=[src], dst=[dst])
 
     def emit(self, *args, **kwargs):
         """ Abstract instruction emitter """
-        i = self.makeIns(*args, **kwargs)
+        i = makeIns(*args, **kwargs)
         return self.emit2(i)
 
     def emit2(self, i):
         self.frame.instructions.append(i)
         return i
 
-    def newFrame(self, name):
-        raise NotImplementedError()
-
     def munchStm(self, s):
         """ Implement this in the target specific back-end """
         raise NotImplementedError()
--- a/python/ir/__init__.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/ir/__init__.py	Sat Sep 14 17:29:10 2013 +0200
@@ -1,3 +1,3 @@
 from .module import *
-from .builder import Builder
+from .builder import Builder, NamedClassGenerator
 
--- a/python/ir/module.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/ir/module.py	Sat Sep 14 17:29:10 2013 +0200
@@ -20,9 +20,9 @@
 class Module:
     """ Main container of variables and functions. """
     def __init__(self, name):
-      self.name = name
-      self.funcs = []
-      self.variables = []
+        self.name = name
+        self.funcs = []
+        self.variables = []
 
     def __repr__(self):
         return 'IR-module [{0}]'.format(self.name)
@@ -53,17 +53,12 @@
 
     getFunction = findFunction
 
-    def dump(self):
+    def dump(self, indent='   '):
         print(self)
-        indent = '   '
         for v in self.Variables:
             print(indent, v)
         for fn in self.Functions:
-            print(fn)
-            for bb in fn.Blocks:
-                print(indent+str(bb))
-                for ins in bb.Instructions:
-                    print(indent * 2 + str(ins))
+            fn.dump(indent=indent+'   ')
 
     # Analysis functions:
     def check(self):
@@ -81,7 +76,9 @@
         self.entry = Block('{}_entry'.format(name))
         self.epiloog = Block('{}_epilog'.format(name))
         self.epiloog.addInstruction(Terminator())
+        self.return_value = Temp('{}_retval'.format(name))
         self.arguments = []
+        self.localvars = []
 
     def __repr__(self):
         args = ','.join(str(a) for a in self.arguments)
@@ -128,17 +125,21 @@
         for b in self.Blocks:
             b.check()
 
-    def addParameter(self, pname):
-        self.arguments.append(pname)
+    def addParameter(self, p):
+        assert type(p) is Parameter
+        p.num = len(self.arguments)
+        self.arguments.append(p)
 
-    def call(self, *args):
-        varmap = {}
-        bb = self.Entry
-        ip = 0
-        while True:
-            i = bb.Instructions[ip]
-            ip += 1
-            return
+    def addLocal(self, l):
+        assert type(l) is LocalVariable
+        self.localvars.append(l)
+
+    def dump(self, indent=''):
+        print(indent+str(self))
+        for bb in self.Blocks:
+            print(indent+'   '+str(bb))
+            for ins in bb.Instructions:
+                print(indent +'   '*2 + str(ins))
 
 
 class Block:
@@ -220,7 +221,7 @@
         self.value = value
 
     def __repr__(self):
-        return 'Constant {}'.format(self.value)
+        return 'Const {}'.format(self.value)
 
 
 # Function calling:
@@ -231,7 +232,7 @@
         self.arguments = arguments
 
     def __repr__(self):
-        args = ','.join([str(arg) for arg in self.arguments])
+        args = ', '.join([str(arg) for arg in self.arguments])
         return '{}({})'.format(self.f.name, args)
 
 
@@ -240,12 +241,12 @@
     ops = ['+', '-', '*', '/', '|', '&', '<<', '>>']
     def __init__(self, value1, operation, value2):
         assert operation in Binop.ops
-        self.value1 = value1
-        self.value2 = value2
+        self.a = value1
+        self.b = value2
         self.operation = operation
 
     def __repr__(self):
-        a, b = self.value1, self.value2
+        a, b = self.a, self.b
         return '({} {} {})'.format(a, self.operation, b)
 
 
@@ -254,6 +255,16 @@
     return Binop(a, '+', b)
 
 
+class Eseq(Expression):
+    """ Sequence of instructions where the last is an expression """
+    def __init__(self, stmt, e):
+        self.stmt = stmt
+        self.e = e
+
+    def __repr__(self):
+        return '({}, {})'.format(self.stmt, self.e)
+
+
 class Alloc(Expression):
     """ Allocates space on the stack """
     def __init__(self):
@@ -272,11 +283,8 @@
 
 
 class LocalVariable(Variable):
-    pass
-
-
-class GlobalVariable(Variable):
-    pass
+    def __repr__(self):
+        return 'Local {}'.format(self.name)
 
 
 class Parameter(Variable):
@@ -290,7 +298,7 @@
         self.name = name
 
     def __repr__(self):
-        return 'T_{}_'.format(self.name)
+        return 'TMP_{}'.format(self.name)
 
 
 class Mem(Expression):
@@ -319,8 +327,12 @@
     def __init__(self, e):
         self.e = e
 
+    def __repr__(self):
+        return '{}'.format(self.e)
+
 
 class Label(Statement):
+    # TODO: is this duplicate with block?
     def __init__(self, name):
         self.name = name
         self.statements = []
@@ -351,8 +363,9 @@
 
 
 class CJump(LastStatement):
+    conditions = ['==', '<', '>', '>=', '<=', '!=']
     def __init__(self, a, cond, b, lab_yes, lab_no):
-        assert cond in ['==', '<', '>', '>=', '<=', '!=']
+        assert cond in CJump.conditions 
         self.a = a
         self.cond = cond
         self.b = b
--- a/python/irmach.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/irmach.py	Sat Sep 14 17:29:10 2013 +0200
@@ -16,10 +16,13 @@
     def __init__(self, name):
         self.name = name
         self.instructions = []
+        self.stacksize = 0
 
     def __repr__(self):
-        return 'Frame'
+        return 'Frame {}'.format(self.name)
 
+def makeIns(*args, **kwargs):
+    return AbstractInstruction(*args, **kwargs)
 
 class AbstractInstruction:
     """ 
@@ -36,6 +39,24 @@
         s = str(self.src) if self.src else ''
         d = str(self.dst) if self.dst else ''
         l = str(self.jumps) if self.jumps else ''
-        return self.assem + s + d + l
+        #return self.assem + s + d + l
+        return self.render()
+
+    def render(self):
+        """
+            Substitutes source, dst and labels in the string
+        """
+        x = self.assem
+        for i, s in enumerate(self.src):
+            p = '%s{}'.format(i)
+            x = x.replace(p, str(s))
+        for i, d in enumerate(self.dst):
+            p = '%d{}'.format(i)
+            x = x.replace(p, str(d))
+        for i, j in enumerate(self.jumps):
+            p = '%l{}'.format(i)
+            x = x.replace(p, str(j))
+        
+        return x
         
 
--- a/python/registerallocator.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/registerallocator.py	Sat Sep 14 17:29:10 2013 +0200
@@ -12,7 +12,9 @@
 
 class InterferenceGraph(graph.Graph):
     def __init__(self, flowgraph):
-        """ Create a new interference graph from a flowgraph """
+        """ 
+            Create a new interference graph from a flowgraph 
+        """
         super().__init__()
         # Mapping from node to live set
         self.liveMap = {}
@@ -60,12 +62,14 @@
 
 class RegisterAllocator:
     """ Target independent register allocator """
-    def registerAllocate(self, ig, regs):
-        """ Color the given interference graph with the provided registers """
-        regMap = {}
+    def registerAllocate(self, ig, regs, precolored):
+        """ 
+            Color the given interference graph with the provided registers 
+        """
+        regMap = dict(precolored)
         regs = set(regs)
         K = len(regs)
-        allvars = list(ig.nodes)
+        allvars = list(n for n in ig.nodes if n.varname not in regMap)
 
         # Chaitin's algorithm:
         # remove all nodes that have less than K neighbours:
@@ -85,9 +89,9 @@
             possibleregs = set(regs) - set(regMap[n.varname] for n in adj)
             regMap[n.varname] = list(possibleregs)[0]
         # We have a register mapping!
-        #print(self.regMap)
+        # print(regMap)
+        # TODO: implement spilling
+        # TODO: implement coalescing
         return regMap
 
-        # TODO: implement spilling
-        # TODO: implement coalescing
 
--- a/python/serve_arm_as.py	Wed Sep 04 17:35:06 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-
-import subprocess
-import tornado.web
-
-
-def mangle(inp):
-    p_as = subprocess.Popen(['arm-elf-as', '-mthumb'], stdin=subprocess.PIPE)
-    p_as.communicate(input=inp.encode('ascii'))
-
-    p_objdump = subprocess.Popen(['arm-elf-objdump', '-d'], stdout=subprocess.PIPE)
-    output = p_objdump.communicate()[0].decode('ascii')
-    print(output)
-
-    p_objdump = subprocess.Popen(['arm-elf-objdump', '-s'], stdout=subprocess.PIPE)
-    output = p_objdump.communicate()[0].decode('ascii')
-    print(output)
-
-class MainHandler(tornado.web.RequestHandler):
-    def get(self):
-        self.write('Hello')
-
-if __name__ == '__main__':
-    inp = """add r1, r2, r3
-    """
-    inp2 = """blt henkie
-    bgt henkie
-    henkie:
-    """
-    mangle(inp2)
-    
-
--- a/python/target.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/target.py	Sat Sep 14 17:29:10 2013 +0200
@@ -22,6 +22,16 @@
         if type(vop) is ANumber and vop.number < 256:
             return cls(vop.number)
 
+class Imm7:
+    def __init__(self, imm):
+        assert imm < 128
+        self.imm = imm
+
+    @classmethod
+    def Create(cls, vop):
+        if type(vop) is ANumber and vop.number < 128:
+            return cls(vop.number)
+
 class Imm3:
     def __init__(self, imm):
         assert imm < 8
--- a/python/tcodegen.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/tcodegen.py	Sat Sep 14 17:29:10 2013 +0200
@@ -40,10 +40,11 @@
    a = b + a;
    cee = a;
    cee = cee * 2 + cee;
-   if (cee + a > b and b - a+b== 3*6-b)
+   insanemath(2, 3);
+   if (cee + a > b and b - a+b== 3*6-insanemath(b, 2))
    {
       var int x = a;
-      x = b - a + insanemath(3, 4) - insanemath(33,2);
+      x = b - a + insanemath(3, 4) - insanemath(33, insanemath(2, 0));
       a = x * (x + a);
    }
    else
@@ -55,6 +56,50 @@
 }
 """
 
+testsrc = """
+package test3;
+
+function int ab(int a, int b)
+{
+  var int c;
+  c = 0;
+  c = c + a + b;
+  return c; 
+}
+
+function void tesssst()
+{
+   var int a, b;
+   a = 2;
+   b = 3;
+   ab(ab(a, b) + ab(9,b), 0);
+}
+"""
+def dump_cfg(cga, cfg_file):
+    print('digraph G {', file=cfg_file)
+    #print('edge [constraint=none]', file=cfg_file)
+    print('rankdir=TB', file=cfg_file)
+    for f in cga.frames:
+        print('subgraph cluster_{} {{'.format(f.name), file=cfg_file)
+        print('label={};'.format(f.name), file=cfg_file)
+        print('color=lightgrey;', file=cfg_file)
+        print('style=filled;', file=cfg_file)
+        f.cfg.to_dot(cfg_file)
+        print('}', file=cfg_file)
+    print('}', file=cfg_file)
+
+def dump_ig(cga, ig_file):
+    print('digraph G {', file=ig_file)
+    print('edge [arrowhead=none]', file=ig_file)
+    for f in cga.frames:
+        print('subgraph cluster_{} {{'.format(f.name), file=ig_file)
+        print('label={};'.format(f.name), file=ig_file)
+        print('color=lightgrey;', file=ig_file)
+        print('style=filled;', file=ig_file)
+        f.ig.to_dot(ig_file)
+        print('}', file=ig_file)
+    print('}', file=ig_file)
+
 if __name__ == '__main__':
     diag = ppci.DiagnosticsManager()
     builder = c3.Builder(diag)
@@ -70,32 +115,15 @@
     ir2 = cga.generate(irc)
 
     with open('cfg.gv', 'w') as cfg_file:
-        print('digraph G {', file=cfg_file)
-        #print('edge [constraint=none]', file=cfg_file)
-        print('rankdir=TB', file=cfg_file)
-        for f in cga.frames:
-            print('subgraph cluster_{} {{'.format(f.name), file=cfg_file)
-            print('label={};'.format(f.name), file=cfg_file)
-            print('color=lightgrey;', file=cfg_file)
-            print('style=filled;', file=cfg_file)
-            f.cfg.to_dot(cfg_file)
-            print('}', file=cfg_file)
-        print('}', file=cfg_file)
+        dump_cfg(cga, cfg_file)
 
     with open('ig.gv', 'w') as ig_file:
-        print('digraph G {', file=ig_file)
-        print('edge [arrowhead=none]', file=ig_file)
-        for f in cga.frames:
-            print('subgraph cluster_{} {{'.format(f.name), file=ig_file)
-            print('label={};'.format(f.name), file=ig_file)
-            print('color=lightgrey;', file=ig_file)
-            print('style=filled;', file=ig_file)
-            f.ig.to_dot(ig_file)
-            print('}', file=ig_file)
-        print('}', file=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/testasm.py	Wed Sep 04 17:35:06 2013 +0200
+++ b/python/testasm.py	Sat Sep 14 17:29:10 2013 +0200
@@ -265,6 +265,13 @@
         self.feed('lsl r3, r5')
         self.check('ab40')
 
+    def testModSp(self):
+        self.feed('add sp,sp,8')
+        self.feed('add sp,sp,16')
+        self.feed('sub sp,sp,32')
+        self.feed('sub sp,sp,4')
+        self.check('02b004b0 88b081b0')
+
     def testSequence1(self):
         self.feed('mov r5, 3')
         self.feed('add r4, r5, 0')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/serve_arm_as.py	Sat Sep 14 17:29:10 2013 +0200
@@ -0,0 +1,66 @@
+
+"""
+   Tornado webserver interface to arm-elf-as.
+"""
+
+import subprocess
+import tornado.web
+import tornado.ioloop
+import io
+
+def mangle(inp, outstream):
+    print('assembling...', file=outstream)
+    p_as = subprocess.Popen(['arm-elf-as', '-mthumb'], stdin=subprocess.PIPE)
+    p_as.communicate(input=inp.encode('ascii'))
+
+    p_objdump = subprocess.Popen(['arm-elf-objdump', '-d'], stdout=subprocess.PIPE)
+    output = p_objdump.communicate()[0].decode('ascii')
+    print(output, file=outstream)
+
+    p_objdump = subprocess.Popen(['arm-elf-objdump', '-s'], stdout=subprocess.PIPE)
+    output = p_objdump.communicate()[0].decode('ascii')
+    print(output, file=outstream)
+    print('Done!', file=outstream)
+
+page = """
+<html>
+<head>
+</head>
+<body>
+<h1>
+
+</h1>
+<form action="" method="post">
+<textarea name="source" rows="25" cols="80">
+%src%
+</textarea>
+<br>
+<input type="submit" value="Assemble!">
+</form>
+<div>
+%result%
+</div>
+</body>
+</html>
+"""
+
+class MainHandler(tornado.web.RequestHandler):
+    def get(self):
+        src="sub sp,sp,#8"
+        self.write(page.replace('%result%', '').replace('%src%', src))
+    def post(self):
+        #print(self.request.body)
+        src = self.get_argument('source')
+        out = io.StringIO()
+        mangle(src, out)
+        txt = out.getvalue()
+        txt = txt.replace('\n', '<br>')
+        self.write(page.replace('%result%', txt).replace('%src%', src))
+
+
+application = tornado.web.Application([(r"/", MainHandler)])
+
+if __name__ == '__main__':
+    application.listen(8888)
+    tornado.ioloop.IOLoop.instance().start()
+