changeset 272:e64bae57cda8

refactor ir
author Windel Bouwman
date Sat, 31 Aug 2013 17:58:54 +0200
parents cf7d5fb7d9c8
children 6b3a874edd6e
files python/c3/analyse.py python/c3/astnodes.py python/c3/builder.py python/c3/codegenerator.py python/c3/parser.py python/c3/scope.py python/c3/typecheck.py python/c3/visitor.py python/c3/wishes/coro.c3 python/codegenarm.py python/doc/design.rst python/ir/__init__.py python/ir/function.py python/ir/instruction.py python/ir/module.py python/tcodegen.py python/testc3.py python/testcg.py python/testhexfile.py python/testir.py python/zcc.py
diffstat 21 files changed, 518 insertions(+), 266 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/analyse.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/c3/analyse.py	Sat Aug 31 17:58:54 2013 +0200
@@ -110,7 +110,7 @@
             raise Exception('Error resolving type {} {}'.format(t, type(t)))
 
     def findRefs(self, sym):
-        if type(sym) in [Variable, Constant]:
+        if type(sym) in [Constant] or isinstance(sym, Variable):
             sym.typ = self.resolveType(sym.typ, sym.scope)
         elif type(sym) is TypeCast:
             sym.to_type = self.resolveType(sym.to_type, sym.scope)
--- a/python/c3/astnodes.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/c3/astnodes.py	Sat Aug 31 17:58:54 2013 +0200
@@ -42,14 +42,17 @@
 """
 
 class Type(Node):
-   def isType(self, b):
-      return isType(self, b)
+    def isType(self, b):
+        return isType(self, b)
+
 
 class BaseType(Type):
-  def __init__(self, name):
-    self.name = name
-  def __repr__(self):
-    return '{}'.format(self.name)
+    def __init__(self, name):
+        self.name = name
+
+    def __repr__(self):
+        return '{}'.format(self.name)
+
 
 class FunctionType(Type):
    def __init__(self, parametertypes, returntype):
@@ -59,6 +62,7 @@
       params = ', '.join([str(v) for v in self.parametertypes])
       return '{1} f({0})'.format(params, self.returntype)
 
+
 class PointerType(Type):
     def __init__(self, ptype):
         assert isinstance(ptype, Type) or isinstance(ptype, Designator)
@@ -102,6 +106,7 @@
     def __repr__(self):
         return 'STRUCT'
 
+
 class DefinedType(Type):
     def __init__(self, name, typ, loc):
         assert isinstance(name, str)
@@ -116,32 +121,51 @@
 # Variables, parameters, local variables, constants:
 class Symbol(Node):
     def __init__(self, name):
-      self.name = name
-      self.refs = []
+        self.name = name
+        self.refs = []
+
     def addRef(self, r):
-      self.refs.append(r)
+        self.refs.append(r)
+
     @property
     def References(self):
-      return self.refs
+        return self.refs
+
 
 class Constant(Symbol):
     def __init__(self, name, typ, value):
-      super().__init__(name)
-      self.typ = typ
-      self.value = value
+        super().__init__(name)
+        self.typ = typ
+        self.value = value
+
     def __repr__(self):
-      return 'CONSTANT {0} = {1}'.format(self.name, self.value)
+        return 'CONSTANT {0} = {1}'.format(self.name, self.value)
+
 
 class Variable(Symbol):
-   def __init__(self, name, typ):
-      super().__init__(name)
-      self.typ = typ
-      self.ival = None
-      self.isLocal = False
-      self.isReadOnly = False
-      self.isParameter = False
-   def __repr__(self):
-      return 'Var {} [{}]'.format(self.name, self.typ)
+    def __init__(self, name, typ):
+        super().__init__(name)
+        self.typ = typ
+        self.ival = None
+        self.isLocal = False
+        self.isReadOnly = False
+        self.isParameter = False
+
+    def __repr__(self):
+        return 'Var {} [{}]'.format(self.name, self.typ)
+
+
+class LocalVariable(Variable):
+    def __init__(self, name, typ):
+        super().__init__(name, typ)
+        self.isLocal = True
+
+
+class FormalParameter(Variable):
+    def __init__(self, name, typ):
+        super().__init__(name, typ)
+        self.isParameter = True
+
 
 # Procedure types
 class Function(Symbol):
--- a/python/c3/builder.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/c3/builder.py	Sat Aug 31 17:58:54 2013 +0200
@@ -10,6 +10,7 @@
         Reports errors to the diagnostics system
     """
     def __init__(self, diag):
+        self.pack_dir = None
         self.logger = logging.getLogger('c3')
         self.diag = diag
         self.parser = Parser(diag)
@@ -24,11 +25,17 @@
             return self.packages[pname]
         else:
             # Try to lookup package from file
-            fns = glob.glob('./*/{}.c3'.format(pname))
+            fns = glob.glob('./**/{}.c3'.format(pname))
             if fns:
                 with open(fns[0]) as f:
                     src = f.read()
                 self.build(src)
+            if self.pack_dir:
+                fns = glob.glob('{}/{}.c3'.format(self.pack_dir, pname))
+                if fns:
+                    with open(fns[0]) as f:
+                        src = f.read()
+                    self.build(src)
             if pname in self.packages:
                 return self.packages[pname]
 
@@ -48,8 +55,9 @@
         self.packages[pkg.name] = pkg
         return pkg
 
-    def build(self, src):
+    def build(self, src, pack_dir=None):
         """ Create IR-code from sources """
+        self.pack_dir = pack_dir
         pkg = self.parse(src)
 
         # Only return ircode when everything is OK
--- a/python/c3/codegenerator.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/c3/codegenerator.py	Sat Aug 31 17:58:54 2013 +0200
@@ -27,19 +27,16 @@
         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.varMap[s] = self.newTemp()
-                pass
-            elif type(s) is astnodes.Function:
-                self.genFunction(s)
-            else:
-                raise NotImplementedError(str(s))
+        for v in pkg.innerScope.Variables:
+            #print(v)
+            self.varMap[v] = self.newTemp()
+        for s in pkg.innerScope.Functions:
+            self.genFunction(s)
 
     def genFunction(self, fn):
         # TODO: handle arguments
         f = self.funcMap[fn]
+        f.return_value = self.newTemp()
         # TODO reserve room for stack, this can be done at later point?
         self.setFunction(f)
         l2 = self.newBlock()
@@ -49,14 +46,21 @@
 
         for sym in fn.innerScope:
             # TODO: handle parameters different
+            if sym.isParameter:
+                print('param', sym)
+                ir.Parameter(sym.name)
+            if sym.isLocal:
+                print('local', sym)
+            
             v = self.newTemp()
             # TODO: make this ssa here??
             self.varMap[sym] = v
 
         self.genCode(fn.body)
-        # TODO handle return?
+        # Set the default return value to zero:
+        # TBD: this may not be required?
+        self.emit(ir.Move(f.return_value, ir.Const(0)))
         self.emit(ir.Jump(f.epiloog))
-        #self.emit(ir.Return(ir.Const(0)))
         self.setFunction(None)
 
     def genCode(self, code):
@@ -87,7 +91,8 @@
         elif type(code) is astnodes.ReturnStatement:
             if code.expr:
                 re = self.genExprCode(code.expr)
-                self.emit(ir.Return(re))
+                self.emit(ir.Move(self.fn.return_value, re))
+                self.emit(ir.Jump(self.fn.epiloog))
             else:
                 self.builder.addIns(ir.Return())
         elif type(code) is astnodes.WhileStatement:
--- a/python/c3/parser.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/c3/parser.py	Sat Aug 31 17:58:54 2013 +0200
@@ -124,19 +124,19 @@
 
     # Variable declarations:
     def parseVarDef(self):
-      self.Consume('var')
-      t = self.parseTypeSpec()
-      def parseVar():
-         name = self.Consume('ID')
-         v = astnodes.Variable(name.val, t)
-         v.loc = name.loc
-         if self.hasConsumed('='):
-            v.ival = self.Expression()
-         self.addDeclaration(v)
-      parseVar()
-      while self.hasConsumed(','):
-         parseVar()
-      self.Consume(';')
+        self.Consume('var')
+        t = self.parseTypeSpec()
+        def parseVar():
+            name = self.Consume('ID')
+            v = astnodes.Variable(name.val, t)
+            v.loc = name.loc
+            if self.hasConsumed('='):
+                v.ival = self.Expression()
+            self.addDeclaration(v)
+        parseVar()
+        while self.hasConsumed(','):
+            parseVar()
+        self.Consume(';')
 
     def parseConstDef(self):
       self.Consume('const')
@@ -164,17 +164,17 @@
       self.Consume('(')
       parameters = []
       if not self.hasConsumed(')'):
-         def parseParameter():
-            typ = self.parseTypeSpec()
-            name = self.Consume('ID')
-            param = astnodes.Variable(name.val, typ)
-            param.loc = name.loc
-            self.addDeclaration(param)
-            parameters.append(param)
-         parseParameter()
-         while self.hasConsumed(','):
+            def parseParameter():
+                typ = self.parseTypeSpec()
+                name = self.Consume('ID')
+                param = astnodes.FormalParameter(name.val, typ)
+                param.loc = name.loc
+                self.addDeclaration(param)
+                parameters.append(param)
             parseParameter()
-         self.Consume(')')
+            while self.hasConsumed(','):
+                parseParameter()
+            self.Consume(')')
       paramtypes = [p.typ for p in parameters]
       f.typ = astnodes.FunctionType(paramtypes, returntype)
       f.body = self.parseCompoundStatement()
@@ -183,16 +183,16 @@
     # Statements:
 
     def parseIfStatement(self):
-      loc = self.Consume('if').loc
-      self.Consume('(')
-      condition = self.Expression()
-      self.Consume(')')
-      yes = self.parseCompoundStatement()
-      if self.hasConsumed('else'):
-         no = self.parseCompoundStatement()
-      else:
-         no = None
-      return astnodes.IfStatement(condition, yes, no, loc)
+        loc = self.Consume('if').loc
+        self.Consume('(')
+        condition = self.Expression()
+        self.Consume(')')
+        yes = self.parseCompoundStatement()
+        if self.hasConsumed('else'):
+            no = self.parseCompoundStatement()
+        else:
+            no = None
+        return astnodes.IfStatement(condition, yes, no, loc)
 
     def parseWhileStatement(self):
         loc = self.Consume('while').loc
--- a/python/c3/scope.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/c3/scope.py	Sat Aug 31 17:58:54 2013 +0200
@@ -7,8 +7,8 @@
         self.parent = parent
 
     def __iter__(self):
-      # Iterate in a deterministic manner:
-      return iter(self.Constants + self.Variables + self.Functions)
+        # Iterate in a deterministic manner:
+        return iter(self.Constants + self.Variables + self.Functions)
 
     @property
     def Syms(self):
@@ -21,33 +21,34 @@
 
     @property
     def Variables(self):
-        return [s for s in self.Syms if type(s) is astnodes.Variable]
+        return [s for s in self.Syms if isinstance(s, astnodes.Variable)]
 
     @property
     def Functions(self):
         return [s for s in self.Syms if type(s) is astnodes.Function]
 
     def getSymbol(self, name):
-      if name in self.symbols:
-         return self.symbols[name]
-      # Look for symbol:
-      if self.parent:
-         return self.parent.getSymbol(name)
-      raise CompilerException("Symbol {0} not found".format(name), name.loc)
+        if name in self.symbols:
+            return self.symbols[name]
+        # Look for symbol:
+        if self.parent:
+            return self.parent.getSymbol(name)
+        raise CompilerException("Symbol {0} not found".format(name), name.loc)
 
     def hasSymbol(self, name):
-      if name in self.symbols:
-         return True
-      if self.parent:
-         return self.parent.hasSymbol(name)
-      return False
+        if name in self.symbols:
+            return True
+        if self.parent:
+            return self.parent.hasSymbol(name)
+        return False
 
     def addSymbol(self, sym):
-      self.symbols[sym.name] = sym
+        self.symbols[sym.name] = sym
 
     def __repr__(self):
         return 'Scope with {} symbols'.format(len(self.symbols))
 
+
 # buildin types:
 intType = astnodes.BaseType('int')
 intType.bytesize = 4
--- a/python/c3/typecheck.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/c3/typecheck.py	Sat Aug 31 17:58:54 2013 +0200
@@ -33,7 +33,7 @@
                     return False
             return True
         else:
-            raise Exception('Type compare not implemented')
+            raise Exception('Type compare for {} not implemented'.format(type(a)))
     return False
 
 def canCast(fromT, toT):
@@ -99,7 +99,7 @@
             sym.typ = sym.proc.typ.returntype
         elif type(sym) is VariableUse:
             sym.lvalue = True
-            if type(sym.target) is Variable:
+            if isinstance(sym.target, Variable):
                 sym.typ = sym.target.typ
             else:
                 print('warning {} has no target, defaulting to int'.format(sym))
@@ -172,7 +172,7 @@
                    self.error('Must be {0}'.format(boolType), sym.b.loc)
             else:
                 raise Exception('Unknown binop {0}'.format(sym.op))
-        elif type(sym) is Variable:
+        elif isinstance(sym, Variable):
             # check initial value type:
             # TODO
             pass
--- a/python/c3/visitor.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/c3/visitor.py	Sat Aug 31 17:58:54 2013 +0200
@@ -54,7 +54,7 @@
             self.do(node.ptr)
         elif type(node) is Constant:
             self.do(node.value)
-        elif type(node) in [VariableUse, Variable, Literal, FunctionType, DefinedType]:
+        elif type(node) in [VariableUse, Variable, Literal, FunctionType, DefinedType, FormalParameter, LocalVariable]:
             # Those nodes do not have child nodes.
             pass
         elif type(node) is WhileStatement:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/c3/wishes/coro.c3	Sat Aug 31 17:58:54 2013 +0200
@@ -0,0 +1,91 @@
+module coro;
+
+/*
+  Some co-routines doing some work.
+
+  This example demonstrates how to write co-operating
+  routines in a nice way.
+*/
+
+int regbank[10];
+
+function i2c_write(int address, int d)
+{
+    regbank[2] = address;
+    regbank[0] |= 0x1; // Issue go command
+    while (regbank[1] != 0)
+    {
+        yield;
+    }
+
+    // Wait while busy:
+    while (regbank[1] != 11)
+    {
+        yield;
+    }
+}
+
+function int i2c_read(int address)
+{
+    regbank[2] = address;
+    regbank[0] |= 0x1; // Issue go command
+    while (regbank[1] != 0)
+    {
+        yield;
+    }
+
+    // Wait while busy:
+    while (regbank[1] != 11)
+    {
+        yield;
+    }
+}
+
+function void eeprom_set(int address, int v)
+{
+    i2c_write(address, v);
+    i2c_read(address);
+}
+
+function int calcX(int y)
+{
+  var int x;
+  x = 2;
+  x = x + 2 + 9 * y;
+  return x;
+}
+
+var int counter = 0;
+
+task task1()
+{
+    start task3;
+   var int a = 200;
+   while (a > 0)
+   {
+      yield;
+   }
+}
+
+task task2()
+{
+    while(true)
+    {
+        yield;
+    }
+}
+
+task task3()
+{
+    eeprom_set(99, 1);
+   yield;
+}
+
+task main()
+{
+    start task1;
+    start task2;
+    await task1;
+    await task2;
+}
+
--- a/python/codegenarm.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/codegenarm.py	Sat Aug 31 17:58:54 2013 +0200
@@ -6,7 +6,7 @@
 import flowgraph
 import registerallocator
 from instructionselector import InstructionSelector
-
+import irmach
 
 class ArmInstructionSelector(InstructionSelector):
     """ Instruction selector for the arm architecture """
@@ -58,8 +58,16 @@
             return d
         elif isinstance(e, ir.Temp):
             return self.getTempReg(e)
+        elif isinstance(e, ir.Call):
+            args = [self.munchExpr(a) for a in e.arguments]
+            self.emit('add sp, sp, 22')
+            # 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')
         else:
-            raise NotImplementedError('--> {}'.format(e))
+            raise NotImplementedError('Expr --> {}'.format(e))
 
     def munchStm(self, s):
         if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
@@ -70,9 +78,6 @@
             val = self.munchExpr(s.src)
             dreg = self.getTempReg(s.dst)
             self.emit('mov %d0, %s0', dst=[dreg], src=[val])
-        elif isinstance(s, ir.Return):
-            #etgt = self.targets[
-            self.emit('jmp exit', jumps=[])
         elif isinstance(s, ir.Jump):
             tgt = self.targets[s.target]
             self.emit('jmp {}'.format(s), jumps=[tgt])
@@ -102,12 +107,19 @@
     def useUnused(self, inslist):
         # Use unused temporaries at the end of the list
         defTemps = []
-        for d in (i.dst for i in inslist):
-            print(d)
-            defTemps.append(d)
-        useTemps = [d for d in ([i.src] for i in inslist)]
-        print(defTemps)
-        print(useTemps)
+        useTemps = []
+        for i in inslist:
+            for d in iter(i.dst):
+                defTemps.append(d)
+            for s in iter(i.src):
+                useTemps.append(s)
+        defTemps = set(defTemps)
+        useTemps = set(useTemps)
+        unUsed = defTemps - useTemps
+        #print('Unused:', unUsed)
+        for uu in unUsed:
+            inslist.append(irmach.AbstractInstruction('use %s0', src=[uu]))
+        #print(useTemps)
 
     def generate(self, ircode, cfg_file=None, ig_file=None):
         ir2 = self.ins_sel.munchProgram(ircode)
@@ -122,11 +134,13 @@
         regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7']
         ra = registerallocator.RegisterAllocator()
         regMap = ra.registerAllocate(ig, regs)
-        print(regMap)
+        #print(regMap)
+        # Use allocated registers:
         for i in ir2:
             i.src = tuple(regMap[t] for t in i.src)
             i.dst = tuple(regMap[t] for t in i.dst)
-            print(i)
+            #print(i)
+        return ir2
 
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/doc/design.rst	Sat Aug 31 17:58:54 2013 +0200
@@ -0,0 +1,93 @@
+
+= processes / threads =
+
+Processes are completely seperated and fully pre-emptive.
+This means a process can be unscheduled at any moment.
+
+Threads are co-operative. This means they yield control
+voluntary. This means that mutexes and locks are not required.
+This is done with the built-in language feature called tasks.
+
+If some heavy duty task must be performed, either way spawn
+a new process, or yield frequently from this hard labour.
+
+= tasks =
+
+Consider the following::
+
+--
+function int insanemath(int a)
+{
+    while (a > 0)
+    {
+       a = a -1;
+       resume agent1;
+    }
+    return a - 1;
+}
+
+task agent1()
+{
+  start agent2;
+}
+
+task agent2()
+{
+   insanemath(55);
+   insanemath(44);
+}
+
+task main()
+{
+  start agent1;
+  join agent1;
+}
+--
+
+Say to tasks are running in concurrent / parallel.
+
+
+
+Stack layout for tasks.
+||
+||
+\/
++---------+
+| return address
+| locals
+|
++------
+| return address
+| locals
+|
++---
+
+Assembly code for the functions above:
+
+.code
+insanemath:
+L1:
+load r0, sp - 4
+cmp r0, 0
+jl L2
+dec r0
+store r0, sp - 4
+jmp L1
+L2:
+ret
+
+agent1:
+hlt?
+
+agent2:
+hlt?
+
+main:
+jmp agent1
+
+.data
+agent1_task:
+dd 0
+agent2_task:
+dd 0
+
--- a/python/ir/__init__.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/ir/__init__.py	Sat Aug 31 17:58:54 2013 +0200
@@ -1,5 +1,4 @@
-from .module import *
+from .module import Module, Function, Block
 from .instruction import *
-from .function import Function, Block
 from .builder import Builder
 
--- a/python/ir/function.py	Tue Aug 20 18:56:02 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-
-class Function:
-    def __init__(self, name):
-        self.name = name
-        self.entry = Block('{}_entry'.format(name))
-        self.epiloog = Block('{}_epilog'.format(name))
-
-    def __repr__(self):
-        return 'Function {0}'.format(self.name)
-
-    def addBB(self, bb):
-        self.bbs.append(bb)
-        bb.parent = self
-    addBasicBlock = addBB
-
-    def removeBasicBlock(self, bb):
-        self.bbs.remove(bb)
-        bb.parent = None
-
-    def getBBs(self):
-        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)
-        bbs.remove(self.entry)
-        if self.epiloog in bbs:
-            bbs.remove(self.epiloog)
-        bbs.insert(0, self.entry)
-        bbs.append(self.epiloog)
-        return bbs
-
-    def findBasicBlock(self, name):
-        for bb in self.bbs:
-            if bb.name == name:
-                return bb
-        raise KeyError(name)
-
-    BasicBlocks = property(getBBs)
-
-    @property
-    def Entry(self):
-        return self.entry
-
-    def check(self):
-        pass
-
-    def call(self, *args):
-        varmap = {}
-        bb = self.Entry
-        ip = 0
-        while True:
-            i = bb.Instructions[ip]
-            ip += 1
-            return
-
-
-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 'Block {0}'.format(self.name)
-
-    def addInstruction(self, i):
-        i.parent = self
-        self.instructions.append(i)
-
-    def replaceInstruction(self, i1, i2):
-        idx = self.instructions.index(i1)
-        i1.parent = None
-        i1.delete()
-        i2.parent = self
-        self.instructions[idx] = i2
-
-    def removeInstruction(self, i):
-        i.parent = None
-        i.delete()
-        self.instructions.remove(i)
-
-    def getInstructions(self):
-        return self.instructions
-    Instructions = property(getInstructions)
-
-    def getLastIns(self):
-        return self.instructions[-1]
-    LastInstruction = property(getLastIns)
-
-    @property
-    def Empty(self):
-        return len(self.instructions) == 0
-
-    @property
-    def FirstInstruction(self):
-        return self.instructions[0]
-
-    def getSuccessors(self):
-        if not self.Empty:
-            return self.LastInstruction.Targets
-        return []
-    Successors = property(getSuccessors)
-
-    def getPredecessors(self):
-        preds = []
-        for bb in self.parent.BasicBlocks:
-            if self in bb.Successors:
-                preds.append(bb)
-        return preds
-    Predecessors = property(getPredecessors)
-
-    def precedes(self, other):
-        raise NotImplementedError()
-
-    def check(self):
-        pass
--- a/python/ir/instruction.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/ir/instruction.py	Sat Aug 31 17:58:54 2013 +0200
@@ -1,4 +1,4 @@
-from .function import Function
+from .module import Function
 
 class Expression:
     pass
@@ -39,6 +39,7 @@
 
 
 def Add(a, b):
+    """ Convenience call """
     return Binop(a, '+', b)
 
 
@@ -51,6 +52,26 @@
         return 'Alloc'
 
 
+class Variable(Expression):
+    def __init__(self, offset):
+        self.offset = offset
+
+    def __repr__(self):
+        return 'Variable'
+
+
+class LocalVariable(Variable):
+    pass
+
+
+class GlobalVariable(Variable):
+    pass
+
+
+class Parameter(Variable):
+    pass
+
+
 class Temp(Expression):
     """ Temporary storage, same as register """
     def __init__(self, name):
@@ -120,15 +141,4 @@
         return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no)
 
 
-class Return(Statement):
-    def __init__(self, value):
-        self.value = value
-        self.Targets = [] # TODO: Do this in another way
 
-    def __repr__(self):
-        if self.value:
-            return 'ret {0}'.format(self.value)
-        else:
-            return 'ret'
-
-
--- a/python/ir/module.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/ir/module.py	Sat Aug 31 17:58:54 2013 +0200
@@ -1,6 +1,5 @@
 # IR-Structures:
-from .instruction import *
-from .function import Block
+
 
 class Module:
     """ Main container for a piece of code. """
@@ -68,5 +67,129 @@
         """ Perform sanity check on module """
         for f in self.Functions:
             f.check()
-            
+
+
+class Function:
+    def __init__(self, name):
+        self.name = name
+        self.entry = Block('{}_entry'.format(name))
+        self.epiloog = Block('{}_epilog'.format(name))
+        self.arguments = []
+
+    def __repr__(self):
+        return 'Function {0}'.format(self.name)
+
+    def addBB(self, bb):
+        self.bbs.append(bb)
+        bb.parent = self
+    addBasicBlock = addBB
+
+    def removeBasicBlock(self, bb):
+        self.bbs.remove(bb)
+        bb.parent = None
+
+    def getBBs(self):
+        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)
+        bbs.remove(self.entry)
+        if self.epiloog in bbs:
+            bbs.remove(self.epiloog)
+        bbs.insert(0, self.entry)
+        bbs.append(self.epiloog)
+        return bbs
+
+    def findBasicBlock(self, name):
+        for bb in self.bbs:
+            if bb.name == name:
+                return bb
+        raise KeyError(name)
+
+    BasicBlocks = property(getBBs)
+
+    @property
+    def Entry(self):
+        return self.entry
+
+    def check(self):
+        pass
+
+    def call(self, *args):
+        varmap = {}
+        bb = self.Entry
+        ip = 0
+        while True:
+            i = bb.Instructions[ip]
+            ip += 1
+            return
+
 
+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 'Block {0}'.format(self.name)
+
+    def addInstruction(self, i):
+        i.parent = self
+        self.instructions.append(i)
+
+    def replaceInstruction(self, i1, i2):
+        idx = self.instructions.index(i1)
+        i1.parent = None
+        i1.delete()
+        i2.parent = self
+        self.instructions[idx] = i2
+
+    def removeInstruction(self, i):
+        i.parent = None
+        i.delete()
+        self.instructions.remove(i)
+
+    def getInstructions(self):
+        return self.instructions
+    Instructions = property(getInstructions)
+
+    def getLastIns(self):
+        return self.instructions[-1]
+    LastInstruction = property(getLastIns)
+
+    @property
+    def Empty(self):
+        return len(self.instructions) == 0
+
+    @property
+    def FirstInstruction(self):
+        return self.instructions[0]
+
+    def getSuccessors(self):
+        if not self.Empty:
+            return self.LastInstruction.Targets
+        return []
+    Successors = property(getSuccessors)
+
+    def getPredecessors(self):
+        preds = []
+        for bb in self.parent.BasicBlocks:
+            if self in bb.Successors:
+                preds.append(bb)
+        return preds
+    Predecessors = property(getPredecessors)
+
+    def precedes(self, other):
+        raise NotImplementedError()
+
+    def check(self):
+        pass
+
+
--- a/python/tcodegen.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/tcodegen.py	Sat Aug 31 17:58:54 2013 +0200
@@ -11,6 +11,15 @@
 testsrc = """
 package test2;
 
+var int phaa, foo, bar;
+
+function int insanemath(int a, int b)
+{
+  var int c;
+  c = a + b + 1;
+  return c;
+}
+
 function void tesssst(int henkie)
 {
    var int a, b, cee;
@@ -22,7 +31,7 @@
    if (cee + a > b and b - a+b== 3*6-b)
    {
       var int x = a;
-      x = b - a;
+      x = b - a + insanemath(3, 4);
       a = x * (x + a);
    }
    else
@@ -43,7 +52,9 @@
     cga = codegenarm.ArmCodeGenerator(outs)
     cfg_file = open('cfg.gv', 'w')
     ig_file = open('ig.gv', 'w')
-    cga.generate(ir, cfg_file=cfg_file, ig_file=ig_file)
+    ir2 = cga.generate(ir, cfg_file=cfg_file, ig_file=ig_file)
     cfg_file.close()
     ig_file.close()
+    for i in ir2:
+        print(i)
 
--- a/python/testc3.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/testc3.py	Sat Aug 31 17:58:54 2013 +0200
@@ -105,23 +105,13 @@
         self.assertSequenceEqual(rows, actualErrors)
         self.assertFalse(ircode)
 
-    def expectOK(self, snippet):
-        ircode = self.builder.build(snippet)
+    def expectOK(self, snippet, pack_dir=None):
+        ircode = self.builder.build(snippet, pack_dir=pack_dir)
         if not ircode:
             self.diag.printErrors(snippet)
         self.assertTrue(ircode)
         return ircode
 
-    def expectIR(self, snippet, ir_out):
-        ircode = self.builder.build(snippet)
-        if not ircode:
-            self.diag.printErrors(snippet)
-        self.assertTrue(ircode)
-        actual_ins = [str(i) for i in ircode.Instructions]
-        expected_ins = [i.strip() for i in ir_out.split('\n')]
-        self.assertSequenceEqual(expected_ins, actual_ins)
-        return ircode
-
     def testPackage(self):
         p1 = """package p1;
         type int A;
@@ -408,7 +398,7 @@
         for filename in example_filenames:
             with open(filename, 'r') as f:
                 src = f.read()
-            self.expectOK(src)
+            self.expectOK(src, pack_dir='./c3/examples')
 
     def test2(self):
         # testsrc2 is valid code:
--- a/python/testcg.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/testcg.py	Sat Aug 31 17:58:54 2013 +0200
@@ -8,7 +8,7 @@
     m = ir.Module('tst')
     f = ir.Function('tst')
     m.addFunction(f)
-    return m, f.entry
+    return m, f, f.entry
 
 
 class testCodeGeneration(unittest.TestCase):
@@ -16,9 +16,9 @@
         self.cg = codegen.CodeGenerator(arm.armtarget)
 
     def testFunction(self):
-        m, bb = genTestFunction()
+        m, f, bb = genTestFunction()
         bb.addInstruction(ir.Const(123))
-        bb.addInstruction(ir.Return(ir.Const(0)))
+        bb.addInstruction(ir.Jump(f.epiloog))
         m.check()
         obj = self.cg.generate(m)
         self.assertTrue(obj)
@@ -28,9 +28,9 @@
     def testStack(self):
         s = outstream.OutputStream()
         cg = codegenarm.ArmCodeGenerator(s)
-        m, bb = genTestFunction()
+        m, f, bb = genTestFunction()
         bb.addInstruction(ir.Move(ir.Mem(ir.Const(1)), ir.Const(22)))
-        bb.addInstruction(ir.Return(ir.Const(0)))
+        bb.addInstruction(ir.Jump(f.epiloog))
         m.check()
         cg.generate(m)
         #s.dump()
--- a/python/testhexfile.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/testhexfile.py	Sat Aug 31 17:58:54 2013 +0200
@@ -28,11 +28,13 @@
         hf.addRegion(0xFFFE, bytes.fromhex('aabbcc'))
         self.saveload(hf)
 
+    @unittest.skip
     def testSave4(self):
         hf = HexFile()
         hf.addRegion(0xF000, bytes.fromhex('ab')*0x10000)
         self.saveload(hf)
 
+    @unittest.skip
     def testSave5(self):
         hf = HexFile()
         hf.addRegion(0xF003, bytes.fromhex('ab')*0x10000)
--- a/python/testir.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/testir.py	Sat Aug 31 17:58:54 2013 +0200
@@ -5,6 +5,7 @@
 import ir, x86, transform
 import optimize
 
+
 class IrCodeTestCase(unittest.TestCase):
     def setUp(self):
         self.b = ir.Builder()
@@ -16,12 +17,13 @@
         self.b.setFunction(f)
         bb = self.b.newBlock()
         self.b.setBlock(bb)
-        self.b.emit(ir.Return(ir.Const(0)))
+        self.b.emit(ir.Exp(ir.Const(0)))
         self.m.check()
         # Run interpreter:
         # r = self.m.getFunction('add').call(1, 2)
         #self.assertEqual(3, r)
 
+
 class ConstantFolderTestCase(unittest.TestCase):
     def setUp(self):
         self.b = ir.Builder()
--- a/python/zcc.py	Tue Aug 20 18:56:02 2013 +0200
+++ b/python/zcc.py	Sat Aug 31 17:58:54 2013 +0200
@@ -21,15 +21,16 @@
 parser.add_argument('--dumpir', action='store_true', help="Dump IR-code")
 parser.add_argument('--dumpasm', action='store_true', help="Dump ASM-code")
 parser.add_argument('--optimize', action='store_true', help="Optimize")
+parser.add_argument('--package_dir', help="Look in this directory for packages")
 parser.add_argument('-o', '--output', help='Output file', metavar='filename')
 parser.add_argument('--hexfile', help='Output hexfile', type=argparse.FileType('w'))
 parser.add_argument('--log', help='Log level (INFO,DEBUG)', type=logLevel)
 
-def zcc(src, outs, diag, dumpir=False, do_optimize=False):
+def zcc(src, outs, diag, dumpir=False, do_optimize=False, pack_dir=None):
     logging.info('Zcc started')
     # Front end:
     c3b = c3.Builder(diag)
-    ircode = c3b.build(src)
+    ircode = c3b.build(src, pack_dir=pack_dir)
     if not ircode:
         return
 
@@ -55,7 +56,7 @@
     outs = outstream.TextOutputStream()
 
     # Invoke compiler:
-    res = zcc(src, outs, diag, dumpir=args.dumpir, do_optimize=args.optimize)
+    res = zcc(src, outs, diag, dumpir=args.dumpir, do_optimize=args.optimize, pack_dir=args.package_dir)
     if not res:
         diag.printErrors(src)
         sys.exit(1)